aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBond_009 <bond.009@outlook.com>2019-07-29 23:47:25 +0200
committerBond_009 <bond.009@outlook.com>2019-08-11 15:54:58 +0200
commit5eaf5465a55df0359f85077b7922ca4a45681831 (patch)
tree73b87fef4f2b7e857bdd4177d7fdce3fe79aaaeb
parent1ad67e223f581efd417efa2bb1cb626c50a6f5a9 (diff)
Check checksum for plugin downloads
* Compare the MD5 checksum when downloading plugins * Reduced log spam due to http requests * Removed 'GetTempFileResponse' function from HttpClientManager * Fixed caching for HttpClientManager
-rw-r--r--Emby.Dlna/PlayTo/SsdpHttpClient.cs10
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs14
-rw-r--r--Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs206
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs5
-rw-r--r--Emby.Server.Implementations/Updates/InstallationManager.cs140
-rw-r--r--MediaBrowser.Api/PackageService.cs2
-rw-r--r--MediaBrowser.Common/Extensions/HexHelper.cs22
-rw-r--r--MediaBrowser.Common/Net/HttpRequestOptions.cs12
-rw-r--r--MediaBrowser.Common/Net/IHttpClient.cs16
-rw-r--r--MediaBrowser.Common/Updates/IInstallationManager.cs7
-rw-r--r--MediaBrowser.Model/Cryptography/PasswordHash.cs1
-rw-r--r--MediaBrowser.Model/Updates/InstallationInfo.cs6
-rw-r--r--MediaBrowser.Providers/Studios/StudiosImageProvider.cs28
-rw-r--r--Mono.Nat/Upnp/Messages/GetServicesMessage.cs39
-rw-r--r--Mono.Nat/Upnp/Messages/UpnpMessage.cs46
-rw-r--r--Mono.Nat/Upnp/UpnpNatDevice.cs4
-rw-r--r--jellyfin.ruleset2
17 files changed, 141 insertions, 419 deletions
diff --git a/Emby.Dlna/PlayTo/SsdpHttpClient.cs b/Emby.Dlna/PlayTo/SsdpHttpClient.cs
index 22aaa6885..217ea3a4b 100644
--- a/Emby.Dlna/PlayTo/SsdpHttpClient.cs
+++ b/Emby.Dlna/PlayTo/SsdpHttpClient.cs
@@ -73,9 +73,6 @@ namespace Emby.Dlna.PlayTo
UserAgent = USERAGENT,
LogErrorResponseBody = true,
BufferContent = false,
-
- // The periodic requests may keep some devices awake
- LogRequestAsDebug = true
};
options.RequestHeaders["HOST"] = ip + ":" + port.ToString(_usCulture);
@@ -98,9 +95,6 @@ namespace Emby.Dlna.PlayTo
LogErrorResponseBody = true,
BufferContent = false,
- // The periodic requests may keep some devices awake
- LogRequestAsDebug = true,
-
CancellationToken = cancellationToken
};
@@ -135,13 +129,9 @@ namespace Emby.Dlna.PlayTo
{
Url = url,
UserAgent = USERAGENT,
- LogRequest = logRequest || _config.GetDlnaConfiguration().EnableDebugLog,
LogErrorResponseBody = true,
BufferContent = false,
- // The periodic requests may keep some devices awake
- LogRequestAsDebug = true,
-
CancellationToken = cancellationToken
};
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 09847b2f8..6074e5218 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -1528,8 +1528,6 @@ namespace Emby.Server.Implementations
{
Url = Url,
LogErrorResponseBody = false,
- LogErrors = false,
- LogRequest = false,
BufferContent = false,
CancellationToken = cancellationToken
}).ConfigureAwait(false))
@@ -1681,8 +1679,8 @@ namespace Emby.Server.Implementations
private async Task<bool> IsIpAddressValidAsync(IPAddress address, CancellationToken cancellationToken)
{
- if (address.Equals(IPAddress.Loopback) ||
- address.Equals(IPAddress.IPv6Loopback))
+ if (address.Equals(IPAddress.Loopback)
+ || address.Equals(IPAddress.IPv6Loopback))
{
return true;
}
@@ -1695,12 +1693,6 @@ namespace Emby.Server.Implementations
return cachedResult;
}
-#if DEBUG
- const bool LogPing = true;
-#else
- const bool LogPing = false;
-#endif
-
try
{
using (var response = await HttpClient.SendAsync(
@@ -1708,8 +1700,6 @@ namespace Emby.Server.Implementations
{
Url = apiUrl,
LogErrorResponseBody = false,
- LogErrors = LogPing,
- LogRequest = LogPing,
BufferContent = false,
CancellationToken = cancellationToken
}, HttpMethod.Post).ConfigureAwait(false))
diff --git a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
index a933b53f5..0dd4d4ca5 100644
--- a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
+++ b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
@@ -5,9 +5,6 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
-using System.Net.Http.Headers;
-using System.Text;
-using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
@@ -20,7 +17,7 @@ using Microsoft.Net.Http.Headers;
namespace Emby.Server.Implementations.HttpClientManager
{
/// <summary>
- /// Class HttpClientManager
+ /// Class HttpClientManager.
/// </summary>
public class HttpClientManager : IHttpClient
{
@@ -45,19 +42,9 @@ namespace Emby.Server.Implementations.HttpClientManager
IFileSystem fileSystem,
Func<string> defaultUserAgentFn)
{
- if (appPaths == null)
- {
- throw new ArgumentNullException(nameof(appPaths));
- }
-
- if (logger == null)
- {
- throw new ArgumentNullException(nameof(logger));
- }
-
- _logger = logger;
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
_fileSystem = fileSystem;
- _appPaths = appPaths;
+ _appPaths = appPaths ?? throw new ArgumentNullException(nameof(appPaths));
_defaultUserAgentFn = defaultUserAgentFn;
}
@@ -118,7 +105,7 @@ namespace Emby.Server.Implementations.HttpClientManager
request.Headers.Add(HeaderNames.Connection, "Keep-Alive");
}
- //request.Headers.Add(HeaderNames.CacheControl, "no-cache");
+ // request.Headers.Add(HeaderNames.CacheControl, "no-cache");
/*
if (!string.IsNullOrWhiteSpace(userInfo))
@@ -196,7 +183,7 @@ namespace Emby.Server.Implementations.HttpClientManager
}
var url = options.Url;
- var urlHash = url.ToLowerInvariant().GetMD5().ToString("N", CultureInfo.InvariantCulture);
+ var urlHash = url.ToUpperInvariant().GetMD5().ToString("N", CultureInfo.InvariantCulture);
var responseCachePath = Path.Combine(_appPaths.CachePath, "httpclient", urlHash);
@@ -239,7 +226,13 @@ namespace Emby.Server.Implementations.HttpClientManager
{
Directory.CreateDirectory(Path.GetDirectoryName(responseCachePath));
- using (var fileStream = _fileSystem.GetFileStream(responseCachePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.None, true))
+ using (var fileStream = new FileStream(
+ responseCachePath,
+ FileMode.Create,
+ FileAccess.Write,
+ FileShare.None,
+ StreamDefaults.DefaultFileStreamBufferSize,
+ true))
{
await response.Content.CopyToAsync(fileStream).ConfigureAwait(false);
@@ -278,16 +271,11 @@ namespace Emby.Server.Implementations.HttpClientManager
}
}
- if (options.LogRequest)
- {
- _logger.LogDebug("HttpClientManager {0}: {1}", httpMethod.ToString(), options.Url);
- }
-
options.CancellationToken.ThrowIfCancellationRequested();
var response = await client.SendAsync(
httpWebRequest,
- options.BufferContent ? HttpCompletionOption.ResponseContentRead : HttpCompletionOption.ResponseHeadersRead,
+ options.BufferContent || options.CacheMode == CacheMode.Unconditional ? HttpCompletionOption.ResponseContentRead : HttpCompletionOption.ResponseHeadersRead,
options.CancellationToken).ConfigureAwait(false);
await EnsureSuccessStatusCode(response, options).ConfigureAwait(false);
@@ -308,138 +296,6 @@ namespace Emby.Server.Implementations.HttpClientManager
public Task<HttpResponseInfo> Post(HttpRequestOptions options)
=> SendAsync(options, HttpMethod.Post);
- /// <summary>
- /// Downloads the contents of a given url into a temporary location
- /// </summary>
- /// <param name="options">The options.</param>
- /// <returns>Task{System.String}.</returns>
- public async Task<string> GetTempFile(HttpRequestOptions options)
- {
- var response = await GetTempFileResponse(options).ConfigureAwait(false);
- return response.TempFilePath;
- }
-
- public async Task<HttpResponseInfo> GetTempFileResponse(HttpRequestOptions options)
- {
- ValidateParams(options);
-
- Directory.CreateDirectory(_appPaths.TempDirectory);
-
- var tempFile = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid() + ".tmp");
-
- if (options.Progress == null)
- {
- throw new ArgumentException("Options did not have a Progress value.", nameof(options));
- }
-
- options.CancellationToken.ThrowIfCancellationRequested();
-
- var httpWebRequest = GetRequestMessage(options, HttpMethod.Get);
-
- options.Progress.Report(0);
-
- if (options.LogRequest)
- {
- _logger.LogDebug("HttpClientManager.GetTempFileResponse url: {0}", options.Url);
- }
-
- var client = GetHttpClient(options.Url);
-
- try
- {
- options.CancellationToken.ThrowIfCancellationRequested();
-
- using (var response = (await client.SendAsync(httpWebRequest, options.CancellationToken).ConfigureAwait(false)))
- {
- await EnsureSuccessStatusCode(response, options).ConfigureAwait(false);
-
- options.CancellationToken.ThrowIfCancellationRequested();
-
- using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
- using (var fs = _fileSystem.GetFileStream(tempFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
- {
- await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
- }
-
- options.Progress.Report(100);
-
- var responseInfo = new HttpResponseInfo(response.Headers, response.Content.Headers)
- {
- TempFilePath = tempFile,
- StatusCode = response.StatusCode,
- ContentType = response.Content.Headers.ContentType?.MediaType,
- ContentLength = response.Content.Headers.ContentLength
- };
-
- return responseInfo;
- }
- }
- catch (Exception ex)
- {
- if (File.Exists(tempFile))
- {
- File.Delete(tempFile);
- }
-
- throw GetException(ex, options);
- }
- }
-
- private Exception GetException(Exception ex, HttpRequestOptions options)
- {
- if (ex is HttpException)
- {
- return ex;
- }
-
- var webException = ex as WebException
- ?? ex.InnerException as WebException;
-
- if (webException != null)
- {
- if (options.LogErrors)
- {
- _logger.LogError(webException, "Error {Status} getting response from {Url}", webException.Status, options.Url);
- }
-
- var exception = new HttpException(webException.Message, webException);
-
- using (var response = webException.Response as HttpWebResponse)
- {
- if (response != null)
- {
- exception.StatusCode = response.StatusCode;
- }
- }
-
- if (!exception.StatusCode.HasValue)
- {
- if (webException.Status == WebExceptionStatus.NameResolutionFailure ||
- webException.Status == WebExceptionStatus.ConnectFailure)
- {
- exception.IsTimedOut = true;
- }
- }
-
- return exception;
- }
-
- var operationCanceledException = ex as OperationCanceledException
- ?? ex.InnerException as OperationCanceledException;
-
- if (operationCanceledException != null)
- {
- return GetCancellationException(options, options.CancellationToken, operationCanceledException);
- }
-
- if (options.LogErrors)
- {
- _logger.LogError(ex, "Error getting response from {Url}", options.Url);
- }
-
- return ex;
- }
-
private void ValidateParams(HttpRequestOptions options)
{
if (string.IsNullOrEmpty(options.Url))
@@ -471,35 +327,6 @@ namespace Emby.Server.Implementations.HttpClientManager
return url;
}
- /// <summary>
- /// Throws the cancellation exception.
- /// </summary>
- /// <param name="options">The options.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="exception">The exception.</param>
- /// <returns>Exception.</returns>
- private Exception GetCancellationException(HttpRequestOptions options, CancellationToken cancellationToken, OperationCanceledException exception)
- {
- // If the HttpClient's timeout is reached, it will cancel the Task internally
- if (!cancellationToken.IsCancellationRequested)
- {
- var msg = string.Format("Connection to {0} timed out", options.Url);
-
- if (options.LogErrors)
- {
- _logger.LogError(msg);
- }
-
- // Throw an HttpException so that the caller doesn't think it was cancelled by user code
- return new HttpException(msg, exception)
- {
- IsTimedOut = true
- };
- }
-
- return exception;
- }
-
private async Task EnsureSuccessStatusCode(HttpResponseMessage response, HttpRequestOptions options)
{
if (response.IsSuccessStatusCode)
@@ -507,8 +334,11 @@ namespace Emby.Server.Implementations.HttpClientManager
return;
}
- var msg = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
- _logger.LogError("HTTP request failed with message: {Message}", msg);
+ if (options.LogErrorResponseBody)
+ {
+ var msg = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
+ _logger.LogError("HTTP request failed with message: {Message}", msg);
+ }
throw new HttpException(response.ReasonPhrase)
{
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs
index bde7d5c81..7afeba9dd 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs
@@ -65,7 +65,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
try
{
- await _installationManager.InstallPackage(package, new SimpleProgress<double>(), cancellationToken).ConfigureAwait(false);
+ await _installationManager.InstallPackage(package, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
@@ -87,8 +87,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
// Update progress
lock (progress)
{
- numComplete++;
- progress.Report(90.0 * numComplete / packagesToInstall.Count + 10);
+ progress.Report((90.0 * ++numComplete / packagesToInstall.Count) + 10);
}
}
diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs
index 9bc85633d..c60319964 100644
--- a/Emby.Server.Implementations/Updates/InstallationManager.cs
+++ b/Emby.Server.Implementations/Updates/InstallationManager.cs
@@ -4,13 +4,14 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
+using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common;
using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Plugins;
-using MediaBrowser.Common.Progress;
using MediaBrowser.Common.Updates;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Model.Events;
@@ -126,13 +127,16 @@ namespace Emby.Server.Implementations.Updates
/// <returns>Task{List{PackageInfo}}.</returns>
public async Task<List<PackageInfo>> GetAvailablePackagesWithoutRegistrationInfo(CancellationToken cancellationToken)
{
- using (var response = await _httpClient.SendAsync(new HttpRequestOptions
- {
- Url = "https://repo.jellyfin.org/releases/plugin/manifest.json",
- CancellationToken = cancellationToken,
- CacheLength = GetCacheLength()
- }, HttpMethod.Get).ConfigureAwait(false))
- using (var stream = response.Content)
+ using (var response = await _httpClient.SendAsync(
+ new HttpRequestOptions
+ {
+ Url = "https://repo.jellyfin.org/releases/plugin/manifest.json",
+ CancellationToken = cancellationToken,
+ CacheMode = CacheMode.Unconditional,
+ CacheLength = GetCacheLength()
+ },
+ HttpMethod.Get).ConfigureAwait(false))
+ using (Stream stream = response.Content)
{
return FilterPackages(await _jsonSerializer.DeserializeFromStreamAsync<PackageInfo[]>(stream).ConfigureAwait(false));
}
@@ -309,27 +313,14 @@ namespace Emby.Server.Implementations.Updates
.Where(p => !string.IsNullOrEmpty(p.sourceUrl) && !CompletedInstallations.Any(i => string.Equals(i.AssemblyGuid, p.guid, StringComparison.OrdinalIgnoreCase)));
}
- /// <summary>
- /// Installs the package.
- /// </summary>
- /// <param name="package">The package.</param>
- /// <param name="isPlugin">if set to <c>true</c> [is plugin].</param>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- /// <exception cref="ArgumentNullException">package</exception>
- public async Task InstallPackage(PackageVersionInfo package, IProgress<double> progress, CancellationToken cancellationToken)
+ /// <inheritdoc />
+ public async Task InstallPackage(PackageVersionInfo package, CancellationToken cancellationToken)
{
if (package == null)
{
throw new ArgumentNullException(nameof(package));
}
- if (progress == null)
- {
- throw new ArgumentNullException(nameof(progress));
- }
-
var installationInfo = new InstallationInfo
{
Id = Guid.NewGuid(),
@@ -349,16 +340,6 @@ namespace Emby.Server.Implementations.Updates
_currentInstallations.Add(tuple);
}
- var innerProgress = new ActionableProgress<double>();
-
- // Whenever the progress updates, update the outer progress object and InstallationInfo
- innerProgress.RegisterAction(percent =>
- {
- progress.Report(percent);
-
- installationInfo.PercentComplete = percent;
- });
-
var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, innerCancellationTokenSource.Token).Token;
var installationEventArgs = new InstallationEventArgs
@@ -371,7 +352,7 @@ namespace Emby.Server.Implementations.Updates
try
{
- await InstallPackageInternal(package, innerProgress, linkedToken).ConfigureAwait(false);
+ await InstallPackageInternal(package, linkedToken).ConfigureAwait(false);
lock (_currentInstallations)
{
@@ -423,20 +404,16 @@ namespace Emby.Server.Implementations.Updates
/// Installs the package internal.
/// </summary>
/// <param name="package">The package.</param>
- /// <param name="isPlugin">if set to <c>true</c> [is plugin].</param>
- /// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task InstallPackageInternal(PackageVersionInfo package, IProgress<double> progress, CancellationToken cancellationToken)
+ /// <returns><see cref="Task" />.</returns>
+ private async Task InstallPackageInternal(PackageVersionInfo package, CancellationToken cancellationToken)
{
// Set last update time if we were installed before
IPlugin plugin = _applicationHost.Plugins.FirstOrDefault(p => string.Equals(p.Id.ToString(), package.guid, StringComparison.OrdinalIgnoreCase))
?? _applicationHost.Plugins.FirstOrDefault(p => p.Name.Equals(package.name, StringComparison.OrdinalIgnoreCase));
- string targetPath = plugin == null ? null : plugin.AssemblyFilePath;
-
// Do the install
- await PerformPackageInstallation(progress, targetPath, package, cancellationToken).ConfigureAwait(false);
+ await PerformPackageInstallation(package, cancellationToken).ConfigureAwait(false);
// Do plugin-specific processing
if (plugin == null)
@@ -455,76 +432,57 @@ namespace Emby.Server.Implementations.Updates
_applicationHost.NotifyPendingRestart();
}
- private async Task PerformPackageInstallation(IProgress<double> progress, string target, PackageVersionInfo package, CancellationToken cancellationToken)
+ private async Task PerformPackageInstallation(PackageVersionInfo package, CancellationToken cancellationToken)
{
- // TODO: Remove the `string target` argument as it is not used any longer
-
var extension = Path.GetExtension(package.targetFilename);
- var isArchive = string.Equals(extension, ".zip", StringComparison.OrdinalIgnoreCase);
-
- if (!isArchive)
+ if (!string.Equals(extension, ".zip", StringComparison.OrdinalIgnoreCase))
{
_logger.LogError("Only zip packages are supported. {Filename} is not a zip archive.", package.targetFilename);
return;
}
// Always override the passed-in target (which is a file) and figure it out again
- target = Path.Combine(_appPaths.PluginsPath, package.name);
- _logger.LogDebug("Installing plugin to {Filename}.", target);
-
- // Download to temporary file so that, if interrupted, it won't destroy the existing installation
- _logger.LogDebug("Downloading ZIP.");
- var tempFile = await _httpClient.GetTempFile(new HttpRequestOptions
- {
- Url = package.sourceUrl,
- CancellationToken = cancellationToken,
- Progress = progress
-
- }).ConfigureAwait(false);
+ string targetDir = Path.Combine(_appPaths.PluginsPath, package.name);
- cancellationToken.ThrowIfCancellationRequested();
-
- // TODO: Validate with a checksum, *properly*
-
- // Check if the target directory already exists, and remove it if so
- if (Directory.Exists(target))
- {
- _logger.LogDebug("Deleting existing plugin at {Filename}.", target);
- Directory.Delete(target, true);
- }
+// CA5351: Do Not Use Broken Cryptographic Algorithms
+#pragma warning disable CA5351
+ using (var res = await _httpClient.SendAsync(
+ new HttpRequestOptions
+ {
+ Url = package.sourceUrl,
+ CancellationToken = cancellationToken,
+ // We need it to be buffered for setting the position
+ BufferContent = true
+ },
+ HttpMethod.Get).ConfigureAwait(false))
+ using (var stream = res.Content)
+ using (var md5 = MD5.Create())
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ var hash = HexHelper.ToHexString(md5.ComputeHash(stream));
+ if (!string.Equals(package.checksum, hash, StringComparison.OrdinalIgnoreCase))
+ {
+ _logger.LogDebug("{0}, {1}", package.checksum, hash);
+ throw new InvalidDataException($"The checksums didn't match while installing {package.name}.");
+ }
- // Success - move it to the real target
- try
- {
- _logger.LogDebug("Extracting ZIP {TempFile} to {Filename}.", tempFile, target);
- using (var stream = File.OpenRead(tempFile))
+ if (Directory.Exists(targetDir))
{
- _zipClient.ExtractAllFromZip(stream, target, true);
+ Directory.Delete(targetDir);
}
- }
- catch (IOException ex)
- {
- _logger.LogError(ex, "Error attempting to extract {TempFile} to {TargetFile}", tempFile, target);
- throw;
- }
- try
- {
- _logger.LogDebug("Deleting temporary file {Filename}.", tempFile);
- _fileSystem.DeleteFile(tempFile);
- }
- catch (IOException ex)
- {
- // Don't fail because of this
- _logger.LogError(ex, "Error deleting temp file {TempFile}", tempFile);
+ stream.Position = 0;
+ _zipClient.ExtractAllFromZip(stream, targetDir, true);
}
+
+#pragma warning restore CA5351
}
/// <summary>
/// Uninstalls a plugin
/// </summary>
/// <param name="plugin">The plugin.</param>
- /// <exception cref="ArgumentException"></exception>
public void UninstallPlugin(IPlugin plugin)
{
plugin.OnUninstalling();
diff --git a/MediaBrowser.Api/PackageService.cs b/MediaBrowser.Api/PackageService.cs
index cf1e08d53..915c9784e 100644
--- a/MediaBrowser.Api/PackageService.cs
+++ b/MediaBrowser.Api/PackageService.cs
@@ -197,7 +197,7 @@ namespace MediaBrowser.Api
throw new ResourceNotFoundException(string.Format("Package not found: {0}", request.Name));
}
- await _installationManager.InstallPackage(package, new SimpleProgress<double>(), CancellationToken.None);
+ await _installationManager.InstallPackage(package, CancellationToken.None);
}
/// <summary>
diff --git a/MediaBrowser.Common/Extensions/HexHelper.cs b/MediaBrowser.Common/Extensions/HexHelper.cs
new file mode 100644
index 000000000..3d80d94ac
--- /dev/null
+++ b/MediaBrowser.Common/Extensions/HexHelper.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Globalization;
+
+namespace MediaBrowser.Common.Extensions
+{
+ public static class HexHelper
+ {
+ public static byte[] FromHexString(string str)
+ {
+ byte[] bytes = new byte[str.Length / 2];
+ for (int i = 0; i < str.Length; i += 2)
+ {
+ bytes[i / 2] = byte.Parse(str.Substring(i, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
+ }
+
+ return bytes;
+ }
+
+ public static string ToHexString(byte[] bytes)
+ => BitConverter.ToString(bytes).Replace("-", "");
+ }
+}
diff --git a/MediaBrowser.Common/Net/HttpRequestOptions.cs b/MediaBrowser.Common/Net/HttpRequestOptions.cs
index 76bd35e57..94b972a02 100644
--- a/MediaBrowser.Common/Net/HttpRequestOptions.cs
+++ b/MediaBrowser.Common/Net/HttpRequestOptions.cs
@@ -64,12 +64,6 @@ namespace MediaBrowser.Common.Net
set => RequestHeaders[HeaderNames.Host] = value;
}
- /// <summary>
- /// Gets or sets the progress.
- /// </summary>
- /// <value>The progress.</value>
- public IProgress<double> Progress { get; set; }
-
public Dictionary<string, string> RequestHeaders { get; private set; }
public string RequestContentType { get; set; }
@@ -79,10 +73,6 @@ namespace MediaBrowser.Common.Net
public bool BufferContent { get; set; }
- public bool LogRequest { get; set; }
- public bool LogRequestAsDebug { get; set; }
- public bool LogErrors { get; set; }
-
public bool LogErrorResponseBody { get; set; }
public bool EnableKeepAlive { get; set; }
@@ -105,8 +95,6 @@ namespace MediaBrowser.Common.Net
{
RequestHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- LogRequest = true;
- LogErrors = true;
CacheMode = CacheMode.None;
DecompressionMethod = CompressionMethod.Deflate;
}
diff --git a/MediaBrowser.Common/Net/IHttpClient.cs b/MediaBrowser.Common/Net/IHttpClient.cs
index db69c6f2c..d84a4d664 100644
--- a/MediaBrowser.Common/Net/IHttpClient.cs
+++ b/MediaBrowser.Common/Net/IHttpClient.cs
@@ -47,21 +47,5 @@ namespace MediaBrowser.Common.Net
/// <param name="options">The options.</param>
/// <returns>Task{HttpResponseInfo}.</returns>
Task<HttpResponseInfo> Post(HttpRequestOptions options);
-
- /// <summary>
- /// Downloads the contents of a given url into a temporary location
- /// </summary>
- /// <param name="options">The options.</param>
- /// <returns>Task{System.String}.</returns>
- /// <exception cref="System.ArgumentNullException">progress</exception>
- /// <exception cref="Model.Net.HttpException"></exception>
- Task<string> GetTempFile(HttpRequestOptions options);
-
- /// <summary>
- /// Gets the temporary file response.
- /// </summary>
- /// <param name="options">The options.</param>
- /// <returns>Task{HttpResponseInfo}.</returns>
- Task<HttpResponseInfo> GetTempFileResponse(HttpRequestOptions options);
}
}
diff --git a/MediaBrowser.Common/Updates/IInstallationManager.cs b/MediaBrowser.Common/Updates/IInstallationManager.cs
index 3472a5692..d43024ac8 100644
--- a/MediaBrowser.Common/Updates/IInstallationManager.cs
+++ b/MediaBrowser.Common/Updates/IInstallationManager.cs
@@ -97,12 +97,9 @@ namespace MediaBrowser.Common.Updates
/// Installs the package.
/// </summary>
/// <param name="package">The package.</param>
- /// <param name="isPlugin">if set to <c>true</c> [is plugin].</param>
- /// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- /// <exception cref="ArgumentNullException">package</exception>
- Task InstallPackage(PackageVersionInfo package, IProgress<double> progress, CancellationToken cancellationToken);
+ /// <returns><see cref="Task" />.</returns>
+ Task InstallPackage(PackageVersionInfo package, CancellationToken cancellationToken);
/// <summary>
/// Uninstalls a plugin
diff --git a/MediaBrowser.Model/Cryptography/PasswordHash.cs b/MediaBrowser.Model/Cryptography/PasswordHash.cs
index df32fdb00..4bcf0c117 100644
--- a/MediaBrowser.Model/Cryptography/PasswordHash.cs
+++ b/MediaBrowser.Model/Cryptography/PasswordHash.cs
@@ -84,6 +84,7 @@ namespace MediaBrowser.Model.Cryptography
_hash = Array.Empty<Byte>();
}
+ // TODO: move this class and use the HexHelper class
public static byte[] ConvertFromByteString(string byteString)
{
byte[] bytes = new byte[byteString.Length / 2];
diff --git a/MediaBrowser.Model/Updates/InstallationInfo.cs b/MediaBrowser.Model/Updates/InstallationInfo.cs
index a3f19e236..7554e9fe2 100644
--- a/MediaBrowser.Model/Updates/InstallationInfo.cs
+++ b/MediaBrowser.Model/Updates/InstallationInfo.cs
@@ -36,11 +36,5 @@ namespace MediaBrowser.Model.Updates
/// </summary>
/// <value>The update class.</value>
public PackageVersionClass UpdateClass { get; set; }
-
- /// <summary>
- /// Gets or sets the percent complete.
- /// </summary>
- /// <value>The percent complete.</value>
- public double? PercentComplete { get; set; }
}
}
diff --git a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs
index 4b41589f1..ef412db5a 100644
--- a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs
+++ b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs
@@ -2,10 +2,10 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Net;
-using MediaBrowser.Common.Progress;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
@@ -143,26 +143,20 @@ namespace MediaBrowser.Providers.Studios
if (!fileInfo.Exists || (DateTime.UtcNow - fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays > 1)
{
- var temp = await httpClient.GetTempFile(new HttpRequestOptions
- {
- CancellationToken = cancellationToken,
- Progress = new SimpleProgress<double>(),
- Url = url
-
- }).ConfigureAwait(false);
-
Directory.CreateDirectory(Path.GetDirectoryName(file));
- try
- {
- File.Copy(temp, file, true);
- }
- catch
+ using (var res = await httpClient.SendAsync(
+ new HttpRequestOptions
+ {
+ CancellationToken = cancellationToken,
+ Url = url
+ },
+ HttpMethod.Get).ConfigureAwait(false))
+ using (var content = res.Content)
+ using (var fileStream = new FileStream(file, FileMode.Create))
{
-
+ await content.CopyToAsync(fileStream).ConfigureAwait(false);
}
-
- return temp;
}
return file;
diff --git a/Mono.Nat/Upnp/Messages/GetServicesMessage.cs b/Mono.Nat/Upnp/Messages/GetServicesMessage.cs
index 72b4c2b25..f619f5ca4 100644
--- a/Mono.Nat/Upnp/Messages/GetServicesMessage.cs
+++ b/Mono.Nat/Upnp/Messages/GetServicesMessage.cs
@@ -25,50 +25,37 @@
//
using System;
-using System.Diagnostics;
using System.Net;
using MediaBrowser.Common.Net;
-using Microsoft.Extensions.Logging;
namespace Mono.Nat.Upnp
{
internal class GetServicesMessage : MessageBase
{
- private string servicesDescriptionUrl;
- private EndPoint hostAddress;
- private readonly ILogger _logger;
+ private string _servicesDescriptionUrl;
+ private EndPoint _hostAddress;
- public GetServicesMessage(string description, EndPoint hostAddress, ILogger logger)
+ public GetServicesMessage(string description, EndPoint hostAddress)
: base(null)
{
if (string.IsNullOrEmpty(description))
- _logger.LogWarning("Description is null");
-
- if (hostAddress == null)
- _logger.LogWarning("hostaddress is null");
-
- this.servicesDescriptionUrl = description;
- this.hostAddress = hostAddress;
- _logger = logger;
- }
-
- public override string Method
- {
- get
{
- return "GET";
+ throw new ArgumentException("Description is null/empty", nameof(description));
}
+
+ this._servicesDescriptionUrl = description;
+ this._hostAddress = hostAddress ?? throw new ArgumentNullException(nameof(hostAddress));
}
+ public override string Method => "GET";
+
public override HttpRequestOptions Encode()
{
- var req = new HttpRequestOptions();
-
- // The periodic request logging may keep some devices awake
- req.LogRequestAsDebug = true;
- req.LogErrors = false;
+ var req = new HttpRequestOptions()
+ {
+ Url = $"http://{this._hostAddress}{this._servicesDescriptionUrl}"
+ };
- req.Url = "http://" + this.hostAddress.ToString() + this.servicesDescriptionUrl;
req.RequestHeaders.Add("ACCEPT-LANGUAGE", "en");
return req;
diff --git a/Mono.Nat/Upnp/Messages/UpnpMessage.cs b/Mono.Nat/Upnp/Messages/UpnpMessage.cs
index ade9df50b..d47241d4a 100644
--- a/Mono.Nat/Upnp/Messages/UpnpMessage.cs
+++ b/Mono.Nat/Upnp/Messages/UpnpMessage.cs
@@ -24,13 +24,8 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-using System;
-using System.Diagnostics;
using System.Xml;
-using System.Net;
-using System.IO;
using System.Text;
-using System.Globalization;
using MediaBrowser.Common.Net;
namespace Mono.Nat.Upnp
@@ -46,38 +41,31 @@ namespace Mono.Nat.Upnp
protected HttpRequestOptions CreateRequest(string upnpMethod, string methodParameters)
{
- string ss = "http://" + this.device.HostEndPoint.ToString() + this.device.ControlUrl;
+ var req = new HttpRequestOptions()
+ {
+ Url = $"http://{this.device.HostEndPoint}{this.device.ControlUrl}",
+ EnableKeepAlive = false,
+ RequestContentType = "text/xml",
+ RequestContent = "<s:Envelope "
+ + "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
+ + "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
+ + "<s:Body>"
+ + "<u:" + upnpMethod + " "
+ + "xmlns:u=\"" + device.ServiceType + "\">"
+ + methodParameters
+ + "</u:" + upnpMethod + ">"
+ + "</s:Body>"
+ + "</s:Envelope>\r\n\r\n"
+ };
- var req = new HttpRequestOptions();
- req.LogErrors = false;
-
- // The periodic request logging may keep some devices awake
- req.LogRequestAsDebug = true;
-
- req.Url = ss;
- req.EnableKeepAlive = false;
- req.RequestContentType = "text/xml";
req.RequestHeaders.Add("SOAPACTION", "\"" + device.ServiceType + "#" + upnpMethod + "\"");
- req.RequestContent = "<s:Envelope "
- + "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
- + "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
- + "<s:Body>"
- + "<u:" + upnpMethod + " "
- + "xmlns:u=\"" + device.ServiceType + "\">"
- + methodParameters
- + "</u:" + upnpMethod + ">"
- + "</s:Body>"
- + "</s:Envelope>\r\n\r\n";
return req;
}
public abstract HttpRequestOptions Encode();
- public virtual string Method
- {
- get { return "POST"; }
- }
+ public virtual string Method => "POST";
protected void WriteFullElement(XmlWriter writer, string element, string value)
{
diff --git a/Mono.Nat/Upnp/UpnpNatDevice.cs b/Mono.Nat/Upnp/UpnpNatDevice.cs
index fd408ee63..3ff1eeb90 100644
--- a/Mono.Nat/Upnp/UpnpNatDevice.cs
+++ b/Mono.Nat/Upnp/UpnpNatDevice.cs
@@ -27,11 +27,9 @@
//
using System;
-using System.IO;
using System.Net;
using System.Xml;
using System.Text;
-using System.Diagnostics;
using System.Threading.Tasks;
using MediaBrowser.Common.Net;
using Microsoft.Extensions.Logging;
@@ -96,7 +94,7 @@ namespace Mono.Nat.Upnp
public async Task GetServicesList()
{
// Create a HTTPWebRequest to download the list of services the device offers
- var message = new GetServicesMessage(this.serviceDescriptionUrl, this.hostEndPoint, _logger);
+ var message = new GetServicesMessage(this.serviceDescriptionUrl, this.hostEndPoint);
using (var response = await _httpClient.SendAsync(message.Encode(), message.Method).ConfigureAwait(false))
{
diff --git a/jellyfin.ruleset b/jellyfin.ruleset
index e7e02a7d5..8ea1d6b16 100644
--- a/jellyfin.ruleset
+++ b/jellyfin.ruleset
@@ -38,5 +38,7 @@
<Rule Id="CA1054" Action="None" />
<!-- disable warning CA1303: Do not pass literals as localized parameters -->
<Rule Id="CA1303" Action="None" />
+ <!-- disable warning CA2000: Dispose objects before losing scope -->
+ <Rule Id="CA2000" Action="None" />
</Rules>
</RuleSet>