فهرست منبع

Merge pull request #1080 from Bond-009/httpclient

Remove usage of deprecated 'WebRequest'
Anthony Lavado 6 سال پیش
والد
کامیت
d4a42a1680

+ 6 - 5
Emby.Server.Implementations/ApplicationHost.cs

@@ -6,6 +6,7 @@ using System.Globalization;
 using System.IO;
 using System.Linq;
 using System.Net;
+using System.Net.Http;
 using System.Reflection;
 using System.Runtime.InteropServices;
 using System.Security.Cryptography.X509Certificates;
@@ -1538,12 +1539,12 @@ namespace Emby.Server.Implementations
                     LogErrorResponseBody = false,
                     LogErrors = false,
                     LogRequest = false,
-                    TimeoutMs = 10000,
                     BufferContent = false,
                     CancellationToken = cancellationToken
                 }).ConfigureAwait(false))
                 {
-                    return GetWanApiUrl(response.ReadToEnd().Trim());
+                    string res = await response.ReadToEndAsync().ConfigureAwait(false);
+                    return GetWanApiUrl(res.Trim());
                 }
             }
             catch (Exception ex)
@@ -1696,15 +1697,15 @@ namespace Emby.Server.Implementations
                         LogErrorResponseBody = false,
                         LogErrors = LogPing,
                         LogRequest = LogPing,
-                        TimeoutMs = 5000,
                         BufferContent = false,
 
                         CancellationToken = cancellationToken
-                    }, "POST").ConfigureAwait(false))
+
+                    }, HttpMethod.Post).ConfigureAwait(false))
                 {
                     using (var reader = new StreamReader(response.Content))
                     {
-                        var result = reader.ReadToEnd();
+                        var result = await reader.ReadToEndAsync().ConfigureAwait(false);
                         var valid = string.Equals(Name, result, StringComparison.OrdinalIgnoreCase);
 
                         _validAddressResults.AddOrUpdate(apiUrl, valid, (k, v) => valid);

+ 0 - 18
Emby.Server.Implementations/HttpClientManager/HttpClientInfo.cs

@@ -1,18 +0,0 @@
-using System;
-using System.Net.Http;
-
-namespace Emby.Server.Implementations.HttpClientManager
-{
-    /// <summary>
-    /// Class HttpClientInfo
-    /// </summary>
-    public class HttpClientInfo
-    {
-        /// <summary>
-        /// Gets or sets the last timeout.
-        /// </summary>
-        /// <value>The last timeout.</value>
-        public DateTime LastTimeout { get; set; }
-        public HttpClient HttpClient { get; set; }
-    }
-}

+ 149 - 299
Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs

@@ -1,11 +1,10 @@
 using System;
 using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Globalization;
 using System.IO;
 using System.Linq;
 using System.Net;
-using System.Net.Cache;
+using System.Net.Http;
+using System.Net.Http.Headers;
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
@@ -55,12 +54,13 @@ namespace Emby.Server.Implementations.HttpClientManager
             {
                 throw new ArgumentNullException(nameof(appPaths));
             }
+
             if (loggerFactory == null)
             {
                 throw new ArgumentNullException(nameof(loggerFactory));
             }
 
-            _logger = loggerFactory.CreateLogger("HttpClient");
+            _logger = loggerFactory.CreateLogger(nameof(HttpClientManager));
             _fileSystem = fileSystem;
             _appPaths = appPaths;
             _defaultUserAgentFn = defaultUserAgentFn;
@@ -74,27 +74,26 @@ namespace Emby.Server.Implementations.HttpClientManager
         /// DON'T dispose it after use.
         /// </summary>
         /// <value>The HTTP clients.</value>
-        private readonly ConcurrentDictionary<string, HttpClientInfo> _httpClients = new ConcurrentDictionary<string, HttpClientInfo>();
+        private readonly ConcurrentDictionary<string, HttpClient> _httpClients = new ConcurrentDictionary<string, HttpClient>();
 
         /// <summary>
         /// Gets
         /// </summary>
-        /// <param name="host">The host.</param>
+        /// <param name="url">The host.</param>
         /// <param name="enableHttpCompression">if set to <c>true</c> [enable HTTP compression].</param>
         /// <returns>HttpClient.</returns>
         /// <exception cref="ArgumentNullException">host</exception>
-        private HttpClientInfo GetHttpClient(string host, bool enableHttpCompression)
+        private HttpClient GetHttpClient(string url, bool enableHttpCompression)
         {
-            if (string.IsNullOrEmpty(host))
-            {
-                throw new ArgumentNullException(nameof(host));
-            }
-
-            var key = host + enableHttpCompression;
+            var key = GetHostFromUrl(url) + enableHttpCompression;
 
             if (!_httpClients.TryGetValue(key, out var client))
             {
-                client = new HttpClientInfo();
+
+                client = new HttpClient()
+                {
+                    BaseAddress = new Uri(url)
+                };
 
                 _httpClients.TryAdd(key, client);
             }
@@ -102,110 +101,87 @@ namespace Emby.Server.Implementations.HttpClientManager
             return client;
         }
 
-        private WebRequest GetRequest(HttpRequestOptions options, string method)
+        private HttpRequestMessage GetRequestMessage(HttpRequestOptions options, HttpMethod method)
         {
             string url = options.Url;
-
             var uriAddress = new Uri(url);
             string userInfo = uriAddress.UserInfo;
             if (!string.IsNullOrWhiteSpace(userInfo))
             {
-                _logger.LogInformation("Found userInfo in url: {0} ... url: {1}", userInfo, url);
+                _logger.LogWarning("Found userInfo in url: {0} ... url: {1}", userInfo, url);
                 url = url.Replace(userInfo + "@", string.Empty);
             }
 
-            var request = WebRequest.Create(url);
+            var request = new HttpRequestMessage(method, url);
 
-            if (request is HttpWebRequest httpWebRequest)
-            {
-                AddRequestHeaders(httpWebRequest, options);
+            AddRequestHeaders(request, options);
 
-                if (options.EnableHttpCompression)
+            if (options.EnableHttpCompression)
+            {
+                if (options.DecompressionMethod.HasValue
+                    && options.DecompressionMethod.Value == CompressionMethod.Gzip)
                 {
-                    httpWebRequest.AutomaticDecompression = DecompressionMethods.Deflate;
-                    if (options.DecompressionMethod.HasValue
-                        && options.DecompressionMethod.Value == CompressionMethod.Gzip)
-                    {
-                        httpWebRequest.AutomaticDecompression = DecompressionMethods.GZip;
-                    }
+                    request.Headers.Add(HeaderNames.AcceptEncoding, new[] { "gzip", "deflate" });
                 }
                 else
                 {
-                    httpWebRequest.AutomaticDecompression = DecompressionMethods.None;
+                    request.Headers.Add(HeaderNames.AcceptEncoding, "deflate");
                 }
+            }
 
-                httpWebRequest.KeepAlive = options.EnableKeepAlive;
+            if (options.EnableKeepAlive)
+            {
+                request.Headers.Add(HeaderNames.Connection, "Keep-Alive");
+            }
 
-                if (!string.IsNullOrEmpty(options.Host))
-                {
-                    httpWebRequest.Host = options.Host;
-                }
+            if (!string.IsNullOrEmpty(options.Host))
+            {
+                request.Headers.Add(HeaderNames.Host, options.Host);
+            }
 
-                if (!string.IsNullOrEmpty(options.Referer))
-                {
-                    httpWebRequest.Referer = options.Referer;
-                }
+            if (!string.IsNullOrEmpty(options.Referer))
+            {
+                request.Headers.Add(HeaderNames.Referer, options.Referer);
             }
 
-            request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
+            //request.Headers.Add(HeaderNames.CacheControl, "no-cache");
 
-            request.Method = method;
-            request.Timeout = options.TimeoutMs;
+            //request.Headers.Add(HeaderNames., options.TimeoutMs;
 
+            /*
             if (!string.IsNullOrWhiteSpace(userInfo))
             {
                 var parts = userInfo.Split(':');
                 if (parts.Length == 2)
                 {
-                    request.Credentials = GetCredential(url, parts[0], parts[1]);
-                    // TODO: .net core ??
-                    request.PreAuthenticate = true;
+                    request.Headers.Add(HeaderNames., GetCredential(url, parts[0], parts[1]);
                 }
             }
+            */
 
             return request;
         }
 
-        private static CredentialCache GetCredential(string url, string username, string password)
-        {
-            //ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
-            var credentialCache = new CredentialCache();
-            credentialCache.Add(new Uri(url), "Basic", new NetworkCredential(username, password));
-            return credentialCache;
-        }
-
-        private void AddRequestHeaders(HttpWebRequest request, HttpRequestOptions options)
+        private void AddRequestHeaders(HttpRequestMessage request, HttpRequestOptions options)
         {
             var hasUserAgent = false;
 
             foreach (var header in options.RequestHeaders)
             {
-                if (string.Equals(header.Key, HeaderNames.Accept, StringComparison.OrdinalIgnoreCase))
+                if (string.Equals(header.Key, HeaderNames.UserAgent, StringComparison.OrdinalIgnoreCase))
                 {
-                    request.Accept = header.Value;
-                }
-                else if (string.Equals(header.Key, HeaderNames.UserAgent, StringComparison.OrdinalIgnoreCase))
-                {
-                    SetUserAgent(request, header.Value);
                     hasUserAgent = true;
                 }
-                else
-                {
-                    request.Headers.Set(header.Key, header.Value);
-                }
+
+                request.Headers.Add(header.Key, header.Value);
             }
 
             if (!hasUserAgent && options.EnableDefaultUserAgent)
             {
-                SetUserAgent(request, _defaultUserAgentFn());
+                request.Headers.Add(HeaderNames.UserAgent, _defaultUserAgentFn());
             }
         }
 
-        private static void SetUserAgent(HttpWebRequest request, string userAgent)
-        {
-            request.UserAgent = userAgent;
-        }
-
         /// <summary>
         /// Gets the response internal.
         /// </summary>
@@ -213,7 +189,7 @@ namespace Emby.Server.Implementations.HttpClientManager
         /// <returns>Task{HttpResponseInfo}.</returns>
         public Task<HttpResponseInfo> GetResponse(HttpRequestOptions options)
         {
-            return SendAsync(options, "GET");
+            return SendAsync(options, HttpMethod.Get);
         }
 
         /// <summary>
@@ -235,7 +211,21 @@ namespace Emby.Server.Implementations.HttpClientManager
         /// <returns>Task{HttpResponseInfo}.</returns>
         /// <exception cref="HttpException">
         /// </exception>
-        public async Task<HttpResponseInfo> SendAsync(HttpRequestOptions options, string httpMethod)
+        public Task<HttpResponseInfo> SendAsync(HttpRequestOptions options, string httpMethod)
+        {
+            var httpMethod2 = GetHttpMethod(httpMethod);
+            return SendAsync(options, httpMethod2);
+        }
+
+        /// <summary>
+        /// send as an asynchronous operation.
+        /// </summary>
+        /// <param name="options">The options.</param>
+        /// <param name="httpMethod">The HTTP method.</param>
+        /// <returns>Task{HttpResponseInfo}.</returns>
+        /// <exception cref="HttpException">
+        /// </exception>
+        public async Task<HttpResponseInfo> SendAsync(HttpRequestOptions options, HttpMethod httpMethod)
         {
             if (options.CacheMode == CacheMode.None)
             {
@@ -263,6 +253,40 @@ namespace Emby.Server.Implementations.HttpClientManager
             return response;
         }
 
+        private HttpMethod GetHttpMethod(string httpMethod)
+        {
+            if (httpMethod.Equals("DELETE", StringComparison.OrdinalIgnoreCase))
+            {
+                return HttpMethod.Delete;
+            }
+            else if (httpMethod.Equals("GET", StringComparison.OrdinalIgnoreCase))
+            {
+                return HttpMethod.Get;
+            }
+            else if (httpMethod.Equals("HEAD", StringComparison.OrdinalIgnoreCase))
+            {
+                return HttpMethod.Head;
+            }
+            else if (httpMethod.Equals("OPTIONS", StringComparison.OrdinalIgnoreCase))
+            {
+                return HttpMethod.Options;
+            }
+            else if (httpMethod.Equals("POST", StringComparison.OrdinalIgnoreCase))
+            {
+                return HttpMethod.Post;
+            }
+            else if (httpMethod.Equals("PUT", StringComparison.OrdinalIgnoreCase))
+            {
+                return HttpMethod.Put;
+            }
+            else if (httpMethod.Equals("TRACE", StringComparison.OrdinalIgnoreCase))
+            {
+                return HttpMethod.Trace;
+            }
+
+            throw new ArgumentException("Invalid HTTP method", nameof(httpMethod));
+        }
+
         private HttpResponseInfo GetCachedResponse(string responseCachePath, TimeSpan cacheLength, string url)
         {
             if (File.Exists(responseCachePath)
@@ -294,31 +318,23 @@ namespace Emby.Server.Implementations.HttpClientManager
             }
         }
 
-        private async Task<HttpResponseInfo> SendAsyncInternal(HttpRequestOptions options, string httpMethod)
+        private async Task<HttpResponseInfo> SendAsyncInternal(HttpRequestOptions options, HttpMethod httpMethod)
         {
             ValidateParams(options);
 
             options.CancellationToken.ThrowIfCancellationRequested();
 
-            var client = GetHttpClient(GetHostFromUrl(options.Url), options.EnableHttpCompression);
+            var client = GetHttpClient(options.Url, options.EnableHttpCompression);
 
-            if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < TimeoutSeconds)
-            {
-                throw new HttpException(string.Format("Cancelling connection to {0} due to a previous timeout.", options.Url))
-                {
-                    IsTimedOut = true
-                };
-            }
-
-            var httpWebRequest = GetRequest(options, httpMethod);
+            var httpWebRequest = GetRequestMessage(options, httpMethod);
 
             if (options.RequestContentBytes != null ||
                 !string.IsNullOrEmpty(options.RequestContent) ||
-                string.Equals(httpMethod, "post", StringComparison.OrdinalIgnoreCase))
+                httpMethod == HttpMethod.Post)
             {
                 try
                 {
-                    var bytes = options.RequestContentBytes ?? Encoding.UTF8.GetBytes(options.RequestContent ?? string.Empty);
+                    httpWebRequest.Content = new StringContent(Encoding.UTF8.GetString(options.RequestContentBytes) ?? options.RequestContent ?? string.Empty);
 
                     var contentType = options.RequestContentType ?? "application/x-www-form-urlencoded";
 
@@ -327,8 +343,8 @@ namespace Emby.Server.Implementations.HttpClientManager
                         contentType = contentType.TrimEnd(';') + "; charset=\"utf-8\"";
                     }
 
-                    httpWebRequest.ContentType = contentType;
-                    (await httpWebRequest.GetRequestStreamAsync().ConfigureAwait(false)).Write(bytes, 0, bytes.Length);
+                    httpWebRequest.Headers.Add(HeaderNames.ContentType, contentType);
+                    await client.SendAsync(httpWebRequest).ConfigureAwait(false);
                 }
                 catch (Exception ex)
                 {
@@ -336,143 +352,96 @@ namespace Emby.Server.Implementations.HttpClientManager
                 }
             }
 
-            if (options.ResourcePool != null)
-            {
-                await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false);
-            }
-
-            if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < TimeoutSeconds)
-            {
-                options.ResourcePool?.Release();
-
-                throw new HttpException($"Connection to {options.Url} timed out") { IsTimedOut = true };
-            }
-
             if (options.LogRequest)
             {
-                if (options.LogRequestAsDebug)
-                {
-                    _logger.LogDebug("HttpClientManager {0}: {1}", httpMethod.ToUpper(CultureInfo.CurrentCulture), options.Url);
-                }
-                else
-                {
-                    _logger.LogInformation("HttpClientManager {0}: {1}", httpMethod.ToUpper(CultureInfo.CurrentCulture), options.Url);
-                }
+                _logger.LogDebug("HttpClientManager {0}: {1}", httpMethod.ToString(), options.Url);
             }
 
             try
             {
                 options.CancellationToken.ThrowIfCancellationRequested();
 
-                if (!options.BufferContent)
+                /*if (!options.BufferContent)
                 {
-                    var response = await GetResponseAsync(httpWebRequest, TimeSpan.FromMilliseconds(options.TimeoutMs)).ConfigureAwait(false);
+                    var response = await client.HttpClient.SendAsync(httpWebRequest).ConfigureAwait(false);
 
-                    var httpResponse = (HttpWebResponse)response;
-
-                    EnsureSuccessStatusCode(client, httpResponse, options);
+                    await EnsureSuccessStatusCode(client, response, options).ConfigureAwait(false);
 
                     options.CancellationToken.ThrowIfCancellationRequested();
 
-                    return GetResponseInfo(httpResponse, httpResponse.GetResponseStream(), GetContentLength(httpResponse), httpResponse);
-                }
+                    return GetResponseInfo(response, await response.Content.ReadAsStreamAsync().ConfigureAwait(false), response.Content.Headers.ContentLength, response);
+                }*/
 
-                using (var response = await GetResponseAsync(httpWebRequest, TimeSpan.FromMilliseconds(options.TimeoutMs)).ConfigureAwait(false))
+                using (var response = await client.SendAsync(httpWebRequest).ConfigureAwait(false))
                 {
-                    var httpResponse = (HttpWebResponse)response;
-
-                    EnsureSuccessStatusCode(client, httpResponse, options);
+                    await EnsureSuccessStatusCode(response, options).ConfigureAwait(false);
 
                     options.CancellationToken.ThrowIfCancellationRequested();
 
-                    using (var stream = httpResponse.GetResponseStream())
+                    using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
                     {
                         var memoryStream = new MemoryStream();
                         await stream.CopyToAsync(memoryStream).ConfigureAwait(false);
-
                         memoryStream.Position = 0;
 
-                        return GetResponseInfo(httpResponse, memoryStream, memoryStream.Length, null);
+                        return GetResponseInfo(response, memoryStream, memoryStream.Length, null);
                     }
                 }
             }
             catch (OperationCanceledException ex)
             {
-                throw GetCancellationException(options, client, options.CancellationToken, ex);
-            }
-            catch (Exception ex)
-            {
-                throw GetException(ex, options, client);
-            }
-            finally
-            {
-                options.ResourcePool?.Release();
+                throw GetCancellationException(options, options.CancellationToken, ex);
             }
         }
 
-        private HttpResponseInfo GetResponseInfo(HttpWebResponse httpResponse, Stream content, long? contentLength, IDisposable disposable)
+        private HttpResponseInfo GetResponseInfo(HttpResponseMessage httpResponse, Stream content, long? contentLength, IDisposable disposable)
         {
             var responseInfo = new HttpResponseInfo(disposable)
             {
                 Content = content,
                 StatusCode = httpResponse.StatusCode,
-                ContentType = httpResponse.ContentType,
+                ContentType = httpResponse.Content.Headers.ContentType?.MediaType,
                 ContentLength = contentLength,
-                ResponseUrl = httpResponse.ResponseUri.ToString()
+                ResponseUrl = httpResponse.Content.Headers.ContentLocation?.ToString()
             };
 
             if (httpResponse.Headers != null)
             {
-                SetHeaders(httpResponse.Headers, responseInfo);
+                SetHeaders(httpResponse.Content.Headers, responseInfo);
             }
 
             return responseInfo;
         }
 
-        private HttpResponseInfo GetResponseInfo(HttpWebResponse httpResponse, string tempFile, long? contentLength)
+        private HttpResponseInfo GetResponseInfo(HttpResponseMessage httpResponse, string tempFile, long? contentLength)
         {
             var responseInfo = new HttpResponseInfo
             {
                 TempFilePath = tempFile,
                 StatusCode = httpResponse.StatusCode,
-                ContentType = httpResponse.ContentType,
+                ContentType = httpResponse.Content.Headers.ContentType?.MediaType,
                 ContentLength = contentLength
             };
 
             if (httpResponse.Headers != null)
             {
-                SetHeaders(httpResponse.Headers, responseInfo);
+                SetHeaders(httpResponse.Content.Headers, responseInfo);
             }
 
             return responseInfo;
         }
 
-        private static void SetHeaders(WebHeaderCollection headers, HttpResponseInfo responseInfo)
+        private static void SetHeaders(HttpContentHeaders headers, HttpResponseInfo responseInfo)
         {
-            foreach (var key in headers.AllKeys)
+            foreach (var key in headers)
             {
-                responseInfo.Headers[key] = headers[key];
+                responseInfo.Headers[key.Key] = string.Join(", ", key.Value);
             }
         }
 
         public Task<HttpResponseInfo> Post(HttpRequestOptions options)
         {
-            return SendAsync(options, "POST");
-        }
-
-        /// <summary>
-        /// Performs a POST request
-        /// </summary>
-        /// <param name="options">The options.</param>
-        /// <param name="postData">Params to add to the POST data.</param>
-        /// <returns>stream on success, null on failure</returns>
-        public async Task<Stream> Post(HttpRequestOptions options, Dictionary<string, string> postData)
-        {
-            options.SetPostData(postData);
-
-            var response = await Post(options).ConfigureAwait(false);
-
-            return response.Content;
+            return SendAsync(options, HttpMethod.Post);
         }
 
         /// <summary>
@@ -482,9 +451,10 @@ namespace Emby.Server.Implementations.HttpClientManager
         /// <returns>Task{System.String}.</returns>
         public async Task<string> GetTempFile(HttpRequestOptions options)
         {
-            var response = await GetTempFileResponse(options).ConfigureAwait(false);
-
-            return response.TempFilePath;
+            using (var response = await GetTempFileResponse(options).ConfigureAwait(false))
+            {
+                return response.TempFilePath;
+            }
         }
 
         public async Task<HttpResponseInfo> GetTempFileResponse(HttpRequestOptions options)
@@ -502,44 +472,28 @@ namespace Emby.Server.Implementations.HttpClientManager
 
             options.CancellationToken.ThrowIfCancellationRequested();
 
-            var httpWebRequest = GetRequest(options, "GET");
-
-            if (options.ResourcePool != null)
-            {
-                await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false);
-            }
+            var httpWebRequest = GetRequestMessage(options, HttpMethod.Get);
 
             options.Progress.Report(0);
 
             if (options.LogRequest)
             {
-                if (options.LogRequestAsDebug)
-                {
-                    _logger.LogDebug("HttpClientManager.GetTempFileResponse url: {0}", options.Url);
-                }
-                else
-                {
-                    _logger.LogInformation("HttpClientManager.GetTempFileResponse url: {0}", options.Url);
-                }
+                _logger.LogDebug("HttpClientManager.GetTempFileResponse url: {0}", options.Url);
             }
 
-            var client = GetHttpClient(GetHostFromUrl(options.Url), options.EnableHttpCompression);
+            var client = GetHttpClient(options.Url, options.EnableHttpCompression);
 
             try
             {
                 options.CancellationToken.ThrowIfCancellationRequested();
 
-                using (var response = await httpWebRequest.GetResponseAsync().ConfigureAwait(false))
+                using (var response = (await client.SendAsync(httpWebRequest).ConfigureAwait(false)))
                 {
-                    var httpResponse = (HttpWebResponse)response;
-
-                    EnsureSuccessStatusCode(client, httpResponse, options);
+                    await EnsureSuccessStatusCode(response, options).ConfigureAwait(false);
 
                     options.CancellationToken.ThrowIfCancellationRequested();
 
-                    var contentLength = GetContentLength(httpResponse);
-
-                    using (var stream = httpResponse.GetResponseStream())
+                    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);
@@ -547,35 +501,22 @@ namespace Emby.Server.Implementations.HttpClientManager
 
                     options.Progress.Report(100);
 
-                    return GetResponseInfo(httpResponse, tempFile, contentLength);
+                    var contentLength = response.Content.Headers.ContentLength;
+                    return GetResponseInfo(response, tempFile, contentLength);
                 }
             }
             catch (Exception ex)
             {
-                DeleteTempFile(tempFile);
-                throw GetException(ex, options, client);
-            }
-            finally
-            {
-                options.ResourcePool?.Release();
-            }
-        }
-
-        private static long? GetContentLength(HttpWebResponse response)
-        {
-            var length = response.ContentLength;
+                if (File.Exists(tempFile))
+                {
+                    File.Delete(tempFile);
+                }
 
-            if (length == 0)
-            {
-                return null;
+                throw GetException(ex, options);
             }
-
-            return length;
         }
 
-        protected static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
-        private Exception GetException(Exception ex, HttpRequestOptions options, HttpClientInfo client)
+        private Exception GetException(Exception ex, HttpRequestOptions options)
         {
             if (ex is HttpException)
             {
@@ -599,11 +540,6 @@ namespace Emby.Server.Implementations.HttpClientManager
                     if (response != null)
                     {
                         exception.StatusCode = response.StatusCode;
-
-                        if ((int)response.StatusCode == 429)
-                        {
-                            client.LastTimeout = DateTime.UtcNow;
-                        }
                     }
                 }
 
@@ -624,7 +560,7 @@ namespace Emby.Server.Implementations.HttpClientManager
 
             if (operationCanceledException != null)
             {
-                return GetCancellationException(options, client, options.CancellationToken, operationCanceledException);
+                return GetCancellationException(options, options.CancellationToken, operationCanceledException);
             }
 
             if (options.LogErrors)
@@ -635,18 +571,6 @@ namespace Emby.Server.Implementations.HttpClientManager
             return ex;
         }
 
-        private void DeleteTempFile(string file)
-        {
-            try
-            {
-                _fileSystem.DeleteFile(file);
-            }
-            catch (IOException)
-            {
-                // Might not have been created at all. No need to worry.
-            }
-        }
-
         private void ValidateParams(HttpRequestOptions options)
         {
             if (string.IsNullOrEmpty(options.Url))
@@ -682,11 +606,10 @@ namespace Emby.Server.Implementations.HttpClientManager
         /// Throws the cancellation exception.
         /// </summary>
         /// <param name="options">The options.</param>
-        /// <param name="client">The client.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="exception">The exception.</param>
         /// <returns>Exception.</returns>
-        private Exception GetCancellationException(HttpRequestOptions options, HttpClientInfo client, CancellationToken cancellationToken, OperationCanceledException exception)
+        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)
@@ -698,8 +621,6 @@ namespace Emby.Server.Implementations.HttpClientManager
                     _logger.LogError(msg);
                 }
 
-                client.LastTimeout = DateTime.UtcNow;
-
                 // Throw an HttpException so that the caller doesn't think it was cancelled by user code
                 return new HttpException(msg, exception)
                 {
@@ -710,91 +631,20 @@ namespace Emby.Server.Implementations.HttpClientManager
             return exception;
         }
 
-        private void EnsureSuccessStatusCode(HttpClientInfo client, HttpWebResponse response, HttpRequestOptions options)
+        private async Task EnsureSuccessStatusCode(HttpResponseMessage response, HttpRequestOptions options)
         {
-            var statusCode = response.StatusCode;
-
-            var isSuccessful = statusCode >= HttpStatusCode.OK && statusCode <= (HttpStatusCode)299;
-
-            if (isSuccessful)
+            if (response.IsSuccessStatusCode)
             {
                 return;
             }
 
-            if (options.LogErrorResponseBody)
-            {
-                try
-                {
-                    using (var stream = response.GetResponseStream())
-                    {
-                        if (stream != null)
-                        {
-                            using (var reader = new StreamReader(stream))
-                            {
-                                var msg = reader.ReadToEnd();
-
-                                _logger.LogError(msg);
-                            }
-                        }
-                    }
-                }
-                catch
-                {
-
-                }
-            }
+            var msg = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
+            _logger.LogError(msg);
 
-            throw new HttpException(response.StatusDescription)
+            throw new HttpException(response.ReasonPhrase)
             {
                 StatusCode = response.StatusCode
             };
         }
-
-        private static Task<WebResponse> GetResponseAsync(WebRequest request, TimeSpan timeout)
-        {
-            var taskCompletion = new TaskCompletionSource<WebResponse>();
-
-            var asyncTask = Task.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, null);
-
-            ThreadPool.RegisterWaitForSingleObject((asyncTask as IAsyncResult).AsyncWaitHandle, TimeoutCallback, request, timeout, true);
-            var callback = new TaskCallback { taskCompletion = taskCompletion };
-            asyncTask.ContinueWith(callback.OnSuccess, TaskContinuationOptions.NotOnFaulted);
-
-            // Handle errors
-            asyncTask.ContinueWith(callback.OnError, TaskContinuationOptions.OnlyOnFaulted);
-
-            return taskCompletion.Task;
-        }
-
-        private static void TimeoutCallback(object state, bool timedOut)
-        {
-            if (timedOut && state != null)
-            {
-                var request = (WebRequest)state;
-                request.Abort();
-            }
-        }
-
-        private class TaskCallback
-        {
-            public TaskCompletionSource<WebResponse> taskCompletion;
-
-            public void OnSuccess(Task<WebResponse> task)
-            {
-                taskCompletion.TrySetResult(task.Result);
-            }
-
-            public void OnError(Task<WebResponse> task)
-            {
-                if (task.Exception == null)
-                {
-                    taskCompletion.TrySetException(Enumerable.Empty<Exception>());
-                }
-                else
-                {
-                    taskCompletion.TrySetException(task.Exception);
-                }
-            }
-        }
     }
 }

+ 1 - 9
Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs

@@ -96,8 +96,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
                 Url = ApiUrl + "/schedules",
                 UserAgent = UserAgent,
                 CancellationToken = cancellationToken,
-                // The data can be large so give it some extra time
-                TimeoutMs = 60000,
                 LogErrorResponseBody = true,
                 RequestContent = requestString
             };
@@ -115,9 +113,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
                     Url = ApiUrl + "/programs",
                     UserAgent = UserAgent,
                     CancellationToken = cancellationToken,
-                    LogErrorResponseBody = true,
-                    // The data can be large so give it some extra time
-                    TimeoutMs = 60000
+                    LogErrorResponseBody = true
                 };
 
                 httpOptions.RequestHeaders["token"] = token;
@@ -483,8 +479,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
                 CancellationToken = cancellationToken,
                 RequestContent = imageIdString,
                 LogErrorResponseBody = true,
-                // The data can be large so give it some extra time
-                TimeoutMs = 60000
             };
 
             try
@@ -871,8 +865,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
                 UserAgent = UserAgent,
                 CancellationToken = cancellationToken,
                 LogErrorResponseBody = true,
-                // The data can be large so give it some extra time
-                TimeoutMs = 60000
             };
 
             httpOptions.RequestHeaders["token"] = token;

+ 0 - 2
Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs

@@ -138,7 +138,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
                 {
                     Url = string.Format("{0}/discover.json", GetApiUrl(info)),
                     CancellationToken = cancellationToken,
-                    TimeoutMs = Convert.ToInt32(TimeSpan.FromSeconds(10).TotalMilliseconds),
                     BufferContent = false
 
                 }, "GET").ConfigureAwait(false))
@@ -191,7 +190,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
             {
                 Url = string.Format("{0}/tuners.html", GetApiUrl(info)),
                 CancellationToken = cancellationToken,
-                TimeoutMs = Convert.ToInt32(TimeSpan.FromSeconds(5).TotalMilliseconds),
                 BufferContent = false
             }))
             {

+ 0 - 6
Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs

@@ -47,13 +47,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
                 CancellationToken = CancellationToken.None,
                 BufferContent = false,
 
-                // Increase a little bit
-                TimeoutMs = 30000,
-
                 EnableHttpCompression = false,
-
-                LogResponse = true,
-                LogResponseHeaders = true
             };
 
             foreach (var header in mediaSource.RequiredHttpHeaders)

+ 1 - 21
MediaBrowser.Common/Net/HttpRequestOptions.cs

@@ -28,18 +28,13 @@ namespace MediaBrowser.Common.Net
             get => GetHeaderValue(HeaderNames.Accept);
             set => RequestHeaders[HeaderNames.Accept] = value;
         }
+
         /// <summary>
         /// Gets or sets the cancellation token.
         /// </summary>
         /// <value>The cancellation token.</value>
         public CancellationToken CancellationToken { get; set; }
 
-        /// <summary>
-        /// Gets or sets the resource pool.
-        /// </summary>
-        /// <value>The resource pool.</value>
-        public SemaphoreSlim ResourcePool { get; set; }
-
         /// <summary>
         /// Gets or sets the user agent.
         /// </summary>
@@ -86,8 +81,6 @@ namespace MediaBrowser.Common.Net
         public bool LogRequest { get; set; }
         public bool LogRequestAsDebug { get; set; }
         public bool LogErrors { get; set; }
-        public bool LogResponse { get; set; }
-        public bool LogResponseHeaders { get; set; }
 
         public bool LogErrorResponseBody { get; set; }
         public bool EnableKeepAlive { get; set; }
@@ -95,11 +88,9 @@ namespace MediaBrowser.Common.Net
         public CacheMode CacheMode { get; set; }
         public TimeSpan CacheLength { get; set; }
 
-        public int TimeoutMs { get; set; }
         public bool EnableDefaultUserAgent { get; set; }
 
         public bool AppendCharsetToMimeType { get; set; }
-        public string DownloadFilePath { get; set; }
 
         private string GetHeaderValue(string name)
         {
@@ -120,17 +111,6 @@ namespace MediaBrowser.Common.Net
             LogRequest = true;
             LogErrors = true;
             CacheMode = CacheMode.None;
-
-            TimeoutMs = 20000;
-        }
-
-        public void SetPostData(IDictionary<string, string> values)
-        {
-            var strings = values.Keys.Select(key => string.Format("{0}={1}", key, values[key]));
-            var postContent = string.Join("&", strings.ToArray());
-
-            RequestContent = postContent;
-            RequestContentType = "application/x-www-form-urlencoded";
         }
     }
 

+ 11 - 0
MediaBrowser.Common/Net/IHttpClient.cs

@@ -1,5 +1,6 @@
 using System.IO;
 using System.Threading.Tasks;
+using System.Net.Http;
 
 namespace MediaBrowser.Common.Net
 {
@@ -23,6 +24,8 @@ namespace MediaBrowser.Common.Net
         Task<Stream> Get(HttpRequestOptions options);
 
         /// <summary>
+        /// Warning: Deprecated function,
+        /// use 'Task<HttpResponseInfo> SendAsync(HttpRequestOptions options, HttpMethod httpMethod);' instead
         /// Sends the asynchronous.
         /// </summary>
         /// <param name="options">The options.</param>
@@ -30,6 +33,14 @@ namespace MediaBrowser.Common.Net
         /// <returns>Task{HttpResponseInfo}.</returns>
         Task<HttpResponseInfo> SendAsync(HttpRequestOptions options, string httpMethod);
 
+        /// <summary>
+        /// Sends the asynchronous.
+        /// </summary>
+        /// <param name="options">The options.</param>
+        /// <param name="httpMethod">The HTTP method.</param>
+        /// <returns>Task{HttpResponseInfo}.</returns>
+        Task<HttpResponseInfo> SendAsync(HttpRequestOptions options, HttpMethod httpMethod);
+
         /// <summary>
         /// Posts the specified options.
         /// </summary>