mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-12-24 09:44:47 +03:00
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
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user