Browse Source

Replace custom code with Asp.Net Core code

Bond_009 5 năm trước cách đây
mục cha
commit
9fff4b060e

+ 3 - 3
Emby.Server.Implementations/ApplicationHost.cs

@@ -676,7 +676,7 @@ namespace Emby.Server.Implementations
             var localPath = context.Request.Path.ToString();
             var localPath = context.Request.Path.ToString();
 
 
             var req = new WebSocketSharpRequest(request, response, request.Path, Logger);
             var req = new WebSocketSharpRequest(request, response, request.Path, Logger);
-            await HttpServer.RequestHandler(req, request.GetDisplayUrl(), request.Host.ToString(), localPath, CancellationToken.None).ConfigureAwait(false);
+            await HttpServer.RequestHandler(req, request.GetDisplayUrl(), request.Host.ToString(), localPath, context.RequestAborted).ConfigureAwait(false);
         }
         }
 
 
         public static IStreamHelper StreamHelper { get; set; }
         public static IStreamHelper StreamHelper { get; set; }
@@ -785,7 +785,7 @@ namespace Emby.Server.Implementations
 
 
             HttpServer = new HttpListenerHost(
             HttpServer = new HttpListenerHost(
                 this,
                 this,
-                LoggerFactory,
+                LoggerFactory.CreateLogger<HttpListenerHost>(),
                 ServerConfigurationManager,
                 ServerConfigurationManager,
                 _configuration,
                 _configuration,
                 NetworkManager,
                 NetworkManager,
@@ -873,7 +873,7 @@ namespace Emby.Server.Implementations
             serviceCollection.AddSingleton<IAuthorizationContext>(authContext);
             serviceCollection.AddSingleton<IAuthorizationContext>(authContext);
             serviceCollection.AddSingleton<ISessionContext>(new SessionContext(UserManager, authContext, SessionManager));
             serviceCollection.AddSingleton<ISessionContext>(new SessionContext(UserManager, authContext, SessionManager));
 
 
-            AuthService = new AuthService(UserManager, authContext, ServerConfigurationManager, SessionManager, NetworkManager);
+            AuthService = new AuthService(authContext, ServerConfigurationManager, SessionManager, NetworkManager);
             serviceCollection.AddSingleton(AuthService);
             serviceCollection.AddSingleton(AuthService);
 
 
             SubtitleEncoder = new MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder(LibraryManager, LoggerFactory, ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager, ProcessFactory);
             SubtitleEncoder = new MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder(LibraryManager, LoggerFactory, ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager, ProcessFactory);

+ 107 - 67
Emby.Server.Implementations/HttpServer/FileWriter.cs

@@ -1,50 +1,43 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Globalization;
 using System.Globalization;
+using System.IO;
 using System.Linq;
 using System.Linq;
 using System.Net;
 using System.Net;
+using System.Runtime.InteropServices;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
-using Emby.Server.Implementations.IO;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.Services;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
+using Microsoft.AspNetCore.Http;
 using Microsoft.Net.Http.Headers;
 using Microsoft.Net.Http.Headers;
 
 
 namespace Emby.Server.Implementations.HttpServer
 namespace Emby.Server.Implementations.HttpServer
 {
 {
     public class FileWriter : IHttpResult
     public class FileWriter : IHttpResult
     {
     {
-        private readonly IStreamHelper _streamHelper;
-        private ILogger Logger { get; set; }
-        private readonly IFileSystem _fileSystem;
-
-        private string RangeHeader { get; set; }
-        private bool IsHeadRequest { get; set; }
-
-        private long RangeStart { get; set; }
-        private long RangeEnd { get; set; }
-        private long RangeLength { get; set; }
-        public long TotalContentLength { get; set; }
+        private static readonly CultureInfo UsCulture = CultureInfo.ReadOnly(new CultureInfo("en-US"));
 
 
-        public Action OnComplete { get; set; }
-        public Action OnError { get; set; }
-        private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-        public List<Cookie> Cookies { get; private set; }
+        private static readonly string[] _skipLogExtensions = {
+            ".js",
+            ".html",
+            ".css"
+        };
 
 
-        public FileShareMode FileShare { get; set; }
+        private readonly IStreamHelper _streamHelper;
+        private readonly ILogger _logger;
+        private readonly IFileSystem _fileSystem;
 
 
         /// <summary>
         /// <summary>
         /// The _options
         /// The _options
         /// </summary>
         /// </summary>
         private readonly IDictionary<string, string> _options = new Dictionary<string, string>();
         private readonly IDictionary<string, string> _options = new Dictionary<string, string>();
+
         /// <summary>
         /// <summary>
-        /// Gets the options.
+        /// The _requested ranges
         /// </summary>
         /// </summary>
-        /// <value>The options.</value>
-        public IDictionary<string, string> Headers => _options;
-
-        public string Path { get; set; }
+        private List<KeyValuePair<long, long?>> _requestedRanges;
 
 
         public FileWriter(string path, string contentType, string rangeHeader, ILogger logger, IFileSystem fileSystem, IStreamHelper streamHelper)
         public FileWriter(string path, string contentType, string rangeHeader, ILogger logger, IFileSystem fileSystem, IStreamHelper streamHelper)
         {
         {
@@ -57,7 +50,7 @@ namespace Emby.Server.Implementations.HttpServer
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
 
 
             Path = path;
             Path = path;
-            Logger = logger;
+            _logger = logger;
             RangeHeader = rangeHeader;
             RangeHeader = rangeHeader;
 
 
             Headers[HeaderNames.ContentType] = contentType;
             Headers[HeaderNames.ContentType] = contentType;
@@ -80,39 +73,34 @@ namespace Emby.Server.Implementations.HttpServer
             Cookies = new List<Cookie>();
             Cookies = new List<Cookie>();
         }
         }
 
 
-        /// <summary>
-        /// Sets the range values.
-        /// </summary>
-        private void SetRangeValues()
-        {
-            var requestedRange = RequestedRanges[0];
+        private string RangeHeader { get; set; }
 
 
-            // If the requested range is "0-", we can optimize by just doing a stream copy
-            if (!requestedRange.Value.HasValue)
-            {
-                RangeEnd = TotalContentLength - 1;
-            }
-            else
-            {
-                RangeEnd = requestedRange.Value.Value;
-            }
+        private bool IsHeadRequest { get; set; }
 
 
-            RangeStart = requestedRange.Key;
-            RangeLength = 1 + RangeEnd - RangeStart;
+        private long RangeStart { get; set; }
 
 
-            // Content-Length is the length of what we're serving, not the original content
-            var lengthString = RangeLength.ToString(CultureInfo.InvariantCulture);
-            Headers[HeaderNames.ContentLength] = lengthString;
-            var rangeString = $"bytes {RangeStart}-{RangeEnd}/{TotalContentLength}";
-            Headers[HeaderNames.ContentRange] = rangeString;
+        private long RangeEnd { get; set; }
 
 
-            Logger.LogDebug("Setting range response values for {0}. RangeRequest: {1} Content-Length: {2}, Content-Range: {3}", Path, RangeHeader, lengthString, rangeString);
-        }
+        private long RangeLength { get; set; }
+
+        public long TotalContentLength { get; set; }
+
+        public Action OnComplete { get; set; }
+
+        public Action OnError { get; set; }
+
+        public List<Cookie> Cookies { get; private set; }
+
+        public FileShareMode FileShare { get; set; }
 
 
         /// <summary>
         /// <summary>
-        /// The _requested ranges
+        /// Gets the options.
         /// </summary>
         /// </summary>
-        private List<KeyValuePair<long, long?>> _requestedRanges;
+        /// <value>The options.</value>
+        public IDictionary<string, string> Headers => _options;
+
+        public string Path { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets the requested ranges.
         /// Gets the requested ranges.
         /// </summary>
         /// </summary>
@@ -139,6 +127,7 @@ namespace Emby.Server.Implementations.HttpServer
                         {
                         {
                             start = long.Parse(vals[0], UsCulture);
                             start = long.Parse(vals[0], UsCulture);
                         }
                         }
+
                         if (!string.IsNullOrEmpty(vals[1]))
                         if (!string.IsNullOrEmpty(vals[1]))
                         {
                         {
                             end = long.Parse(vals[1], UsCulture);
                             end = long.Parse(vals[1], UsCulture);
@@ -152,13 +141,50 @@ namespace Emby.Server.Implementations.HttpServer
             }
             }
         }
         }
 
 
-        private static readonly string[] SkipLogExtensions = {
-            ".js",
-            ".html",
-            ".css"
-        };
+        public string ContentType { get; set; }
+
+        public IRequest RequestContext { get; set; }
+
+        public object Response { get; set; }
+
+        public int Status { get; set; }
+
+        public HttpStatusCode StatusCode
+        {
+            get => (HttpStatusCode)Status;
+            set => Status = (int)value;
+        }
+
+        /// <summary>
+        /// Sets the range values.
+        /// </summary>
+        private void SetRangeValues()
+        {
+            var requestedRange = RequestedRanges[0];
+
+            // If the requested range is "0-", we can optimize by just doing a stream copy
+            if (!requestedRange.Value.HasValue)
+            {
+                RangeEnd = TotalContentLength - 1;
+            }
+            else
+            {
+                RangeEnd = requestedRange.Value.Value;
+            }
+
+            RangeStart = requestedRange.Key;
+            RangeLength = 1 + RangeEnd - RangeStart;
+
+            // Content-Length is the length of what we're serving, not the original content
+            var lengthString = RangeLength.ToString(CultureInfo.InvariantCulture);
+            Headers[HeaderNames.ContentLength] = lengthString;
+            var rangeString = $"bytes {RangeStart}-{RangeEnd}/{TotalContentLength}";
+            Headers[HeaderNames.ContentRange] = rangeString;
 
 
-        public async Task WriteToAsync(IResponse response, CancellationToken cancellationToken)
+            _logger.LogInformation("Setting range response values for {0}. RangeRequest: {1} Content-Length: {2}, Content-Range: {3}", Path, RangeHeader, lengthString, rangeString);
+        }
+
+        public async Task WriteToAsync(HttpResponse response, CancellationToken cancellationToken)
         {
         {
             try
             try
             {
             {
@@ -176,16 +202,16 @@ namespace Emby.Server.Implementations.HttpServer
                 {
                 {
                     var extension = System.IO.Path.GetExtension(path);
                     var extension = System.IO.Path.GetExtension(path);
 
 
-                    if (extension == null || !SkipLogExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
+                    if (extension == null || !_skipLogExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
                     {
                     {
-                        Logger.LogDebug("Transmit file {0}", path);
+                        _logger.LogDebug("Transmit file {0}", path);
                     }
                     }
 
 
                     offset = 0;
                     offset = 0;
                     count = 0;
                     count = 0;
                 }
                 }
 
 
-                await response.TransmitFile(path, offset, count, FileShare, _fileSystem, _streamHelper, cancellationToken).ConfigureAwait(false);
+                await TransmitFile(response.Body, path, offset, count, FileShare, cancellationToken).ConfigureAwait(false);
             }
             }
             finally
             finally
             {
             {
@@ -193,18 +219,32 @@ namespace Emby.Server.Implementations.HttpServer
             }
             }
         }
         }
 
 
-        public string ContentType { get; set; }
-
-        public IRequest RequestContext { get; set; }
+        public async Task TransmitFile(Stream stream, string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
+        {
+            var fileOpenOptions = FileOpenOptions.SequentialScan;
 
 
-        public object Response { get; set; }
+            // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
+            if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+            {
+                fileOpenOptions |= FileOpenOptions.Asynchronous;
+            }
 
 
-        public int Status { get; set; }
+            using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, fileShareMode, fileOpenOptions))
+            {
+                if (offset > 0)
+                {
+                    fs.Position = offset;
+                }
 
 
-        public HttpStatusCode StatusCode
-        {
-            get => (HttpStatusCode)Status;
-            set => Status = (int)value;
+                if (count > 0)
+                {
+                    await _streamHelper.CopyToAsync(fs, stream, count, cancellationToken).ConfigureAwait(false);
+                }
+                else
+                {
+                    await fs.CopyToAsync(stream, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false);
+                }
+            }
         }
         }
     }
     }
 }
 }

+ 63 - 91
Emby.Server.Implementations/HttpServer/HttpListenerHost.cs

@@ -5,7 +5,6 @@ using System.IO;
 using System.Linq;
 using System.Linq;
 using System.Net.Sockets;
 using System.Net.Sockets;
 using System.Reflection;
 using System.Reflection;
-using System.Text;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Emby.Server.Implementations.Net;
 using Emby.Server.Implementations.Net;
@@ -30,11 +29,7 @@ namespace Emby.Server.Implementations.HttpServer
 {
 {
     public class HttpListenerHost : IHttpServer, IDisposable
     public class HttpListenerHost : IHttpServer, IDisposable
     {
     {
-        private string DefaultRedirectPath { get; set; }
-        public string[] UrlPrefixes { get; private set; }
-
-        public event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected;
-
+        private readonly ILogger _logger;
         private readonly IServerConfigurationManager _config;
         private readonly IServerConfigurationManager _config;
         private readonly INetworkManager _networkManager;
         private readonly INetworkManager _networkManager;
         private readonly IServerApplicationHost _appHost;
         private readonly IServerApplicationHost _appHost;
@@ -42,18 +37,15 @@ namespace Emby.Server.Implementations.HttpServer
         private readonly IXmlSerializer _xmlSerializer;
         private readonly IXmlSerializer _xmlSerializer;
         private readonly IHttpListener _socketListener;
         private readonly IHttpListener _socketListener;
         private readonly Func<Type, Func<string, object>> _funcParseFn;
         private readonly Func<Type, Func<string, object>> _funcParseFn;
-
-        public Action<IRequest, IResponse, object>[] ResponseFilters { get; set; }
-
+        private readonly string _defaultRedirectPath;
         private readonly Dictionary<Type, Type> ServiceOperationsMap = new Dictionary<Type, Type>();
         private readonly Dictionary<Type, Type> ServiceOperationsMap = new Dictionary<Type, Type>();
-        public static HttpListenerHost Instance { get; protected set; }
-
         private IWebSocketListener[] _webSocketListeners = Array.Empty<IWebSocketListener>();
         private IWebSocketListener[] _webSocketListeners = Array.Empty<IWebSocketListener>();
         private readonly List<IWebSocketConnection> _webSocketConnections = new List<IWebSocketConnection>();
         private readonly List<IWebSocketConnection> _webSocketConnections = new List<IWebSocketConnection>();
+        private bool _disposed = false;
 
 
         public HttpListenerHost(
         public HttpListenerHost(
             IServerApplicationHost applicationHost,
             IServerApplicationHost applicationHost,
-            ILoggerFactory loggerFactory,
+            ILogger<HttpListenerHost> logger,
             IServerConfigurationManager config,
             IServerConfigurationManager config,
             IConfiguration configuration,
             IConfiguration configuration,
             INetworkManager networkManager,
             INetworkManager networkManager,
@@ -62,9 +54,9 @@ namespace Emby.Server.Implementations.HttpServer
             IHttpListener socketListener)
             IHttpListener socketListener)
         {
         {
             _appHost = applicationHost;
             _appHost = applicationHost;
-            Logger = loggerFactory.CreateLogger("HttpServer");
+            _logger = logger;
             _config = config;
             _config = config;
-            DefaultRedirectPath = configuration["HttpListenerHost:DefaultRedirectPath"];
+            _defaultRedirectPath = configuration["HttpListenerHost:DefaultRedirectPath"];
             _networkManager = networkManager;
             _networkManager = networkManager;
             _jsonSerializer = jsonSerializer;
             _jsonSerializer = jsonSerializer;
             _xmlSerializer = xmlSerializer;
             _xmlSerializer = xmlSerializer;
@@ -74,12 +66,20 @@ namespace Emby.Server.Implementations.HttpServer
             _funcParseFn = t => s => JsvReader.GetParseFn(t)(s);
             _funcParseFn = t => s => JsvReader.GetParseFn(t)(s);
 
 
             Instance = this;
             Instance = this;
-            ResponseFilters = Array.Empty<Action<IRequest, IResponse, object>>();
+            ResponseFilters = Array.Empty<Action<IRequest, HttpResponse, object>>();
         }
         }
 
 
+        public Action<IRequest, HttpResponse, object>[] ResponseFilters { get; set; }
+
+        public static HttpListenerHost Instance { get; protected set; }
+
+        public string[] UrlPrefixes { get; private set; }
+
         public string GlobalResponse { get; set; }
         public string GlobalResponse { get; set; }
 
 
-        protected ILogger Logger { get; }
+        public ServiceController ServiceController { get; private set; }
+
+        public event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected;
 
 
         public object CreateInstance(Type type)
         public object CreateInstance(Type type)
         {
         {
@@ -91,7 +91,7 @@ namespace Emby.Server.Implementations.HttpServer
         /// and no more processing should be done.
         /// and no more processing should be done.
         /// </summary>
         /// </summary>
         /// <returns></returns>
         /// <returns></returns>
-        public void ApplyRequestFilters(IRequest req, IResponse res, object requestDto)
+        public void ApplyRequestFilters(IRequest req, HttpResponse res, object requestDto)
         {
         {
             //Exec all RequestFilter attributes with Priority < 0
             //Exec all RequestFilter attributes with Priority < 0
             var attributes = GetRequestFilterAttributes(requestDto.GetType());
             var attributes = GetRequestFilterAttributes(requestDto.GetType());
@@ -145,7 +145,7 @@ namespace Emby.Server.Implementations.HttpServer
                 return;
                 return;
             }
             }
 
 
-            var connection = new WebSocketConnection(e.WebSocket, e.Endpoint, _jsonSerializer, Logger)
+            var connection = new WebSocketConnection(e.WebSocket, e.Endpoint, _jsonSerializer, _logger)
             {
             {
                 OnReceive = ProcessWebSocketMessageReceived,
                 OnReceive = ProcessWebSocketMessageReceived,
                 Url = e.Url,
                 Url = e.Url,
@@ -215,16 +215,16 @@ namespace Emby.Server.Implementations.HttpServer
 
 
                 if (logExceptionStackTrace)
                 if (logExceptionStackTrace)
                 {
                 {
-                    Logger.LogError(ex, "Error processing request");
+                    _logger.LogError(ex, "Error processing request");
                 }
                 }
                 else if (logExceptionMessage)
                 else if (logExceptionMessage)
                 {
                 {
-                    Logger.LogError(ex.Message);
+                    _logger.LogError(ex.Message);
                 }
                 }
 
 
                 var httpRes = httpReq.Response;
                 var httpRes = httpReq.Response;
 
 
-                if (httpRes.OriginalResponse.HasStarted)
+                if (httpRes.HasStarted)
                 {
                 {
                     return;
                     return;
                 }
                 }
@@ -233,11 +233,11 @@ namespace Emby.Server.Implementations.HttpServer
                 httpRes.StatusCode = statusCode;
                 httpRes.StatusCode = statusCode;
 
 
                 httpRes.ContentType = "text/html";
                 httpRes.ContentType = "text/html";
-                await Write(httpRes, NormalizeExceptionMessage(ex.Message)).ConfigureAwait(false);
+                await httpRes.WriteAsync(NormalizeExceptionMessage(ex.Message)).ConfigureAwait(false);
             }
             }
             catch (Exception errorEx)
             catch (Exception errorEx)
             {
             {
-                Logger.LogError(errorEx, "Error this.ProcessRequest(context)(Exception while writing error to the response)");
+                _logger.LogError(errorEx, "Error this.ProcessRequest(context)(Exception while writing error to the response)");
             }
             }
         }
         }
 
 
@@ -431,7 +431,7 @@ namespace Emby.Server.Implementations.HttpServer
                 {
                 {
                     httpRes.StatusCode = 503;
                     httpRes.StatusCode = 503;
                     httpRes.ContentType = "text/plain";
                     httpRes.ContentType = "text/plain";
-                    await Write(httpRes, "Server shutting down").ConfigureAwait(false);
+                    await httpRes.WriteAsync("Server shutting down", cancellationToken).ConfigureAwait(false);
                     return;
                     return;
                 }
                 }
 
 
@@ -439,7 +439,7 @@ namespace Emby.Server.Implementations.HttpServer
                 {
                 {
                     httpRes.StatusCode = 400;
                     httpRes.StatusCode = 400;
                     httpRes.ContentType = "text/plain";
                     httpRes.ContentType = "text/plain";
-                    await Write(httpRes, "Invalid host").ConfigureAwait(false);
+                    await httpRes.WriteAsync("Invalid host", cancellationToken).ConfigureAwait(false);
                     return;
                     return;
                 }
                 }
 
 
@@ -447,7 +447,7 @@ namespace Emby.Server.Implementations.HttpServer
                 {
                 {
                     httpRes.StatusCode = 403;
                     httpRes.StatusCode = 403;
                     httpRes.ContentType = "text/plain";
                     httpRes.ContentType = "text/plain";
-                    await Write(httpRes, "Forbidden").ConfigureAwait(false);
+                    await httpRes.WriteAsync("Forbidden", cancellationToken).ConfigureAwait(false);
                     return;
                     return;
                 }
                 }
 
 
@@ -460,28 +460,27 @@ namespace Emby.Server.Implementations.HttpServer
                 if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase))
                 if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase))
                 {
                 {
                     httpRes.StatusCode = 200;
                     httpRes.StatusCode = 200;
-                    httpRes.AddHeader("Access-Control-Allow-Origin", "*");
-                    httpRes.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
-                    httpRes.AddHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization");
+                    httpRes.Headers.Add("Access-Control-Allow-Origin", "*");
+                    httpRes.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
+                    httpRes.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization");
                     httpRes.ContentType = "text/plain";
                     httpRes.ContentType = "text/plain";
-                    await Write(httpRes, string.Empty).ConfigureAwait(false);
+                    await httpRes.WriteAsync(string.Empty, cancellationToken).ConfigureAwait(false);
                     return;
                     return;
                 }
                 }
 
 
                 urlToLog = GetUrlToLog(urlString);
                 urlToLog = GetUrlToLog(urlString);
-                Logger.LogDebug("HTTP {HttpMethod} {Url} UserAgent: {UserAgent} \nHeaders: {@Headers}", urlToLog, httpReq.UserAgent ?? string.Empty, httpReq.HttpMethod, httpReq.Headers);
 
 
                 if (string.Equals(localPath, "/emby/", StringComparison.OrdinalIgnoreCase) ||
                 if (string.Equals(localPath, "/emby/", StringComparison.OrdinalIgnoreCase) ||
                     string.Equals(localPath, "/mediabrowser/", StringComparison.OrdinalIgnoreCase))
                     string.Equals(localPath, "/mediabrowser/", StringComparison.OrdinalIgnoreCase))
                 {
                 {
-                    RedirectToUrl(httpRes, DefaultRedirectPath);
+                    httpRes.Redirect(_defaultRedirectPath);
                     return;
                     return;
                 }
                 }
 
 
                 if (string.Equals(localPath, "/emby", StringComparison.OrdinalIgnoreCase) ||
                 if (string.Equals(localPath, "/emby", StringComparison.OrdinalIgnoreCase) ||
                     string.Equals(localPath, "/mediabrowser", StringComparison.OrdinalIgnoreCase))
                     string.Equals(localPath, "/mediabrowser", StringComparison.OrdinalIgnoreCase))
                 {
                 {
-                    RedirectToUrl(httpRes, "emby/" + DefaultRedirectPath);
+                    httpRes.Redirect("emby/" + _defaultRedirectPath);
                     return;
                     return;
                 }
                 }
 
 
@@ -494,9 +493,10 @@ namespace Emby.Server.Implementations.HttpServer
 
 
                     if (!string.Equals(newUrl, urlString, StringComparison.OrdinalIgnoreCase))
                     if (!string.Equals(newUrl, urlString, StringComparison.OrdinalIgnoreCase))
                     {
                     {
-                        await Write(httpRes,
+                        await httpRes.WriteAsync(
                             "<!doctype html><html><head><title>Emby</title></head><body>Please update your Emby bookmark to <a href=\"" +
                             "<!doctype html><html><head><title>Emby</title></head><body>Please update your Emby bookmark to <a href=\"" +
-                            newUrl + "\">" + newUrl + "</a></body></html>").ConfigureAwait(false);
+                            newUrl + "\">" + newUrl + "</a></body></html>",
+                            cancellationToken).ConfigureAwait(false);
                         return;
                         return;
                     }
                     }
                 }
                 }
@@ -511,34 +511,35 @@ namespace Emby.Server.Implementations.HttpServer
 
 
                     if (!string.Equals(newUrl, urlString, StringComparison.OrdinalIgnoreCase))
                     if (!string.Equals(newUrl, urlString, StringComparison.OrdinalIgnoreCase))
                     {
                     {
-                        await Write(httpRes,
+                        await httpRes.WriteAsync(
                             "<!doctype html><html><head><title>Emby</title></head><body>Please update your Emby bookmark to <a href=\"" +
                             "<!doctype html><html><head><title>Emby</title></head><body>Please update your Emby bookmark to <a href=\"" +
-                            newUrl + "\">" + newUrl + "</a></body></html>").ConfigureAwait(false);
+                            newUrl + "\">" + newUrl + "</a></body></html>",
+                            cancellationToken).ConfigureAwait(false);
                         return;
                         return;
                     }
                     }
                 }
                 }
 
 
                 if (string.Equals(localPath, "/web", StringComparison.OrdinalIgnoreCase))
                 if (string.Equals(localPath, "/web", StringComparison.OrdinalIgnoreCase))
                 {
                 {
-                    RedirectToUrl(httpRes, DefaultRedirectPath);
+                    httpRes.Redirect(_defaultRedirectPath);
                     return;
                     return;
                 }
                 }
 
 
                 if (string.Equals(localPath, "/web/", StringComparison.OrdinalIgnoreCase))
                 if (string.Equals(localPath, "/web/", StringComparison.OrdinalIgnoreCase))
                 {
                 {
-                    RedirectToUrl(httpRes, "../" + DefaultRedirectPath);
+                    httpRes.Redirect("../" + _defaultRedirectPath);
                     return;
                     return;
                 }
                 }
 
 
                 if (string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase))
                 if (string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase))
                 {
                 {
-                    RedirectToUrl(httpRes, DefaultRedirectPath);
+                    httpRes.Redirect(_defaultRedirectPath);
                     return;
                     return;
                 }
                 }
 
 
                 if (string.IsNullOrEmpty(localPath))
                 if (string.IsNullOrEmpty(localPath))
                 {
                 {
-                    RedirectToUrl(httpRes, "/" + DefaultRedirectPath);
+                    httpRes.Redirect("/" + _defaultRedirectPath);
                     return;
                     return;
                 }
                 }
 
 
@@ -546,12 +547,12 @@ namespace Emby.Server.Implementations.HttpServer
                 {
                 {
                     if (localPath.EndsWith("web/dashboard.html", StringComparison.OrdinalIgnoreCase))
                     if (localPath.EndsWith("web/dashboard.html", StringComparison.OrdinalIgnoreCase))
                     {
                     {
-                        RedirectToUrl(httpRes, "index.html#!/dashboard.html");
+                        httpRes.Redirect("index.html#!/dashboard.html");
                     }
                     }
 
 
                     if (localPath.EndsWith("web/home.html", StringComparison.OrdinalIgnoreCase))
                     if (localPath.EndsWith("web/home.html", StringComparison.OrdinalIgnoreCase))
                     {
                     {
-                        RedirectToUrl(httpRes, "index.html");
+                        httpRes.Redirect("index.html");
                     }
                     }
                 }
                 }
 
 
@@ -562,7 +563,7 @@ namespace Emby.Server.Implementations.HttpServer
                     {
                     {
                         httpRes.StatusCode = 503;
                         httpRes.StatusCode = 503;
                         httpRes.ContentType = "text/html";
                         httpRes.ContentType = "text/html";
-                        await Write(httpRes, GlobalResponse).ConfigureAwait(false);
+                        await httpRes.WriteAsync(GlobalResponse, cancellationToken).ConfigureAwait(false);
                         return;
                         return;
                     }
                     }
                 }
                 }
@@ -571,7 +572,7 @@ namespace Emby.Server.Implementations.HttpServer
 
 
                 if (handler != null)
                 if (handler != null)
                 {
                 {
-                    await handler.ProcessRequestAsync(this, httpReq, httpRes, Logger, cancellationToken).ConfigureAwait(false);
+                    await handler.ProcessRequestAsync(this, httpReq, httpRes, _logger, cancellationToken).ConfigureAwait(false);
                 }
                 }
                 else
                 else
                 {
                 {
@@ -598,11 +599,7 @@ namespace Emby.Server.Implementations.HttpServer
                 var elapsed = stopWatch.Elapsed;
                 var elapsed = stopWatch.Elapsed;
                 if (elapsed.TotalMilliseconds > 500)
                 if (elapsed.TotalMilliseconds > 500)
                 {
                 {
-                    Logger.LogWarning("HTTP Response {StatusCode} to {RemoteIp}. Time (slow): {Elapsed:g}. {Url}", httpRes.StatusCode, remoteIp, elapsed, urlToLog);
-                }
-                else
-                {
-                    Logger.LogDebug("HTTP Response {StatusCode} to {RemoteIp}. Time: {Elapsed:g}. {Url}", httpRes.StatusCode, remoteIp, elapsed, urlToLog);
+                    _logger.LogWarning("HTTP Response {StatusCode} to {RemoteIp}. Time (slow): {Elapsed:g}. {Url}", httpRes.StatusCode, remoteIp, elapsed, urlToLog);
                 }
                 }
             }
             }
         }
         }
@@ -619,18 +616,11 @@ namespace Emby.Server.Implementations.HttpServer
                 return new ServiceHandler(restPath, contentType);
                 return new ServiceHandler(restPath, contentType);
             }
             }
 
 
-            Logger.LogError("Could not find handler for {PathInfo}", pathInfo);
+            _logger.LogError("Could not find handler for {PathInfo}", pathInfo);
             return null;
             return null;
         }
         }
 
 
-        private static Task Write(IResponse response, string text)
-        {
-            var bOutput = Encoding.UTF8.GetBytes(text);
-            response.OriginalResponse.ContentLength = bOutput.Length;
-            return response.OutputStream.WriteAsync(bOutput, 0, bOutput.Length);
-        }
-
-        private void RedirectToSecureUrl(IHttpRequest httpReq, IResponse httpRes, string url)
+        private void RedirectToSecureUrl(IHttpRequest httpReq, HttpResponse httpRes, string url)
         {
         {
             if (Uri.TryCreate(url, UriKind.Absolute, out Uri uri))
             if (Uri.TryCreate(url, UriKind.Absolute, out Uri uri))
             {
             {
@@ -640,23 +630,11 @@ namespace Emby.Server.Implementations.HttpServer
                     Scheme = "https"
                     Scheme = "https"
                 };
                 };
                 url = builder.Uri.ToString();
                 url = builder.Uri.ToString();
-
-                RedirectToUrl(httpRes, url);
-            }
-            else
-            {
-                RedirectToUrl(httpRes, url);
             }
             }
-        }
 
 
-        public static void RedirectToUrl(IResponse httpRes, string url)
-        {
-            httpRes.StatusCode = 302;
-            httpRes.AddHeader("Location", url);
+            httpRes.Redirect(url);
         }
         }
 
 
-        public ServiceController ServiceController { get; private set; }
-
         /// <summary>
         /// <summary>
         /// Adds the rest handlers.
         /// Adds the rest handlers.
         /// </summary>
         /// </summary>
@@ -672,9 +650,9 @@ namespace Emby.Server.Implementations.HttpServer
             var types = services.Select(r => r.GetType());
             var types = services.Select(r => r.GetType());
             ServiceController.Init(this, types);
             ServiceController.Init(this, types);
 
 
-            ResponseFilters = new Action<IRequest, IResponse, object>[]
+            ResponseFilters = new Action<IRequest, HttpResponse, object>[]
             {
             {
-                new ResponseFilter(Logger).FilterResponse
+                new ResponseFilter(_logger).FilterResponse
             };
             };
         }
         }
 
 
@@ -772,24 +750,23 @@ namespace Emby.Server.Implementations.HttpServer
             return "emby/emby/" + path;
             return "emby/emby/" + path;
         }
         }
 
 
-        private bool _disposed;
-        private readonly object _disposeLock = new object();
+        /// <inheritdoc />
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
 
 
         protected virtual void Dispose(bool disposing)
         protected virtual void Dispose(bool disposing)
         {
         {
             if (_disposed) return;
             if (_disposed) return;
 
 
-            lock (_disposeLock)
+            if (disposing)
             {
             {
-                if (_disposed) return;
-
-                _disposed = true;
-
-                if (disposing)
-                {
-                    Stop();
-                }
+                Stop();
             }
             }
+
+            _disposed = true;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -803,7 +780,7 @@ namespace Emby.Server.Implementations.HttpServer
                 return Task.CompletedTask;
                 return Task.CompletedTask;
             }
             }
 
 
-            Logger.LogDebug("Websocket message received: {0}", result.MessageType);
+            _logger.LogDebug("Websocket message received: {0}", result.MessageType);
 
 
             IEnumerable<Task> GetTasks()
             IEnumerable<Task> GetTasks()
             {
             {
@@ -815,10 +792,5 @@ namespace Emby.Server.Implementations.HttpServer
 
 
             return Task.WhenAll(GetTasks());
             return Task.WhenAll(GetTasks());
         }
         }
-
-        public void Dispose()
-        {
-            Dispose(true);
-        }
     }
     }
 }
 }

+ 15 - 11
Emby.Server.Implementations/HttpServer/ResponseFilter.cs

@@ -2,6 +2,7 @@ using System;
 using System.Globalization;
 using System.Globalization;
 using System.Text;
 using System.Text;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.Services;
+using Microsoft.AspNetCore.Http;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
 using Microsoft.Net.Http.Headers;
 using Microsoft.Net.Http.Headers;
 
 
@@ -9,7 +10,7 @@ namespace Emby.Server.Implementations.HttpServer
 {
 {
     public class ResponseFilter
     public class ResponseFilter
     {
     {
-        private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
+        private static readonly CultureInfo _usCulture = CultureInfo.ReadOnly(new CultureInfo("en-US"));
         private readonly ILogger _logger;
         private readonly ILogger _logger;
 
 
         public ResponseFilter(ILogger logger)
         public ResponseFilter(ILogger logger)
@@ -23,12 +24,12 @@ namespace Emby.Server.Implementations.HttpServer
         /// <param name="req">The req.</param>
         /// <param name="req">The req.</param>
         /// <param name="res">The res.</param>
         /// <param name="res">The res.</param>
         /// <param name="dto">The dto.</param>
         /// <param name="dto">The dto.</param>
-        public void FilterResponse(IRequest req, IResponse res, object dto)
+        public void FilterResponse(IRequest req, HttpResponse res, object dto)
         {
         {
             // Try to prevent compatibility view
             // Try to prevent compatibility view
-            res.AddHeader("Access-Control-Allow-Headers", "Accept, Accept-Language, Authorization, Cache-Control, Content-Disposition, Content-Encoding, Content-Language, Content-Length, Content-MD5, Content-Range, Content-Type, Date, Host, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, Origin, OriginToken, Pragma, Range, Slug, Transfer-Encoding, Want-Digest, X-MediaBrowser-Token, X-Emby-Authorization");
-            res.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
-            res.AddHeader("Access-Control-Allow-Origin", "*");
+            res.Headers.Add("Access-Control-Allow-Headers", "Accept, Accept-Language, Authorization, Cache-Control, Content-Disposition, Content-Encoding, Content-Language, Content-Length, Content-MD5, Content-Range, Content-Type, Date, Host, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, Origin, OriginToken, Pragma, Range, Slug, Transfer-Encoding, Want-Digest, X-MediaBrowser-Token, X-Emby-Authorization");
+            res.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
+            res.Headers.Add("Access-Control-Allow-Origin", "*");
 
 
             if (dto is Exception exception)
             if (dto is Exception exception)
             {
             {
@@ -39,7 +40,7 @@ namespace Emby.Server.Implementations.HttpServer
                     var error = exception.Message.Replace(Environment.NewLine, " ");
                     var error = exception.Message.Replace(Environment.NewLine, " ");
                     error = RemoveControlCharacters(error);
                     error = RemoveControlCharacters(error);
 
 
-                    res.AddHeader("X-Application-Error-Code", error);
+                    res.Headers.Add("X-Application-Error-Code", error);
                 }
                 }
             }
             }
 
 
@@ -54,12 +55,11 @@ namespace Emby.Server.Implementations.HttpServer
                 if (hasHeaders.Headers.TryGetValue(HeaderNames.ContentLength, out string contentLength)
                 if (hasHeaders.Headers.TryGetValue(HeaderNames.ContentLength, out string contentLength)
                     && !string.IsNullOrEmpty(contentLength))
                     && !string.IsNullOrEmpty(contentLength))
                 {
                 {
-                    var length = long.Parse(contentLength, UsCulture);
+                    var length = long.Parse(contentLength, _usCulture);
 
 
                     if (length > 0)
                     if (length > 0)
                     {
                     {
-                        res.OriginalResponse.ContentLength = length;
-                        res.SendChunked = false;
+                        res.ContentLength = length;
                     }
                     }
                 }
                 }
             }
             }
@@ -72,9 +72,12 @@ namespace Emby.Server.Implementations.HttpServer
         /// <returns>System.String.</returns>
         /// <returns>System.String.</returns>
         public static string RemoveControlCharacters(string inString)
         public static string RemoveControlCharacters(string inString)
         {
         {
-            if (inString == null) return null;
+            if (inString == null)
+            {
+                return null;
+            }
 
 
-            var newString = new StringBuilder();
+            var newString = new StringBuilder(inString.Length);
 
 
             foreach (var ch in inString)
             foreach (var ch in inString)
             {
             {
@@ -83,6 +86,7 @@ namespace Emby.Server.Implementations.HttpServer
                     newString.Append(ch);
                     newString.Append(ch);
                 }
                 }
             }
             }
+
             return newString.ToString();
             return newString.ToString();
         }
         }
     }
     }

+ 23 - 25
Emby.Server.Implementations/HttpServer/Security/AuthService.cs

@@ -3,7 +3,6 @@ using System.Linq;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Security;
 using MediaBrowser.Controller.Security;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Controller.Session;
@@ -13,28 +12,23 @@ namespace Emby.Server.Implementations.HttpServer.Security
 {
 {
     public class AuthService : IAuthService
     public class AuthService : IAuthService
     {
     {
+        private readonly IAuthorizationContext _authorizationContext;
+        private readonly ISessionManager _sessionManager;
         private readonly IServerConfigurationManager _config;
         private readonly IServerConfigurationManager _config;
+        private readonly INetworkManager _networkManager;
 
 
-        public AuthService(IUserManager userManager, IAuthorizationContext authorizationContext, IServerConfigurationManager config, ISessionManager sessionManager, INetworkManager networkManager)
+        public AuthService(
+            IAuthorizationContext authorizationContext,
+            IServerConfigurationManager config,
+            ISessionManager sessionManager,
+            INetworkManager networkManager)
         {
         {
-            AuthorizationContext = authorizationContext;
+            _authorizationContext = authorizationContext;
             _config = config;
             _config = config;
-            SessionManager = sessionManager;
-            UserManager = userManager;
-            NetworkManager = networkManager;
+            _sessionManager = sessionManager;
+            _networkManager = networkManager;
         }
         }
 
 
-        public IUserManager UserManager { get; private set; }
-        public IAuthorizationContext AuthorizationContext { get; private set; }
-        public ISessionManager SessionManager { get; private set; }
-        public INetworkManager NetworkManager { get; private set; }
-
-        /// <summary>
-        /// Redirect the client to a specific URL if authentication failed.
-        /// If this property is null, simply `401 Unauthorized` is returned.
-        /// </summary>
-        public string HtmlRedirect { get; set; }
-
         public void Authenticate(IRequest request, IAuthenticationAttributes authAttribtues)
         public void Authenticate(IRequest request, IAuthenticationAttributes authAttribtues)
         {
         {
             ValidateUser(request, authAttribtues);
             ValidateUser(request, authAttribtues);
@@ -43,7 +37,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
         private void ValidateUser(IRequest request, IAuthenticationAttributes authAttribtues)
         private void ValidateUser(IRequest request, IAuthenticationAttributes authAttribtues)
         {
         {
             // This code is executed before the service
             // This code is executed before the service
-            var auth = AuthorizationContext.GetAuthorizationInfo(request);
+            var auth = _authorizationContext.GetAuthorizationInfo(request);
 
 
             if (!IsExemptFromAuthenticationToken(authAttribtues, request))
             if (!IsExemptFromAuthenticationToken(authAttribtues, request))
             {
             {
@@ -80,7 +74,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
                 !string.IsNullOrEmpty(auth.Client) &&
                 !string.IsNullOrEmpty(auth.Client) &&
                 !string.IsNullOrEmpty(auth.Device))
                 !string.IsNullOrEmpty(auth.Device))
             {
             {
-                SessionManager.LogSessionActivity(auth.Client,
+                _sessionManager.LogSessionActivity(auth.Client,
                     auth.Version,
                     auth.Version,
                     auth.DeviceId,
                     auth.DeviceId,
                     auth.Device,
                     auth.Device,
@@ -89,7 +83,9 @@ namespace Emby.Server.Implementations.HttpServer.Security
             }
             }
         }
         }
 
 
-        private void ValidateUserAccess(User user, IRequest request,
+        private void ValidateUserAccess(
+            User user,
+            IRequest request,
             IAuthenticationAttributes authAttribtues,
             IAuthenticationAttributes authAttribtues,
             AuthorizationInfo auth)
             AuthorizationInfo auth)
         {
         {
@@ -101,7 +97,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
                 };
                 };
             }
             }
 
 
-            if (!user.Policy.EnableRemoteAccess && !NetworkManager.IsInLocalNetwork(request.RemoteIp))
+            if (!user.Policy.EnableRemoteAccess && !_networkManager.IsInLocalNetwork(request.RemoteIp))
             {
             {
                 throw new SecurityException("User account has been disabled.")
                 throw new SecurityException("User account has been disabled.")
                 {
                 {
@@ -109,11 +105,11 @@ namespace Emby.Server.Implementations.HttpServer.Security
                 };
                 };
             }
             }
 
 
-            if (!user.Policy.IsAdministrator &&
-                !authAttribtues.EscapeParentalControl &&
-                !user.IsParentalScheduleAllowed())
+            if (!user.Policy.IsAdministrator
+                && !authAttribtues.EscapeParentalControl
+                && !user.IsParentalScheduleAllowed())
             {
             {
-                request.Response.AddHeader("X-Application-Error-Code", "ParentalControl");
+                request.Response.Headers.Add("X-Application-Error-Code", "ParentalControl");
 
 
                 throw new SecurityException("This user account is not allowed access at this time.")
                 throw new SecurityException("This user account is not allowed access at this time.")
                 {
                 {
@@ -183,6 +179,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
                     };
                     };
                 }
                 }
             }
             }
+
             if (roles.Contains("delete", StringComparer.OrdinalIgnoreCase))
             if (roles.Contains("delete", StringComparer.OrdinalIgnoreCase))
             {
             {
                 if (user == null || !user.Policy.EnableContentDeletion)
                 if (user == null || !user.Policy.EnableContentDeletion)
@@ -193,6 +190,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
                     };
                     };
                 }
                 }
             }
             }
+
             if (roles.Contains("download", StringComparer.OrdinalIgnoreCase))
             if (roles.Contains("download", StringComparer.OrdinalIgnoreCase))
             {
             {
                 if (user == null || !user.Policy.EnableContentDownloading)
                 if (user == null || !user.Policy.EnableContentDownloading)

+ 5 - 4
Emby.Server.Implementations/Services/HttpResult.cs

@@ -10,8 +10,6 @@ namespace Emby.Server.Implementations.Services
     public class HttpResult
     public class HttpResult
         : IHttpResult, IAsyncStreamWriter
         : IHttpResult, IAsyncStreamWriter
     {
     {
-        public object Response { get; set; }
-
         public HttpResult(object response, string contentType, HttpStatusCode statusCode)
         public HttpResult(object response, string contentType, HttpStatusCode statusCode)
         {
         {
             this.Headers = new Dictionary<string, string>();
             this.Headers = new Dictionary<string, string>();
@@ -21,6 +19,8 @@ namespace Emby.Server.Implementations.Services
             this.StatusCode = statusCode;
             this.StatusCode = statusCode;
         }
         }
 
 
+        public object Response { get; set; }
+
         public string ContentType { get; set; }
         public string ContentType { get; set; }
 
 
         public IDictionary<string, string> Headers { get; private set; }
         public IDictionary<string, string> Headers { get; private set; }
@@ -37,7 +37,7 @@ namespace Emby.Server.Implementations.Services
 
 
         public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken)
         public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken)
         {
         {
-            var response = RequestContext == null ? null : RequestContext.Response;
+            var response = RequestContext?.Response;
 
 
             if (this.Response is byte[] bytesResponse)
             if (this.Response is byte[] bytesResponse)
             {
             {
@@ -45,13 +45,14 @@ namespace Emby.Server.Implementations.Services
 
 
                 if (response != null)
                 if (response != null)
                 {
                 {
-                    response.OriginalResponse.ContentLength = contentLength;
+                    response.ContentLength = contentLength;
                 }
                 }
 
 
                 if (contentLength > 0)
                 if (contentLength > 0)
                 {
                 {
                     await responseStream.WriteAsync(bytesResponse, 0, contentLength, cancellationToken).ConfigureAwait(false);
                     await responseStream.WriteAsync(bytesResponse, 0, contentLength, cancellationToken).ConfigureAwait(false);
                 }
                 }
+
                 return;
                 return;
             }
             }
 
 

+ 15 - 16
Emby.Server.Implementations/Services/ResponseHelper.cs

@@ -1,5 +1,4 @@
 using System;
 using System;
-using System.Collections.Generic;
 using System.Globalization;
 using System.Globalization;
 using System.IO;
 using System.IO;
 using System.Net;
 using System.Net;
@@ -7,13 +6,14 @@ using System.Text;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Emby.Server.Implementations.HttpServer;
 using Emby.Server.Implementations.HttpServer;
+using Microsoft.AspNetCore.Http;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.Services;
 
 
 namespace Emby.Server.Implementations.Services
 namespace Emby.Server.Implementations.Services
 {
 {
     public static class ResponseHelper
     public static class ResponseHelper
     {
     {
-        public static Task WriteToResponse(IResponse response, IRequest request, object result, CancellationToken cancellationToken)
+        public static Task WriteToResponse(HttpResponse response, IRequest request, object result, CancellationToken cancellationToken)
         {
         {
             if (result == null)
             if (result == null)
             {
             {
@@ -22,7 +22,7 @@ namespace Emby.Server.Implementations.Services
                     response.StatusCode = (int)HttpStatusCode.NoContent;
                     response.StatusCode = (int)HttpStatusCode.NoContent;
                 }
                 }
 
 
-                response.OriginalResponse.ContentLength = 0;
+                response.ContentLength = 0;
                 return Task.CompletedTask;
                 return Task.CompletedTask;
             }
             }
 
 
@@ -41,7 +41,6 @@ namespace Emby.Server.Implementations.Services
                     httpResult.RequestContext = request;
                     httpResult.RequestContext = request;
 
 
                 response.StatusCode = httpResult.Status;
                 response.StatusCode = httpResult.Status;
-                response.StatusDescription = httpResult.StatusCode.ToString();
             }
             }
 
 
             var responseOptions = result as IHasHeaders;
             var responseOptions = result as IHasHeaders;
@@ -51,11 +50,11 @@ namespace Emby.Server.Implementations.Services
                 {
                 {
                     if (string.Equals(responseHeaders.Key, "Content-Length", StringComparison.OrdinalIgnoreCase))
                     if (string.Equals(responseHeaders.Key, "Content-Length", StringComparison.OrdinalIgnoreCase))
                     {
                     {
-                        response.OriginalResponse.ContentLength = long.Parse(responseHeaders.Value, CultureInfo.InvariantCulture);
+                        response.ContentLength = long.Parse(responseHeaders.Value, CultureInfo.InvariantCulture);
                         continue;
                         continue;
                     }
                     }
 
 
-                    response.AddHeader(responseHeaders.Key, responseHeaders.Value);
+                    response.Headers.Add(responseHeaders.Key, responseHeaders.Value);
                 }
                 }
             }
             }
 
 
@@ -74,31 +73,31 @@ namespace Emby.Server.Implementations.Services
             switch (result)
             switch (result)
             {
             {
                 case IAsyncStreamWriter asyncStreamWriter:
                 case IAsyncStreamWriter asyncStreamWriter:
-                    return asyncStreamWriter.WriteToAsync(response.OutputStream, cancellationToken);
+                    return asyncStreamWriter.WriteToAsync(response.Body, cancellationToken);
                 case IStreamWriter streamWriter:
                 case IStreamWriter streamWriter:
-                    streamWriter.WriteTo(response.OutputStream);
+                    streamWriter.WriteTo(response.Body);
                     return Task.CompletedTask;
                     return Task.CompletedTask;
                 case FileWriter fileWriter:
                 case FileWriter fileWriter:
                     return fileWriter.WriteToAsync(response, cancellationToken);
                     return fileWriter.WriteToAsync(response, cancellationToken);
                 case Stream stream:
                 case Stream stream:
-                    return CopyStream(stream, response.OutputStream);
+                    return CopyStream(stream, response.Body);
                 case byte[] bytes:
                 case byte[] bytes:
                     response.ContentType = "application/octet-stream";
                     response.ContentType = "application/octet-stream";
-                    response.OriginalResponse.ContentLength = bytes.Length;
+                    response.ContentLength = bytes.Length;
 
 
                     if (bytes.Length > 0)
                     if (bytes.Length > 0)
                     {
                     {
-                        return response.OutputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
+                        return response.Body.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
                     }
                     }
 
 
                     return Task.CompletedTask;
                     return Task.CompletedTask;
                 case string responseText:
                 case string responseText:
                     var responseTextAsBytes = Encoding.UTF8.GetBytes(responseText);
                     var responseTextAsBytes = Encoding.UTF8.GetBytes(responseText);
-                    response.OriginalResponse.ContentLength = responseTextAsBytes.Length;
+                    response.ContentLength = responseTextAsBytes.Length;
 
 
                     if (responseTextAsBytes.Length > 0)
                     if (responseTextAsBytes.Length > 0)
                     {
                     {
-                        return response.OutputStream.WriteAsync(responseTextAsBytes, 0, responseTextAsBytes.Length, cancellationToken);
+                        return response.Body.WriteAsync(responseTextAsBytes, 0, responseTextAsBytes.Length, cancellationToken);
                     }
                     }
 
 
                     return Task.CompletedTask;
                     return Task.CompletedTask;
@@ -115,7 +114,7 @@ namespace Emby.Server.Implementations.Services
             }
             }
         }
         }
 
 
-        public static async Task WriteObject(IRequest request, object result, IResponse response)
+        public static async Task WriteObject(IRequest request, object result, HttpResponse response)
         {
         {
             var contentType = request.ResponseContentType;
             var contentType = request.ResponseContentType;
             var serializer = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType);
             var serializer = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType);
@@ -127,11 +126,11 @@ namespace Emby.Server.Implementations.Services
                 ms.Position = 0;
                 ms.Position = 0;
 
 
                 var contentLength = ms.Length;
                 var contentLength = ms.Length;
-                response.OriginalResponse.ContentLength = contentLength;
+                response.ContentLength = contentLength;
 
 
                 if (contentLength > 0)
                 if (contentLength > 0)
                 {
                 {
-                    await ms.CopyToAsync(response.OutputStream).ConfigureAwait(false);
+                    await ms.CopyToAsync(response.Body).ConfigureAwait(false);
                 }
                 }
             }
             }
         }
         }

+ 0 - 4
Emby.Server.Implementations/Services/ServiceController.cs

@@ -147,7 +147,6 @@ namespace Emby.Server.Implementations.Services
 
 
         public Task<object> Execute(HttpListenerHost httpHost, object requestDto, IRequest req)
         public Task<object> Execute(HttpListenerHost httpHost, object requestDto, IRequest req)
         {
         {
-            req.Dto = requestDto;
             var requestType = requestDto.GetType();
             var requestType = requestDto.GetType();
             req.OperationName = requestType.Name;
             req.OperationName = requestType.Name;
 
 
@@ -161,9 +160,6 @@ namespace Emby.Server.Implementations.Services
                 serviceRequiresContext.Request = req;
                 serviceRequiresContext.Request = req;
             }
             }
 
 
-            if (req.Dto == null) // Don't override existing batched DTO[]
-                req.Dto = requestDto;
-
             //Executes the service and returns the result
             //Executes the service and returns the result
             return ServiceExecGeneral.Execute(serviceType, req, service, requestDto, requestType.GetMethodName());
             return ServiceExecGeneral.Execute(serviceType, req, service, requestDto, requestType.GetMethodName());
         }
         }

+ 1 - 1
Emby.Server.Implementations/Services/ServiceExec.cs

@@ -78,7 +78,7 @@ namespace Emby.Server.Implementations.Services
                     foreach (var requestFilter in actionContext.RequestFilters)
                     foreach (var requestFilter in actionContext.RequestFilters)
                     {
                     {
                         requestFilter.RequestFilter(request, request.Response, requestDto);
                         requestFilter.RequestFilter(request, request.Response, requestDto);
-                        if (request.Response.OriginalResponse.HasStarted)
+                        if (request.Response.HasStarted)
                         {
                         {
                             Task.FromResult<object>(null);
                             Task.FromResult<object>(null);
                         }
                         }

+ 38 - 65
Emby.Server.Implementations/Services/ServiceHandler.cs

@@ -5,20 +5,21 @@ using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Emby.Server.Implementations.HttpServer;
 using Emby.Server.Implementations.HttpServer;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.Services;
+using Microsoft.AspNetCore.Http;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
 
 
 namespace Emby.Server.Implementations.Services
 namespace Emby.Server.Implementations.Services
 {
 {
     public class ServiceHandler
     public class ServiceHandler
     {
     {
-        public RestPath RestPath { get; }
+        private RestPath _restPath;
 
 
-        public string ResponseContentType { get; }
+        private string _responseContentType;
 
 
         internal ServiceHandler(RestPath restPath, string responseContentType)
         internal ServiceHandler(RestPath restPath, string responseContentType)
         {
         {
-            RestPath = restPath;
-            ResponseContentType = responseContentType;
+            _restPath = restPath;
+            _responseContentType = responseContentType;
         }
         }
 
 
         protected static Task<object> CreateContentTypeRequest(HttpListenerHost host, IRequest httpReq, Type requestType, string contentType)
         protected static Task<object> CreateContentTypeRequest(HttpListenerHost host, IRequest httpReq, Type requestType, string contentType)
@@ -54,7 +55,7 @@ namespace Emby.Server.Implementations.Services
 
 
         private static string GetFormatContentType(string format)
         private static string GetFormatContentType(string format)
         {
         {
-            //built-in formats
+            // built-in formats
             switch (format)
             switch (format)
             {
             {
                 case "json": return "application/json";
                 case "json": return "application/json";
@@ -63,16 +64,16 @@ namespace Emby.Server.Implementations.Services
             }
             }
         }
         }
 
 
-        public async Task ProcessRequestAsync(HttpListenerHost httpHost, IRequest httpReq, IResponse httpRes, ILogger logger, CancellationToken cancellationToken)
+        public async Task ProcessRequestAsync(HttpListenerHost httpHost, IRequest httpReq, HttpResponse httpRes, ILogger logger, CancellationToken cancellationToken)
         {
         {
-            httpReq.Items["__route"] = RestPath;
+            httpReq.Items["__route"] = _restPath;
 
 
-            if (ResponseContentType != null)
+            if (_responseContentType != null)
             {
             {
-                httpReq.ResponseContentType = ResponseContentType;
+                httpReq.ResponseContentType = _responseContentType;
             }
             }
 
 
-            var request = httpReq.Dto = await CreateRequest(httpHost, httpReq, RestPath, logger).ConfigureAwait(false);
+            var request = await CreateRequest(httpHost, httpReq, _restPath, logger).ConfigureAwait(false);
 
 
             httpHost.ApplyRequestFilters(httpReq, httpRes, request);
             httpHost.ApplyRequestFilters(httpReq, httpRes, request);
 
 
@@ -94,7 +95,7 @@ namespace Emby.Server.Implementations.Services
             if (RequireqRequestStream(requestType))
             if (RequireqRequestStream(requestType))
             {
             {
                 // Used by IRequiresRequestStream
                 // Used by IRequiresRequestStream
-                var requestParams = await GetRequestParams(httpReq).ConfigureAwait(false);
+                var requestParams = GetRequestParams(httpReq.Response.HttpContext.Request);
                 var request = ServiceHandler.CreateRequest(httpReq, restPath, requestParams, host.CreateInstance(requestType));
                 var request = ServiceHandler.CreateRequest(httpReq, restPath, requestParams, host.CreateInstance(requestType));
 
 
                 var rawReq = (IRequiresRequestStream)request;
                 var rawReq = (IRequiresRequestStream)request;
@@ -103,7 +104,7 @@ namespace Emby.Server.Implementations.Services
             }
             }
             else
             else
             {
             {
-                var requestParams = await GetFlattenedRequestParams(httpReq).ConfigureAwait(false);
+                var requestParams = GetFlattenedRequestParams(httpReq.Response.HttpContext.Request);
 
 
                 var requestDto = await CreateContentTypeRequest(host, httpReq, restPath.RequestType, httpReq.ContentType).ConfigureAwait(false);
                 var requestDto = await CreateContentTypeRequest(host, httpReq, restPath.RequestType, httpReq.ContentType).ConfigureAwait(false);
 
 
@@ -130,56 +131,42 @@ namespace Emby.Server.Implementations.Services
         /// <summary>
         /// <summary>
         /// Duplicate Params are given a unique key by appending a #1 suffix
         /// Duplicate Params are given a unique key by appending a #1 suffix
         /// </summary>
         /// </summary>
-        private static async Task<Dictionary<string, string>> GetRequestParams(IRequest request)
+        private static Dictionary<string, string> GetRequestParams(HttpRequest request)
         {
         {
             var map = new Dictionary<string, string>();
             var map = new Dictionary<string, string>();
 
 
-            foreach (var name in request.QueryString.Keys)
+            foreach (var pair in request.Query)
             {
             {
-                if (name == null)
-                {
-                    // thank you ASP.NET
-                    continue;
-                }
-
-                var values = request.QueryString[name];
+                var values = pair.Value;
                 if (values.Count == 1)
                 if (values.Count == 1)
                 {
                 {
-                    map[name] = values[0];
+                    map[pair.Key] = values[0];
                 }
                 }
                 else
                 else
                 {
                 {
                     for (var i = 0; i < values.Count; i++)
                     for (var i = 0; i < values.Count; i++)
                     {
                     {
-                        map[name + (i == 0 ? "" : "#" + i)] = values[i];
+                        map[pair.Key + (i == 0 ? "" : "#" + i)] = values[i];
                     }
                     }
                 }
                 }
             }
             }
 
 
-            if ((IsMethod(request.Verb, "POST") || IsMethod(request.Verb, "PUT")))
+            if (
+                (IsMethod(request.Method, "POST") || IsMethod(request.Method, "PUT"))
+                && request.HasFormContentType)
             {
             {
-                var formData = await request.GetFormData().ConfigureAwait(false);
-                if (formData != null)
+                foreach (var pair in request.Form)
                 {
                 {
-                    foreach (var name in formData.Keys)
+                    var values = pair.Value;
+                    if (values.Count == 1)
                     {
                     {
-                        if (name == null)
-                        {
-                            // thank you ASP.NET
-                            continue;
-                        }
-
-                        var values = formData.GetValues(name);
-                        if (values.Count == 1)
-                        {
-                            map[name] = values[0];
-                        }
-                        else
+                        map[pair.Key] = values[0];
+                    }
+                    else
+                    {
+                        for (var i = 0; i < values.Count; i++)
                         {
                         {
-                            for (var i = 0; i < values.Count; i++)
-                            {
-                                map[name + (i == 0 ? "" : "#" + i)] = values[i];
-                            }
+                            map[pair.Key + (i == 0 ? "" : "#" + i)] = values[i];
                         }
                         }
                     }
                     }
                 }
                 }
@@ -196,36 +183,22 @@ namespace Emby.Server.Implementations.Services
         /// <summary>
         /// <summary>
         /// Duplicate params have their values joined together in a comma-delimited string
         /// Duplicate params have their values joined together in a comma-delimited string
         /// </summary>
         /// </summary>
-        private static async Task<Dictionary<string, string>> GetFlattenedRequestParams(IRequest request)
+        private static Dictionary<string, string> GetFlattenedRequestParams(HttpRequest request)
         {
         {
             var map = new Dictionary<string, string>();
             var map = new Dictionary<string, string>();
 
 
-            foreach (var name in request.QueryString.Keys)
+            foreach (var pair in request.Query)
             {
             {
-                if (name == null)
-                {
-                    // thank you ASP.NET
-                    continue;
-                }
-
-                map[name] = request.QueryString[name];
+                map[pair.Key] = pair.Value;
             }
             }
 
 
-            if ((IsMethod(request.Verb, "POST") || IsMethod(request.Verb, "PUT")))
+            if (
+                (IsMethod(request.Method, "POST") || IsMethod(request.Method, "PUT"))
+                && request.HasFormContentType)
             {
             {
-                var formData = await request.GetFormData().ConfigureAwait(false);
-                if (formData != null)
+                foreach (var pair in request.Form)
                 {
                 {
-                    foreach (var name in formData.Keys)
-                    {
-                        if (name == null)
-                        {
-                            // thank you ASP.NET
-                            continue;
-                        }
-
-                        map[name] = formData[name];
-                    }
+                    map[pair.Key] = pair.Value;
                 }
                 }
             }
             }
 
 

+ 0 - 647
Emby.Server.Implementations/SocketSharp/RequestMono.cs

@@ -1,647 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Net;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Services;
-using Microsoft.Extensions.Primitives;
-using Microsoft.Net.Http.Headers;
-
-namespace Emby.Server.Implementations.SocketSharp
-{
-    public partial class WebSocketSharpRequest : IHttpRequest
-    {
-        internal static string GetParameter(ReadOnlySpan<char> header, string attr)
-        {
-            int ap = header.IndexOf(attr.AsSpan(), StringComparison.Ordinal);
-            if (ap == -1)
-            {
-                return null;
-            }
-
-            ap += attr.Length;
-            if (ap >= header.Length)
-            {
-                return null;
-            }
-
-            char ending = header[ap];
-            if (ending != '"')
-            {
-                ending = ' ';
-            }
-
-            var slice = header.Slice(ap + 1);
-            int end = slice.IndexOf(ending);
-            if (end == -1)
-            {
-                return ending == '"' ? null : header.Slice(ap).ToString();
-            }
-
-            return slice.Slice(0, end - ap - 1).ToString();
-        }
-
-        private async Task LoadMultiPart(WebROCollection form)
-        {
-            string boundary = GetParameter(ContentType.AsSpan(), "; boundary=");
-            if (boundary == null)
-            {
-                return;
-            }
-
-            using (var requestStream = InputStream)
-            {
-                // DB: 30/01/11 - Hack to get around non-seekable stream and received HTTP request
-                // Not ending with \r\n?
-                var ms = new MemoryStream(32 * 1024);
-                await requestStream.CopyToAsync(ms).ConfigureAwait(false);
-
-                var input = ms;
-                ms.WriteByte((byte)'\r');
-                ms.WriteByte((byte)'\n');
-
-                input.Position = 0;
-
-                // Uncomment to debug
-                // var content = new StreamReader(ms).ReadToEnd();
-                // Console.WriteLine(boundary + "::" + content);
-                // input.Position = 0;
-
-                var multi_part = new HttpMultipart(input, boundary, ContentEncoding);
-
-                HttpMultipart.Element e;
-                while ((e = multi_part.ReadNextElement()) != null)
-                {
-                    if (e.Filename == null)
-                    {
-                        byte[] copy = new byte[e.Length];
-
-                        input.Position = e.Start;
-                        await input.ReadAsync(copy, 0, (int)e.Length).ConfigureAwait(false);
-
-                        form.Add(e.Name, (e.Encoding ?? ContentEncoding).GetString(copy, 0, copy.Length));
-                    }
-                    else
-                    {
-                        // We use a substream, as in 2.x we will support large uploads streamed to disk,
-                        files[e.Name] = new HttpPostedFile(e.Filename, e.ContentType, input, e.Start, e.Length);
-                    }
-                }
-            }
-        }
-
-        public async Task<QueryParamCollection> GetFormData()
-        {
-            var form = new WebROCollection();
-            files = new Dictionary<string, HttpPostedFile>();
-
-            if (IsContentType("multipart/form-data"))
-            {
-                await LoadMultiPart(form).ConfigureAwait(false);
-            }
-            else if (IsContentType("application/x-www-form-urlencoded"))
-            {
-                await LoadWwwForm(form).ConfigureAwait(false);
-            }
-
-            if (validate_form && !checked_form)
-            {
-                checked_form = true;
-                ValidateNameValueCollection("Form", form);
-            }
-
-            return form;
-        }
-
-        public string Accept => StringValues.IsNullOrEmpty(request.Headers[HeaderNames.Accept]) ? null : request.Headers[HeaderNames.Accept].ToString();
-
-        public string Authorization => StringValues.IsNullOrEmpty(request.Headers[HeaderNames.Authorization]) ? null : request.Headers[HeaderNames.Authorization].ToString();
-
-        protected bool validate_form { get; set; }
-        protected bool checked_form { get; set; }
-
-        private static void ThrowValidationException(string name, string key, string value)
-        {
-            string v = "\"" + value + "\"";
-            if (v.Length > 20)
-            {
-                v = v.Substring(0, 16) + "...\"";
-            }
-
-            string msg = string.Format(
-                CultureInfo.InvariantCulture,
-                "A potentially dangerous Request.{0} value was detected from the client ({1}={2}).",
-                name,
-                key,
-                v);
-
-            throw new Exception(msg);
-        }
-
-        private static void ValidateNameValueCollection(string name, QueryParamCollection coll)
-        {
-            if (coll == null)
-            {
-                return;
-            }
-
-            foreach (var pair in coll)
-            {
-                var key = pair.Name;
-                var val = pair.Value;
-                if (val != null && val.Length > 0 && IsInvalidString(val))
-                {
-                    ThrowValidationException(name, key, val);
-                }
-            }
-        }
-
-        internal static bool IsInvalidString(string val)
-            => IsInvalidString(val, out var validationFailureIndex);
-
-        internal static bool IsInvalidString(string val, out int validationFailureIndex)
-        {
-            validationFailureIndex = 0;
-
-            int len = val.Length;
-            if (len < 2)
-            {
-                return false;
-            }
-
-            char current = val[0];
-            for (int idx = 1; idx < len; idx++)
-            {
-                char next = val[idx];
-
-                // See http://secunia.com/advisories/14325
-                if (current == '<' || current == '\xff1c')
-                {
-                    if (next == '!' || next < ' '
-                        || (next >= 'a' && next <= 'z')
-                        || (next >= 'A' && next <= 'Z'))
-                    {
-                        validationFailureIndex = idx - 1;
-                        return true;
-                    }
-                }
-                else if (current == '&' && next == '#')
-                {
-                    validationFailureIndex = idx - 1;
-                    return true;
-                }
-
-                current = next;
-            }
-
-            return false;
-        }
-
-        private bool IsContentType(string ct)
-        {
-            if (ContentType == null)
-            {
-                return false;
-            }
-
-            return ContentType.StartsWith(ct, StringComparison.OrdinalIgnoreCase);
-        }
-
-        private async Task LoadWwwForm(WebROCollection form)
-        {
-            using (var input = InputStream)
-            {
-                using (var ms = new MemoryStream())
-                {
-                    await input.CopyToAsync(ms).ConfigureAwait(false);
-                    ms.Position = 0;
-
-                    using (var s = new StreamReader(ms, ContentEncoding))
-                    {
-                        var key = new StringBuilder();
-                        var value = new StringBuilder();
-                        int c;
-
-                        while ((c = s.Read()) != -1)
-                        {
-                            if (c == '=')
-                            {
-                                value.Length = 0;
-                                while ((c = s.Read()) != -1)
-                                {
-                                    if (c == '&')
-                                    {
-                                        AddRawKeyValue(form, key, value);
-                                        break;
-                                    }
-                                    else
-                                    {
-                                        value.Append((char)c);
-                                    }
-                                }
-
-                                if (c == -1)
-                                {
-                                    AddRawKeyValue(form, key, value);
-                                    return;
-                                }
-                            }
-                            else if (c == '&')
-                            {
-                                AddRawKeyValue(form, key, value);
-                            }
-                            else
-                            {
-                                key.Append((char)c);
-                            }
-                        }
-
-                        if (c == -1)
-                        {
-                            AddRawKeyValue(form, key, value);
-                        }
-                    }
-                }
-            }
-        }
-
-        private static void AddRawKeyValue(WebROCollection form, StringBuilder key, StringBuilder value)
-        {
-            form.Add(WebUtility.UrlDecode(key.ToString()), WebUtility.UrlDecode(value.ToString()));
-
-            key.Length = 0;
-            value.Length = 0;
-        }
-
-        private Dictionary<string, HttpPostedFile> files;
-
-        private class WebROCollection : QueryParamCollection
-        {
-            public override string ToString()
-            {
-                var result = new StringBuilder();
-                foreach (var pair in this)
-                {
-                    if (result.Length > 0)
-                    {
-                        result.Append('&');
-                    }
-
-                    var key = pair.Name;
-                    if (key != null && key.Length > 0)
-                    {
-                        result.Append(key);
-                        result.Append('=');
-                    }
-
-                    result.Append(pair.Value);
-                }
-
-                return result.ToString();
-            }
-        }
-        private class HttpMultipart
-        {
-
-            public class Element
-            {
-                public string ContentType { get; set; }
-
-                public string Name { get; set; }
-
-                public string Filename { get; set; }
-
-                public Encoding Encoding { get; set; }
-
-                public long Start { get; set; }
-
-                public long Length { get; set; }
-
-                public override string ToString()
-                {
-                    return "ContentType " + ContentType + ", Name " + Name + ", Filename " + Filename + ", Start " +
-                        Start.ToString(CultureInfo.CurrentCulture) + ", Length " + Length.ToString(CultureInfo.CurrentCulture);
-                }
-            }
-
-            private const byte LF = (byte)'\n';
-
-            private const byte CR = (byte)'\r';
-
-            private Stream data;
-
-            private string boundary;
-
-            private byte[] boundaryBytes;
-
-            private byte[] buffer;
-
-            private bool atEof;
-
-            private Encoding encoding;
-
-            private StringBuilder sb;
-
-            // See RFC 2046
-            // In the case of multipart entities, in which one or more different
-            // sets of data are combined in a single body, a "multipart" media type
-            // field must appear in the entity's header.  The body must then contain
-            // one or more body parts, each preceded by a boundary delimiter line,
-            // and the last one followed by a closing boundary delimiter line.
-            // After its boundary delimiter line, each body part then consists of a
-            // header area, a blank line, and a body area.  Thus a body part is
-            // similar to an RFC 822 message in syntax, but different in meaning.
-
-            public HttpMultipart(Stream data, string b, Encoding encoding)
-            {
-                this.data = data;
-                boundary = b;
-                boundaryBytes = encoding.GetBytes(b);
-                buffer = new byte[boundaryBytes.Length + 2]; // CRLF or '--'
-                this.encoding = encoding;
-                sb = new StringBuilder();
-            }
-
-            public Element ReadNextElement()
-            {
-                if (atEof || ReadBoundary())
-                {
-                    return null;
-                }
-
-                var elem = new Element();
-                ReadOnlySpan<char> header;
-                while ((header = ReadLine().AsSpan()).Length != 0)
-                {
-                    if (header.StartsWith("Content-Disposition:".AsSpan(), StringComparison.OrdinalIgnoreCase))
-                    {
-                        elem.Name = GetContentDispositionAttribute(header, "name");
-                        elem.Filename = StripPath(GetContentDispositionAttributeWithEncoding(header, "filename"));
-                    }
-                    else if (header.StartsWith("Content-Type:".AsSpan(), StringComparison.OrdinalIgnoreCase))
-                    {
-                        elem.ContentType = header.Slice("Content-Type:".Length).Trim().ToString();
-                        elem.Encoding = GetEncoding(elem.ContentType);
-                    }
-                }
-
-                long start = data.Position;
-                elem.Start = start;
-                long pos = MoveToNextBoundary();
-                if (pos == -1)
-                {
-                    return null;
-                }
-
-                elem.Length = pos - start;
-                return elem;
-            }
-
-            private string ReadLine()
-            {
-                // CRLF or LF are ok as line endings.
-                bool got_cr = false;
-                int b = 0;
-                sb.Length = 0;
-                while (true)
-                {
-                    b = data.ReadByte();
-                    if (b == -1)
-                    {
-                        return null;
-                    }
-
-                    if (b == LF)
-                    {
-                        break;
-                    }
-
-                    got_cr = b == CR;
-                    sb.Append((char)b);
-                }
-
-                if (got_cr)
-                {
-                    sb.Length--;
-                }
-
-                return sb.ToString();
-            }
-
-            private static string GetContentDispositionAttribute(ReadOnlySpan<char> l, string name)
-            {
-                int idx = l.IndexOf((name + "=\"").AsSpan(), StringComparison.Ordinal);
-                if (idx < 0)
-                {
-                    return null;
-                }
-
-                int begin = idx + name.Length + "=\"".Length;
-                int end = l.Slice(begin).IndexOf('"');
-                if (end < 0)
-                {
-                    return null;
-                }
-
-                if (begin == end)
-                {
-                    return string.Empty;
-                }
-
-                return l.Slice(begin, end - begin).ToString();
-            }
-
-            private string GetContentDispositionAttributeWithEncoding(ReadOnlySpan<char> l, string name)
-            {
-                int idx = l.IndexOf((name + "=\"").AsSpan(), StringComparison.Ordinal);
-                if (idx < 0)
-                {
-                    return null;
-                }
-
-                int begin = idx + name.Length + "=\"".Length;
-                int end = l.Slice(begin).IndexOf('"');
-                if (end < 0)
-                {
-                    return null;
-                }
-
-                if (begin == end)
-                {
-                    return string.Empty;
-                }
-
-                ReadOnlySpan<char> temp = l.Slice(begin, end - begin);
-                byte[] source = new byte[temp.Length];
-                for (int i = temp.Length - 1; i >= 0; i--)
-                {
-                    source[i] = (byte)temp[i];
-                }
-
-                return encoding.GetString(source, 0, source.Length);
-            }
-
-            private bool ReadBoundary()
-            {
-                try
-                {
-                    string line;
-                    do
-                    {
-                        line = ReadLine();
-                    }
-                    while (line.Length == 0);
-
-                    if (line[0] != '-' || line[1] != '-')
-                    {
-                        return false;
-                    }
-
-                    if (!line.EndsWith(boundary, StringComparison.Ordinal))
-                    {
-                        return true;
-                    }
-                }
-                catch
-                {
-
-                }
-
-                return false;
-            }
-
-            private static bool CompareBytes(byte[] orig, byte[] other)
-            {
-                for (int i = orig.Length - 1; i >= 0; i--)
-                {
-                    if (orig[i] != other[i])
-                    {
-                        return false;
-                    }
-                }
-
-                return true;
-            }
-
-            private long MoveToNextBoundary()
-            {
-                long retval = 0;
-                bool got_cr = false;
-
-                int state = 0;
-                int c = data.ReadByte();
-                while (true)
-                {
-                    if (c == -1)
-                    {
-                        return -1;
-                    }
-
-                    if (state == 0 && c == LF)
-                    {
-                        retval = data.Position - 1;
-                        if (got_cr)
-                        {
-                            retval--;
-                        }
-
-                        state = 1;
-                        c = data.ReadByte();
-                    }
-                    else if (state == 0)
-                    {
-                        got_cr = c == CR;
-                        c = data.ReadByte();
-                    }
-                    else if (state == 1 && c == '-')
-                    {
-                        c = data.ReadByte();
-                        if (c == -1)
-                        {
-                            return -1;
-                        }
-
-                        if (c != '-')
-                        {
-                            state = 0;
-                            got_cr = false;
-                            continue; // no ReadByte() here
-                        }
-
-                        int nread = data.Read(buffer, 0, buffer.Length);
-                        int bl = buffer.Length;
-                        if (nread != bl)
-                        {
-                            return -1;
-                        }
-
-                        if (!CompareBytes(boundaryBytes, buffer))
-                        {
-                            state = 0;
-                            data.Position = retval + 2;
-                            if (got_cr)
-                            {
-                                data.Position++;
-                                got_cr = false;
-                            }
-
-                            c = data.ReadByte();
-                            continue;
-                        }
-
-                        if (buffer[bl - 2] == '-' && buffer[bl - 1] == '-')
-                        {
-                            atEof = true;
-                        }
-                        else if (buffer[bl - 2] != CR || buffer[bl - 1] != LF)
-                        {
-                            state = 0;
-                            data.Position = retval + 2;
-                            if (got_cr)
-                            {
-                                data.Position++;
-                                got_cr = false;
-                            }
-
-                            c = data.ReadByte();
-                            continue;
-                        }
-
-                        data.Position = retval + 2;
-                        if (got_cr)
-                        {
-                            data.Position++;
-                        }
-
-                        break;
-                    }
-                    else
-                    {
-                        // state == 1
-                        state = 0; // no ReadByte() here
-                    }
-                }
-
-                return retval;
-            }
-
-            private static string StripPath(string path)
-            {
-                if (path == null || path.Length == 0)
-                {
-                    return path;
-                }
-
-                if (path.IndexOf(":\\", StringComparison.Ordinal) != 1
-                    && !path.StartsWith("\\\\", StringComparison.Ordinal))
-                {
-                    return path;
-                }
-
-                return path.Substring(path.LastIndexOf('\\') + 1);
-            }
-        }
-    }
-}

+ 93 - 137
Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs

@@ -6,7 +6,6 @@ using System.Net;
 using System.Linq;
 using System.Linq;
 using System.Text;
 using System.Text;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
-using MediaBrowser.Model.Services;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Http.Extensions;
 using Microsoft.AspNetCore.Http.Extensions;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
@@ -14,44 +13,49 @@ using Microsoft.Extensions.Primitives;
 using Microsoft.Net.Http.Headers;
 using Microsoft.Net.Http.Headers;
 using IHttpFile = MediaBrowser.Model.Services.IHttpFile;
 using IHttpFile = MediaBrowser.Model.Services.IHttpFile;
 using IHttpRequest = MediaBrowser.Model.Services.IHttpRequest;
 using IHttpRequest = MediaBrowser.Model.Services.IHttpRequest;
-using IResponse = MediaBrowser.Model.Services.IResponse;
 
 
 namespace Emby.Server.Implementations.SocketSharp
 namespace Emby.Server.Implementations.SocketSharp
 {
 {
     public partial class WebSocketSharpRequest : IHttpRequest
     public partial class WebSocketSharpRequest : IHttpRequest
     {
     {
-        private readonly HttpRequest request;
+        public const string FormUrlEncoded = "application/x-www-form-urlencoded";
+        public const string MultiPartFormData = "multipart/form-data";
+        public const string Soap11 = "text/xml; charset=utf-8";
+
+        private string _remoteIp;
+        private Dictionary<string, object> _items;
+        private string _responseContentType;
+        private IHttpFile[] _httpFiles;
+        private Dictionary<string, HttpPostedFile> _files;
 
 
-        public WebSocketSharpRequest(HttpRequest httpContext, HttpResponse response, string operationName, ILogger logger)
+        public WebSocketSharpRequest(HttpRequest httpRequest, HttpResponse httpResponse, string operationName, ILogger logger)
         {
         {
             this.OperationName = operationName;
             this.OperationName = operationName;
-            this.request = httpContext;
-            this.Response = new WebSocketSharpResponse(logger, response);
+            this.Request = httpRequest;
+            this.Response = httpResponse;
         }
         }
 
 
-        public HttpRequest HttpRequest => request;
+        public string Accept => StringValues.IsNullOrEmpty(Request.Headers[HeaderNames.Accept]) ? null : Request.Headers[HeaderNames.Accept].ToString();
 
 
-        public IResponse Response { get; }
+        public string Authorization => StringValues.IsNullOrEmpty(Request.Headers[HeaderNames.Authorization]) ? null : Request.Headers[HeaderNames.Authorization].ToString();
 
 
-        public string OperationName { get; set; }
+        public HttpRequest Request { get; }
 
 
-        public object Dto { get; set; }
+        public HttpResponse Response { get; }
 
 
-        public string RawUrl => request.GetEncodedPathAndQuery();
+        public string OperationName { get; set; }
 
 
-        public string AbsoluteUri => request.GetDisplayUrl().TrimEnd('/');
-        // Header[name] returns "" when undefined
+        public string RawUrl => Request.GetEncodedPathAndQuery();
 
 
-        private string GetHeader(string name) => request.Headers[name].ToString();
+        public string AbsoluteUri => Request.GetDisplayUrl().TrimEnd('/');
 
 
-        private string remoteIp;
         public string RemoteIp
         public string RemoteIp
         {
         {
             get
             get
             {
             {
-                if (remoteIp != null)
+                if (_remoteIp != null)
                 {
                 {
-                    return remoteIp;
+                    return _remoteIp;
                 }
                 }
 
 
                 IPAddress ip;
                 IPAddress ip;
@@ -62,14 +66,84 @@ namespace Emby.Server.Implementations.SocketSharp
                 {
                 {
                     if (!IPAddress.TryParse(GetHeader(CustomHeaderNames.XRealIP), out ip))
                     if (!IPAddress.TryParse(GetHeader(CustomHeaderNames.XRealIP), out ip))
                     {
                     {
-                        ip = request.HttpContext.Connection.RemoteIpAddress;
+                        ip = Request.HttpContext.Connection.RemoteIpAddress;
                     }
                     }
                 }
                 }
 
 
-                return remoteIp = NormalizeIp(ip).ToString();
+                return _remoteIp = NormalizeIp(ip).ToString();
             }
             }
         }
         }
 
 
+        public string[] AcceptTypes => Request.Headers.GetCommaSeparatedValues(HeaderNames.Accept);
+
+        public Dictionary<string, object> Items => _items ?? (_items = new Dictionary<string, object>());
+
+        public string ResponseContentType
+        {
+            get =>
+                _responseContentType
+                ?? (_responseContentType = GetResponseContentType(Request));
+            set => this._responseContentType = value;
+        }
+
+        public string PathInfo => Request.Path.Value;
+
+        public string UserAgent => Request.Headers[HeaderNames.UserAgent];
+
+        public IHeaderDictionary Headers => Request.Headers;
+
+        public IQueryCollection QueryString => Request.Query;
+
+        public bool IsLocal => Request.HttpContext.Connection.LocalIpAddress.Equals(Request.HttpContext.Connection.RemoteIpAddress);
+
+
+        public string HttpMethod => Request.Method;
+
+        public string Verb => HttpMethod;
+
+        public string ContentType => Request.ContentType;
+
+        public Uri UrlReferrer => Request.GetTypedHeaders().Referer;
+
+        public Stream InputStream => Request.Body;
+
+        public long ContentLength => Request.ContentLength ?? 0;
+
+
+        public IHttpFile[] Files
+        {
+            get
+            {
+                if (_httpFiles != null)
+                {
+                    return _httpFiles;
+                }
+
+                if (_files == null)
+                {
+                    return _httpFiles = Array.Empty<IHttpFile>();
+                }
+
+                var values = _files.Values;
+                _httpFiles = new IHttpFile[values.Count];
+                for (int i = 0; i < values.Count; i++)
+                {
+                    var reqFile = values.ElementAt(i);
+                    _httpFiles[i] = new HttpFile
+                    {
+                        ContentType = reqFile.ContentType,
+                        ContentLength = reqFile.ContentLength,
+                        FileName = reqFile.FileName,
+                        InputStream = reqFile.InputStream,
+                    };
+                }
+
+                return _httpFiles;
+            }
+        }
+
+        private string GetHeader(string name) => Request.Headers[name].ToString();
+
         private static IPAddress NormalizeIp(IPAddress ip)
         private static IPAddress NormalizeIp(IPAddress ip)
         {
         {
             if (ip.IsIPv4MappedToIPv6)
             if (ip.IsIPv4MappedToIPv6)
@@ -80,22 +154,6 @@ namespace Emby.Server.Implementations.SocketSharp
             return ip;
             return ip;
         }
         }
 
 
-        public string[] AcceptTypes => request.Headers.GetCommaSeparatedValues(HeaderNames.Accept);
-
-        private Dictionary<string, object> items;
-        public Dictionary<string, object> Items => items ?? (items = new Dictionary<string, object>());
-
-        private string responseContentType;
-        public string ResponseContentType
-        {
-            get =>
-                responseContentType
-                ?? (responseContentType = GetResponseContentType(HttpRequest));
-            set => this.responseContentType = value;
-        }
-
-        public const string FormUrlEncoded = "application/x-www-form-urlencoded";
-        public const string MultiPartFormData = "multipart/form-data";
         public static string GetResponseContentType(HttpRequest httpReq)
         public static string GetResponseContentType(HttpRequest httpReq)
         {
         {
             var specifiedContentType = GetQueryStringContentType(httpReq);
             var specifiedContentType = GetQueryStringContentType(httpReq);
@@ -152,8 +210,6 @@ namespace Emby.Server.Implementations.SocketSharp
             return serverDefaultContentType;
             return serverDefaultContentType;
         }
         }
 
 
-        public const string Soap11 = "text/xml; charset=utf-8";
-
         public static bool HasAnyOfContentTypes(HttpRequest request, params string[] contentTypes)
         public static bool HasAnyOfContentTypes(HttpRequest request, params string[] contentTypes)
         {
         {
             if (contentTypes == null || request.ContentType == null)
             if (contentTypes == null || request.ContentType == null)
@@ -224,105 +280,5 @@ namespace Emby.Server.Implementations.SocketSharp
             var pos = strVal.IndexOf(needle);
             var pos = strVal.IndexOf(needle);
             return pos == -1 ? strVal : strVal.Slice(0, pos);
             return pos == -1 ? strVal : strVal.Slice(0, pos);
         }
         }
-
-        public string PathInfo => this.request.Path.Value;
-
-        public string UserAgent => request.Headers[HeaderNames.UserAgent];
-
-        public IHeaderDictionary Headers => request.Headers;
-
-        public IQueryCollection QueryString => request.Query;
-
-        public bool IsLocal => string.Equals(request.HttpContext.Connection.LocalIpAddress.ToString(), request.HttpContext.Connection.RemoteIpAddress.ToString());
-
-        private string httpMethod;
-        public string HttpMethod =>
-            httpMethod
-            ?? (httpMethod = request.Method);
-
-        public string Verb => HttpMethod;
-
-        public string ContentType => request.ContentType;
-
-        private Encoding ContentEncoding
-        {
-            get
-            {
-                // TODO is this necessary?
-                if (UserAgent != null && CultureInfo.InvariantCulture.CompareInfo.IsPrefix(UserAgent, "UP"))
-                {
-                    string postDataCharset = Headers["x-up-devcap-post-charset"];
-                    if (!string.IsNullOrEmpty(postDataCharset))
-                    {
-                        try
-                        {
-                            return Encoding.GetEncoding(postDataCharset);
-                        }
-                        catch (ArgumentException)
-                        {
-                        }
-                    }
-                }
-
-                return request.GetTypedHeaders().ContentType.Encoding ?? Encoding.UTF8;
-            }
-        }
-
-        public Uri UrlReferrer => request.GetTypedHeaders().Referer;
-
-        public static Encoding GetEncoding(string contentTypeHeader)
-        {
-            var param = GetParameter(contentTypeHeader.AsSpan(), "charset=");
-            if (param == null)
-            {
-                return null;
-            }
-
-            try
-            {
-                return Encoding.GetEncoding(param);
-            }
-            catch (ArgumentException)
-            {
-                return null;
-            }
-        }
-
-        public Stream InputStream => request.Body;
-
-        public long ContentLength => request.ContentLength ?? 0;
-
-        private IHttpFile[] httpFiles;
-        public IHttpFile[] Files
-        {
-            get
-            {
-                if (httpFiles != null)
-                {
-                    return httpFiles;
-                }
-
-                if (files == null)
-                {
-                    return httpFiles = Array.Empty<IHttpFile>();
-                }
-
-                var values = files.Values;
-                httpFiles = new IHttpFile[values.Count];
-                for (int i = 0; i < values.Count; i++)
-                {
-                    var reqFile = values.ElementAt(i);
-                    httpFiles[i] = new HttpFile
-                    {
-                        ContentType = reqFile.ContentType,
-                        ContentLength = reqFile.ContentLength,
-                        FileName = reqFile.FileName,
-                        InputStream = reqFile.InputStream,
-                    };
-                }
-
-                return httpFiles;
-            }
-        }
     }
     }
 }
 }

+ 0 - 98
Emby.Server.Implementations/SocketSharp/WebSocketSharpResponse.cs

@@ -1,98 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Services;
-using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.Logging;
-using IRequest = MediaBrowser.Model.Services.IRequest;
-
-namespace Emby.Server.Implementations.SocketSharp
-{
-    public class WebSocketSharpResponse : IResponse
-    {
-        private readonly ILogger _logger;
-
-        public WebSocketSharpResponse(ILogger logger, HttpResponse response)
-        {
-            _logger = logger;
-            OriginalResponse = response;
-        }
-
-        public HttpResponse OriginalResponse { get; }
-
-        public int StatusCode
-        {
-            get => OriginalResponse.StatusCode;
-            set => OriginalResponse.StatusCode = value;
-        }
-
-        public string StatusDescription { get; set; }
-
-        public string ContentType
-        {
-            get => OriginalResponse.ContentType;
-            set => OriginalResponse.ContentType = value;
-        }
-
-        public void AddHeader(string name, string value)
-        {
-            if (string.Equals(name, "Content-Type", StringComparison.OrdinalIgnoreCase))
-            {
-                ContentType = value;
-                return;
-            }
-
-            OriginalResponse.Headers.Add(name, value);
-        }
-
-        public void Redirect(string url)
-        {
-            OriginalResponse.Redirect(url);
-        }
-
-        public Stream OutputStream => OriginalResponse.Body;
-
-        public bool SendChunked { get; set; }
-
-        const int StreamCopyToBufferSize = 81920;
-        public async Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, IFileSystem fileSystem, IStreamHelper streamHelper, CancellationToken cancellationToken)
-        {
-            var allowAsync = !RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
-
-            //if (count <= 0)
-            //{
-            //    allowAsync = true;
-            //}
-
-            var fileOpenOptions = FileOpenOptions.SequentialScan;
-
-            if (allowAsync)
-            {
-                fileOpenOptions |= FileOpenOptions.Asynchronous;
-            }
-
-            // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
-
-            using (var fs = fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, fileShareMode, fileOpenOptions))
-            {
-                if (offset > 0)
-                {
-                    fs.Position = offset;
-                }
-
-                if (count > 0)
-                {
-                    await streamHelper.CopyToAsync(fs, OutputStream, count, cancellationToken).ConfigureAwait(false);
-                }
-                else
-                {
-                    await fs.CopyToAsync(OutputStream, StreamCopyToBufferSize, cancellationToken).ConfigureAwait(false);
-                }
-            }
-        }
-    }
-}

+ 1 - 1
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -1019,7 +1019,7 @@ namespace MediaBrowser.Api.Playback
 
 
             foreach (var item in responseHeaders)
             foreach (var item in responseHeaders)
             {
             {
-                Request.Response.AddHeader(item.Key, item.Value);
+                Request.Response.Headers.Add(item.Key, item.Value);
             }
             }
         }
         }
 
 

+ 2 - 1
MediaBrowser.Controller/Net/AuthenticatedAttribute.cs

@@ -1,5 +1,6 @@
 using System;
 using System;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.Services;
+using Microsoft.AspNetCore.Http;
 
 
 namespace MediaBrowser.Controller.Net
 namespace MediaBrowser.Controller.Net
 {
 {
@@ -33,7 +34,7 @@ namespace MediaBrowser.Controller.Net
         /// <param name="request">The http request wrapper</param>
         /// <param name="request">The http request wrapper</param>
         /// <param name="response">The http response wrapper</param>
         /// <param name="response">The http response wrapper</param>
         /// <param name="requestDto">The request DTO</param>
         /// <param name="requestDto">The request DTO</param>
-        public void RequestFilter(IRequest request, IResponse response, object requestDto)
+        public void RequestFilter(IRequest request, HttpResponse response, object requestDto)
         {
         {
             AuthService.Authenticate(request, this);
             AuthService.Authenticate(request, this);
         }
         }

+ 3 - 1
MediaBrowser.Model/Services/IHasRequestFilter.cs

@@ -1,3 +1,5 @@
+using Microsoft.AspNetCore.Http;
+
 namespace MediaBrowser.Model.Services
 namespace MediaBrowser.Model.Services
 {
 {
     public interface IHasRequestFilter
     public interface IHasRequestFilter
@@ -15,6 +17,6 @@ namespace MediaBrowser.Model.Services
         /// <param name="req">The http request wrapper</param>
         /// <param name="req">The http request wrapper</param>
         /// <param name="res">The http response wrapper</param>
         /// <param name="res">The http response wrapper</param>
         /// <param name="requestDto">The request DTO</param>
         /// <param name="requestDto">The request DTO</param>
-        void RequestFilter(IRequest req, IResponse res, object requestDto);
+        void RequestFilter(IRequest req, HttpResponse res, object requestDto);
     }
     }
 }
 }

+ 1 - 29
MediaBrowser.Model/Services/IRequest.cs

@@ -10,7 +10,7 @@ namespace MediaBrowser.Model.Services
 {
 {
     public interface IRequest
     public interface IRequest
     {
     {
-        IResponse Response { get; }
+        HttpResponse Response { get; }
 
 
         /// <summary>
         /// <summary>
         /// The name of the service being called (e.g. Request DTO Name)
         /// The name of the service being called (e.g. Request DTO Name)
@@ -22,11 +22,6 @@ namespace MediaBrowser.Model.Services
         /// </summary>
         /// </summary>
         string Verb { get; }
         string Verb { get; }
 
 
-        /// <summary>
-        /// The Request DTO, after it has been deserialized.
-        /// </summary>
-        object Dto { get; set; }
-
         /// <summary>
         /// <summary>
         /// The request ContentType
         /// The request ContentType
         /// </summary>
         /// </summary>
@@ -50,8 +45,6 @@ namespace MediaBrowser.Model.Services
 
 
         IQueryCollection QueryString { get; }
         IQueryCollection QueryString { get; }
 
 
-        Task<QueryParamCollection> GetFormData();
-
         string RawUrl { get; }
         string RawUrl { get; }
 
 
         string AbsoluteUri { get; }
         string AbsoluteUri { get; }
@@ -98,25 +91,4 @@ namespace MediaBrowser.Model.Services
     {
     {
         IRequest Request { get; set; }
         IRequest Request { get; set; }
     }
     }
-
-    public interface IResponse
-    {
-        HttpResponse OriginalResponse { get; }
-
-        int StatusCode { get; set; }
-
-        string StatusDescription { get; set; }
-
-        string ContentType { get; set; }
-
-        void AddHeader(string name, string value);
-
-        void Redirect(string url);
-
-        Stream OutputStream { get; }
-
-        Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, IFileSystem fileSystem, IStreamHelper streamHelper, CancellationToken cancellationToken);
-
-        bool SendChunked { get; set; }
-    }
 }
 }