浏览代码

Merge pull request #2862 from MediaBrowser/dev

Dev
Luke 8 年之前
父节点
当前提交
9cf5cd1e5b
共有 29 个文件被更改,包括 328 次插入384 次删除
  1. 4 3
      Emby.Server.Implementations/ApplicationHost.cs
  2. 0 1
      Emby.Server.Implementations/Emby.Server.Implementations.csproj
  3. 29 39
      Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
  4. 2 2
      Emby.Server.Implementations/HttpServer/IHttpListener.cs
  5. 16 11
      Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
  6. 16 24
      Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs
  7. 0 1
      Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
  8. 1 35
      Emby.Server.Implementations/HttpServerFactory.cs
  9. 0 57
      Emby.Server.Implementations/Net/NetAcceptSocket.cs
  10. 7 2
      Emby.Server.Implementations/Services/HttpResult.cs
  11. 22 9
      Emby.Server.Implementations/Services/ResponseHelper.cs
  12. 29 27
      Emby.Server.Implementations/Services/ServiceHandler.cs
  13. 0 3
      MediaBrowser.Model/Net/IAcceptSocket.cs
  14. 0 5
      MediaBrowser.Model/Services/IRequest.cs
  15. 1 1
      SharedVersion.cs
  16. 50 17
      SocketHttpListener/Net/EndPointListener.cs
  17. 11 11
      SocketHttpListener/Net/EndPointManager.cs
  18. 20 18
      SocketHttpListener/Net/HttpConnection.cs
  19. 9 10
      SocketHttpListener/Net/HttpListener.cs
  20. 11 8
      SocketHttpListener/Net/HttpListenerRequest.cs
  21. 2 57
      SocketHttpListener/Net/HttpResponseStream.Managed.cs
  22. 2 2
      SocketHttpListener/Net/ListenerPrefix.cs
  23. 4 7
      SocketHttpListener/Net/SocketAcceptor.cs
  24. 2 2
      SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs
  25. 2 2
      SocketHttpListener/Net/WebSockets/WebSocketContext.cs
  26. 0 11
      SocketHttpListener/Primitives/ICertificate.cs
  27. 0 17
      SocketHttpListener/Primitives/IStreamFactory.cs
  28. 2 2
      SocketHttpListener/SocketHttpListener.csproj
  29. 86 0
      SocketHttpListener/SocketStream.cs

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

@@ -128,6 +128,7 @@ using MediaBrowser.Model.Events;
 using MediaBrowser.Model.Tasks;
 using MediaBrowser.Model.Threading;
 using StringExtensions = MediaBrowser.Controller.Extensions.StringExtensions;
+using X509Certificate = System.Security.Cryptography.X509Certificates.X509Certificate;
 
 namespace Emby.Server.Implementations
 {
@@ -1168,7 +1169,7 @@ namespace Emby.Server.Implementations
             }
         }
 
-        private ICertificate GetCertificate(CertificateInfo info)
+        private X509Certificate GetCertificate(CertificateInfo info)
         {
             var certificateLocation = info == null ? null : info.Path;
 
@@ -1195,7 +1196,7 @@ namespace Emby.Server.Implementations
                     return null;
                 }
 
-                return new Certificate(localCert);
+                return localCert;
             }
             catch (Exception ex)
             {
@@ -1584,7 +1585,7 @@ namespace Emby.Server.Implementations
         }
 
         private CertificateInfo CertificateInfo { get; set; }
-        private ICertificate Certificate { get; set; }
+        private X509Certificate Certificate { get; set; }
 
         private IEnumerable<string> GetUrlPrefixes()
         {

+ 0 - 1
Emby.Server.Implementations/Emby.Server.Implementations.csproj

@@ -440,7 +440,6 @@
     <Compile Include="Networking\NetworkManager.cs" />
     <Compile Include="Net\DisposableManagedObjectBase.cs" />
     <Compile Include="Net\NetAcceptSocket.cs" />
-    <Compile Include="Net\SocketAcceptor.cs" />
     <Compile Include="Net\SocketFactory.cs" />
     <Compile Include="Net\UdpSocket.cs" />
     <Compile Include="News\NewsEntryPoint.cs" />

+ 29 - 39
Emby.Server.Implementations/HttpServer/HttpListenerHost.cs

@@ -7,6 +7,7 @@ using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
@@ -23,8 +24,6 @@ using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.System;
 using MediaBrowser.Model.Text;
-using SocketHttpListener.Net;
-using SocketHttpListener.Primitives;
 
 namespace Emby.Server.Implementations.HttpServer
 {
@@ -55,9 +54,8 @@ namespace Emby.Server.Implementations.HttpServer
         private readonly IFileSystem _fileSystem;
         private readonly IJsonSerializer _jsonSerializer;
         private readonly IXmlSerializer _xmlSerializer;
-        private readonly ICertificate _certificate;
+        private readonly X509Certificate _certificate;
         private readonly IEnvironmentInfo _environment;
-        private readonly IStreamFactory _streamFactory;
         private readonly Func<Type, Func<string, object>> _funcParseFn;
         private readonly bool _enableDualModeSockets;
 
@@ -71,7 +69,7 @@ namespace Emby.Server.Implementations.HttpServer
             ILogger logger,
             IServerConfigurationManager config,
             string serviceName,
-            string defaultRedirectPath, INetworkManager networkManager, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IJsonSerializer jsonSerializer, IXmlSerializer xmlSerializer, IEnvironmentInfo environment, ICertificate certificate, IStreamFactory streamFactory, Func<Type, Func<string, object>> funcParseFn, bool enableDualModeSockets, IFileSystem fileSystem)
+            string defaultRedirectPath, INetworkManager networkManager, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IJsonSerializer jsonSerializer, IXmlSerializer xmlSerializer, IEnvironmentInfo environment, X509Certificate certificate, Func<Type, Func<string, object>> funcParseFn, bool enableDualModeSockets, IFileSystem fileSystem)
         {
             Instance = this;
 
@@ -86,7 +84,6 @@ namespace Emby.Server.Implementations.HttpServer
             _xmlSerializer = xmlSerializer;
             _environment = environment;
             _certificate = certificate;
-            _streamFactory = streamFactory;
             _funcParseFn = funcParseFn;
             _enableDualModeSockets = enableDualModeSockets;
             _fileSystem = fileSystem;
@@ -183,20 +180,10 @@ namespace Emby.Server.Implementations.HttpServer
             return attributes;
         }
 
-        public static string GetHandlerPathIfAny(string listenerUrl)
-        {
-            if (listenerUrl == null) return null;
-            var pos = listenerUrl.IndexOf("://", StringComparison.OrdinalIgnoreCase);
-            if (pos == -1) return null;
-            var startHostUrl = listenerUrl.Substring(pos + "://".Length);
-            var endPos = startHostUrl.IndexOf('/');
-            if (endPos == -1) return null;
-            var endHostUrl = startHostUrl.Substring(endPos + 1);
-            return string.IsNullOrEmpty(endHostUrl) ? null : endHostUrl.TrimEnd('/');
-        }
-
         private IHttpListener GetListener()
         {
+            //return new KestrelHost.KestrelListener(_logger, _environment, _fileSystem);
+
             return new WebSocketSharpListener(_logger,
                 _certificate,
                 _memoryStreamProvider,
@@ -204,22 +191,11 @@ namespace Emby.Server.Implementations.HttpServer
                 _networkManager,
                 _socketFactory,
                 _cryptoProvider,
-                _streamFactory,
                 _enableDualModeSockets,
-                GetRequest,
                 _fileSystem,
                 _environment);
         }
 
-        private IHttpRequest GetRequest(HttpListenerContext httpContext)
-        {
-            var operationName = httpContext.Request.GetOperationName();
-
-            var req = new WebSocketSharpRequest(httpContext, operationName, _logger, _memoryStreamProvider);
-
-            return req;
-        }
-
         private void OnWebSocketConnecting(WebSocketConnectingEventArgs args)
         {
             if (_disposed)
@@ -332,7 +308,8 @@ namespace Emby.Server.Implementations.HttpServer
             if (_listener != null)
             {
                 _logger.Info("Stopping HttpListener...");
-                _listener.Stop();
+                var task = _listener.Stop();
+                Task.WaitAll(task);
                 _logger.Info("HttpListener stopped");
             }
         }
@@ -418,7 +395,7 @@ namespace Emby.Server.Implementations.HttpServer
             return address.Trim('/');
         }
 
-        private bool ValidateHost(Uri url)
+        private bool ValidateHost(string host)
         {
             var hosts = _config
                 .Configuration
@@ -431,7 +408,7 @@ namespace Emby.Server.Implementations.HttpServer
                 return true;
             }
 
-            var host = url.Host ?? string.Empty;
+            host = host ?? string.Empty;
 
             _logger.Debug("Validating host {0}", host);
 
@@ -449,7 +426,7 @@ namespace Emby.Server.Implementations.HttpServer
         /// <summary>
         /// Overridable method that can be used to implement a custom hnandler
         /// </summary>
-        protected async Task RequestHandler(IHttpRequest httpReq, Uri url, CancellationToken cancellationToken)
+        protected async Task RequestHandler(IHttpRequest httpReq, string urlString, string host, string localPath, CancellationToken cancellationToken)
         {
             var date = DateTime.Now;
             var httpRes = httpReq.Response;
@@ -468,7 +445,7 @@ namespace Emby.Server.Implementations.HttpServer
                     return;
                 }
 
-                if (!ValidateHost(url))
+                if (!ValidateHost(host))
                 {
                     httpRes.StatusCode = 400;
                     httpRes.ContentType = "text/plain";
@@ -488,9 +465,7 @@ namespace Emby.Server.Implementations.HttpServer
                 }
 
                 var operationName = httpReq.OperationName;
-                var localPath = url.LocalPath;
 
-                var urlString = url.OriginalString;
                 enableLog = EnableLogging(urlString, localPath);
                 urlToLog = urlString;
                  logHeaders = enableLog && urlToLog.IndexOf("/videos/", StringComparison.OrdinalIgnoreCase) != -1;
@@ -710,12 +685,19 @@ namespace Emby.Server.Implementations.HttpServer
                     Summary = route.Summary
                 });
 
-                routes.Add(new RouteAttribute(DoubleNormalizeEmbyRoutePath(route.Path), route.Verbs)
+                routes.Add(new RouteAttribute(NormalizeMediaBrowserRoutePath(route.Path), route.Verbs)
                 {
                     Notes = route.Notes,
                     Priority = route.Priority,
                     Summary = route.Summary
                 });
+
+                //routes.Add(new RouteAttribute(DoubleNormalizeEmbyRoutePath(route.Path), route.Verbs)
+                //{
+                //    Notes = route.Notes,
+                //    Priority = route.Priority,
+                //    Summary = route.Summary
+                //});
             }
 
             return routes.ToArray(routes.Count);
@@ -756,6 +738,16 @@ namespace Emby.Server.Implementations.HttpServer
             return "emby/" + path;
         }
 
+        private string NormalizeMediaBrowserRoutePath(string path)
+        {
+            if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase))
+            {
+                return "/mediabrowser" + path;
+            }
+
+            return "mediabrowser/" + path;
+        }
+
         private string DoubleNormalizeEmbyRoutePath(string path)
         {
             if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase))
@@ -795,8 +787,6 @@ namespace Emby.Server.Implementations.HttpServer
         {
             UrlPrefixes = urlPrefixes;
 
-            WebSocketSharpRequest.HandlerFactoryPath = GetHandlerPathIfAny(UrlPrefixes[0]);
-
             _listener = GetListener();
 
             _listener.WebSocketConnected = OnWebSocketConnected;

+ 2 - 2
Emby.Server.Implementations/HttpServer/IHttpListener.cs

@@ -19,7 +19,7 @@ namespace Emby.Server.Implementations.HttpServer
         /// Gets or sets the request handler.
         /// </summary>
         /// <value>The request handler.</value>
-        Func<IHttpRequest, Uri, CancellationToken, Task> RequestHandler { get; set; }
+        Func<IHttpRequest, string, string, string, CancellationToken, Task> RequestHandler { get; set; }
 
         /// <summary>
         /// Gets or sets the web socket handler.
@@ -42,6 +42,6 @@ namespace Emby.Server.Implementations.HttpServer
         /// <summary>
         /// Stops this instance.
         /// </summary>
-        void Stop();
+        Task Stop();
     }
 }

+ 16 - 11
Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs

@@ -4,6 +4,7 @@ using SocketHttpListener.Net;
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Security.Cryptography.X509Certificates;
 using System.Threading;
 using System.Threading.Tasks;
 using MediaBrowser.Common.Net;
@@ -22,22 +23,20 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
         private HttpListener _listener;
 
         private readonly ILogger _logger;
-        private readonly ICertificate _certificate;
+        private readonly X509Certificate _certificate;
         private readonly IMemoryStreamFactory _memoryStreamProvider;
         private readonly ITextEncoding _textEncoding;
         private readonly INetworkManager _networkManager;
         private readonly ISocketFactory _socketFactory;
         private readonly ICryptoProvider _cryptoProvider;
-        private readonly IStreamFactory _streamFactory;
         private readonly IFileSystem _fileSystem;
-        private readonly Func<HttpListenerContext, IHttpRequest> _httpRequestFactory;
         private readonly bool _enableDualMode;
         private readonly IEnvironmentInfo _environment;
 
         private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
         private CancellationToken _disposeCancellationToken;
 
-        public WebSocketSharpListener(ILogger logger, ICertificate certificate, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, INetworkManager networkManager, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, bool enableDualMode, Func<HttpListenerContext, IHttpRequest> httpRequestFactory, IFileSystem fileSystem, IEnvironmentInfo environment)
+        public WebSocketSharpListener(ILogger logger, X509Certificate certificate, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, INetworkManager networkManager, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, bool enableDualMode, IFileSystem fileSystem, IEnvironmentInfo environment)
         {
             _logger = logger;
             _certificate = certificate;
@@ -46,9 +45,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
             _networkManager = networkManager;
             _socketFactory = socketFactory;
             _cryptoProvider = cryptoProvider;
-            _streamFactory = streamFactory;
             _enableDualMode = enableDualMode;
-            _httpRequestFactory = httpRequestFactory;
             _fileSystem = fileSystem;
             _environment = environment;
 
@@ -56,7 +53,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
         }
 
         public Action<Exception, IRequest, bool> ErrorHandler { get; set; }
-        public Func<IHttpRequest, Uri, CancellationToken, Task> RequestHandler { get; set; }
+        public Func<IHttpRequest, string, string, string, CancellationToken, Task> RequestHandler { get; set; }
 
         public Action<WebSocketConnectingEventArgs> WebSocketConnecting { get; set; }
 
@@ -65,7 +62,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
         public void Start(IEnumerable<string> urlPrefixes)
         {
             if (_listener == null)
-                _listener = new HttpListener(_logger, _cryptoProvider, _streamFactory, _socketFactory, _networkManager, _textEncoding, _memoryStreamProvider, _fileSystem, _environment);
+                _listener = new HttpListener(_logger, _cryptoProvider, _socketFactory, _networkManager, _textEncoding, _memoryStreamProvider, _fileSystem, _environment);
 
             _listener.EnableDualMode = _enableDualMode;
 
@@ -117,7 +114,9 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
                 return Task.FromResult(true);
             }
 
-            return RequestHandler(httpReq, request.Url, cancellationToken);
+            var uri = request.Url;
+
+            return RequestHandler(httpReq, uri.OriginalString, uri.Host, uri.LocalPath, cancellationToken);
         }
 
         private void ProcessWebSocketRequest(HttpListenerContext ctx)
@@ -173,10 +172,14 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
 
         private IHttpRequest GetRequest(HttpListenerContext httpContext)
         {
-            return _httpRequestFactory(httpContext);
+            var operationName = httpContext.Request.GetOperationName();
+
+            var req = new WebSocketSharpRequest(httpContext, operationName, _logger, _memoryStreamProvider);
+
+            return req;
         }
 
-        public void Stop()
+        public Task Stop()
         {
             _disposeCancellationTokenSource.Cancel();
 
@@ -189,6 +192,8 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
 
                 _listener.Close();
             }
+
+            return Task.FromResult(true);
         }
 
         public void Dispose()

+ 16 - 24
Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs

@@ -27,6 +27,20 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
             _memoryStreamProvider = memoryStreamProvider;
             this.request = httpContext.Request;
             this.response = new WebSocketSharpResponse(logger, httpContext.Response, this);
+
+            //HandlerFactoryPath = GetHandlerPathIfAny(UrlPrefixes[0]);
+        }
+
+        private static string GetHandlerPathIfAny(string listenerUrl)
+        {
+            if (listenerUrl == null) return null;
+            var pos = listenerUrl.IndexOf("://", StringComparison.OrdinalIgnoreCase);
+            if (pos == -1) return null;
+            var startHostUrl = listenerUrl.Substring(pos + "://".Length);
+            var endPos = startHostUrl.IndexOf('/');
+            if (endPos == -1) return null;
+            var endHostUrl = startHostUrl.Substring(endPos + 1);
+            return string.IsNullOrEmpty(endHostUrl) ? null : endHostUrl.TrimEnd('/');
         }
 
         public HttpListenerRequest HttpRequest
@@ -108,7 +122,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
                 return remoteIp ??
                     (remoteIp = (CheckBadChars(XForwardedFor)) ??
                                 (NormalizeIp(CheckBadChars(XRealIp)) ??
-                                (request.RemoteEndPoint != null ? NormalizeIp(request.RemoteEndPoint.IpAddress.ToString()) : null)));
+                                (request.RemoteEndPoint != null ? NormalizeIp(request.RemoteEndPoint.Address.ToString()) : null)));
             }
         }
 
@@ -232,13 +246,12 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
             set
             {
                 this.responseContentType = value;
-                HasExplicitResponseContentType = true;
             }
         }
 
         public const string FormUrlEncoded = "application/x-www-form-urlencoded";
         public const string MultiPartFormData = "multipart/form-data";
-        private static string GetResponseContentType(IRequest httpReq)
+        public static string GetResponseContentType(IRequest httpReq)
         {
             var specifiedContentType = GetQueryStringContentType(httpReq);
             if (!string.IsNullOrEmpty(specifiedContentType)) return specifiedContentType;
@@ -346,8 +359,6 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
                 : strVal.Substring(0, pos);
         }
 
-        public bool HasExplicitResponseContentType { get; private set; }
-
         public static string HandlerFactoryPath;
 
         private string pathInfo;
@@ -490,13 +501,6 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
             get { return HttpMethod; }
         }
 
-        public string Param(string name)
-        {
-            return Headers[name]
-                ?? QueryString[name]
-                ?? FormData[name];
-        }
-
         public string ContentType
         {
             get { return request.ContentType; }
@@ -584,18 +588,6 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
             return stream;
         }
 
-        public static string GetHandlerPathIfAny(string listenerUrl)
-        {
-            if (listenerUrl == null) return null;
-            var pos = listenerUrl.IndexOf("://", StringComparison.OrdinalIgnoreCase);
-            if (pos == -1) return null;
-            var startHostUrl = listenerUrl.Substring(pos + "://".Length);
-            var endPos = startHostUrl.IndexOf('/');
-            if (endPos == -1) return null;
-            var endHostUrl = startHostUrl.Substring(endPos + 1);
-            return String.IsNullOrEmpty(endHostUrl) ? null : endHostUrl.TrimEnd('/');
-        }
-
         public static string NormalizePathInfo(string pathInfo, string handlerPath)
         {
             if (handlerPath != null && pathInfo.TrimStart('/').StartsWith(

+ 0 - 1
Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs

@@ -29,7 +29,6 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
         }
 
         public IRequest Request { get; private set; }
-        public bool UseBufferedStream { get; set; }
         public Dictionary<string, object> Items { get; private set; }
         public object OriginalResponse
         {

+ 1 - 35
Emby.Server.Implementations/HttpServerFactory.cs

@@ -43,7 +43,7 @@ namespace Emby.Server.Implementations
             IJsonSerializer json,
             IXmlSerializer xml,
             IEnvironmentInfo environment,
-            ICertificate certificate,
+            X509Certificate certificate,
             IFileSystem fileSystem,
             bool enableDualModeSockets)
         {
@@ -63,7 +63,6 @@ namespace Emby.Server.Implementations
                 xml,
                 environment,
                 certificate,
-                new StreamFactory(),
                 GetParseFn,
                 enableDualModeSockets,
                 fileSystem);
@@ -74,37 +73,4 @@ namespace Emby.Server.Implementations
             return s => JsvReader.GetParseFn(propertyType)(s);
         }
     }
-
-    public class StreamFactory : IStreamFactory
-    {
-        public Stream CreateNetworkStream(IAcceptSocket acceptSocket, bool ownsSocket)
-        {
-            var netSocket = (NetAcceptSocket)acceptSocket;
-
-            return new SocketStream(netSocket.Socket, ownsSocket);
-        }
-
-        public Task AuthenticateSslStreamAsServer(Stream stream, ICertificate certificate)
-        {
-            var sslStream = (SslStream)stream;
-            var cert = (Certificate)certificate;
-
-            return sslStream.AuthenticateAsServerAsync(cert.X509Certificate);
-        }
-
-        public Stream CreateSslStream(Stream innerStream, bool leaveInnerStreamOpen)
-        {
-            return new SslStream(innerStream, leaveInnerStreamOpen);
-        }
-    }
-
-    public class Certificate : ICertificate
-    {
-        public Certificate(X509Certificate x509Certificate)
-        {
-            X509Certificate = x509Certificate;
-        }
-
-        public X509Certificate X509Certificate { get; private set; }
-    }
 }

+ 0 - 57
Emby.Server.Implementations/Net/NetAcceptSocket.cs

@@ -89,63 +89,6 @@ namespace Emby.Server.Implementations.Net
             Socket.Bind(nativeEndpoint);
         }
 
-        private SocketAcceptor _acceptor;
-        public void StartAccept(Action<IAcceptSocket> onAccept, Func<bool> isClosed)
-        {
-            _acceptor = new SocketAcceptor(_logger, Socket, onAccept, isClosed, DualMode);
-
-            _acceptor.StartAccept();
-        }
-
-        public Task SendFile(string path, byte[] preBuffer, byte[] postBuffer, CancellationToken cancellationToken)
-        {
-            var options = TransmitFileOptions.UseDefaultWorkerThread;
-
-            var completionSource = new TaskCompletionSource<bool>();
-
-            var result = Socket.BeginSendFile(path, preBuffer, postBuffer, options, new AsyncCallback(FileSendCallback), new Tuple<Socket, string, TaskCompletionSource<bool>>(Socket, path, completionSource));
-
-            return completionSource.Task;
-        }
-
-        public IAsyncResult BeginSendFile(string path, byte[] preBuffer, byte[] postBuffer, AsyncCallback callback, object state)
-        {
-            var options = TransmitFileOptions.UseDefaultWorkerThread;
-
-            return Socket.BeginSendFile(path, preBuffer, postBuffer, options, new AsyncCallback(FileSendCallback), state);
-        }
-
-        public void EndSendFile(IAsyncResult result)
-        {
-            Socket.EndSendFile(result);
-        }
-
-        private void FileSendCallback(IAsyncResult ar)
-        {
-            // Retrieve the socket from the state object.
-            Tuple<Socket, string, TaskCompletionSource<bool>> data = (Tuple<Socket, string, TaskCompletionSource<bool>>)ar.AsyncState;
-
-            var client = data.Item1;
-            var path = data.Item2;
-            var taskCompletion = data.Item3;
-
-            // Complete sending the data to the remote device.
-            try
-            {
-                client.EndSendFile(ar);
-                taskCompletion.TrySetResult(true);
-            }
-            catch (SocketException ex)
-            {
-                _logger.Info("Socket.SendFile failed for {0}. error code {1}", path, ex.SocketErrorCode);
-                taskCompletion.TrySetException(ex);
-            }
-            catch (Exception ex)
-            {
-                taskCompletion.TrySetException(ex);
-            }
-        }
-
         public void Dispose()
         {
             Socket.Dispose();

+ 7 - 2
Emby.Server.Implementations/Services/HttpResult.cs

@@ -45,10 +45,15 @@ namespace Emby.Server.Implementations.Services
             var bytesResponse = this.Response as byte[];
             if (bytesResponse != null)
             {
+                var contentLength = bytesResponse.Length;
+
                 if (response != null)
-                    response.SetContentLength(bytesResponse.Length);
+                    response.SetContentLength(contentLength);
 
-                await responseStream.WriteAsync(bytesResponse, 0, bytesResponse.Length).ConfigureAwait(false);
+                if (contentLength > 0)
+                {
+                    await responseStream.WriteAsync(bytesResponse, 0, contentLength).ConfigureAwait(false);
+                }
                 return;
             }
 

+ 22 - 9
Emby.Server.Implementations/Services/ResponseHelper.cs

@@ -41,11 +41,11 @@ namespace Emby.Server.Implementations.Services
 
                 response.StatusCode = httpResult.Status;
                 response.StatusDescription = httpResult.StatusCode.ToString();
-                if (string.IsNullOrEmpty(httpResult.ContentType))
-                {
-                    httpResult.ContentType = defaultContentType;
-                }
-                response.ContentType = httpResult.ContentType;
+                //if (string.IsNullOrEmpty(httpResult.ContentType))
+                //{
+                //    httpResult.ContentType = defaultContentType;
+                //}
+                //response.ContentType = httpResult.ContentType;
 
                 if (httpResult.Cookies != null)
                 {
@@ -124,7 +124,10 @@ namespace Emby.Server.Implementations.Services
                 response.ContentType = "application/octet-stream";
                 response.SetContentLength(bytes.Length);
 
-                await response.OutputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false);
+                if (bytes.Length > 0)
+                {
+                    await response.OutputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false);
+                }
                 return;
             }
 
@@ -133,7 +136,10 @@ namespace Emby.Server.Implementations.Services
             {
                 bytes = Encoding.UTF8.GetBytes(responseText);
                 response.SetContentLength(bytes.Length);
-                await response.OutputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false);
+                if (bytes.Length > 0)
+                {
+                    await response.OutputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false);
+                }
                 return;
             }
 
@@ -150,8 +156,15 @@ namespace Emby.Server.Implementations.Services
                 serializer(result, ms);
 
                 ms.Position = 0;
-                response.SetContentLength(ms.Length);
-                await ms.CopyToAsync(response.OutputStream).ConfigureAwait(false);
+
+                var contentLength = ms.Length;
+
+                response.SetContentLength(contentLength);
+
+                if (contentLength > 0)
+                {
+                    await ms.CopyToAsync(response.OutputStream).ConfigureAwait(false);
+                }
             }
 
             //serializer(result, outputStream);

+ 29 - 27
Emby.Server.Implementations/Services/ServiceHandler.cs

@@ -162,7 +162,11 @@ namespace Emby.Server.Implementations.Services
             if (RequireqRequestStream(requestType))
             {
                 // Used by IRequiresRequestStream
-                return CreateRequiresRequestStreamRequest(host, httpReq, requestType);
+                var request = ServiceHandler.CreateRequest(httpReq, restPath, GetRequestParams(httpReq), host.CreateInstance(requestType));
+
+                var rawReq = (IRequiresRequestStream)request;
+                rawReq.RequestStream = httpReq.InputStream;
+                return rawReq;
             }
 
             var requestParams = GetFlattenedRequestParams(httpReq);
@@ -176,16 +180,6 @@ namespace Emby.Server.Implementations.Services
             return requiresRequestStreamTypeInfo.IsAssignableFrom(requestType.GetTypeInfo());
         }
 
-        private static IRequiresRequestStream CreateRequiresRequestStreamRequest(HttpListenerHost host, IRequest req, Type requestType)
-        {
-            var restPath = GetRoute(req);
-            var request = ServiceHandler.CreateRequest(req, restPath, GetRequestParams(req), host.CreateInstance(requestType));
-
-            var rawReq = (IRequiresRequestStream)request;
-            rawReq.RequestStream = req.InputStream;
-            return rawReq;
-        }
-
         public static object CreateRequest(HttpListenerHost host, IRequest httpReq, RestPath restPath, Dictionary<string, string> requestParams)
         {
             var requestDto = CreateContentTypeRequest(host, httpReq, restPath.RequestType, httpReq.ContentType);
@@ -228,22 +222,26 @@ namespace Emby.Server.Implementations.Services
                 }
             }
 
-            if ((IsMethod(request.Verb, "POST") || IsMethod(request.Verb, "PUT")) && request.FormData != null)
+            if ((IsMethod(request.Verb, "POST") || IsMethod(request.Verb, "PUT")))
             {
-                foreach (var name in request.FormData.Keys)
+                var formData = request.FormData;
+                if (formData != null)
                 {
-                    if (name == null) continue; //thank you ASP.NET
-
-                    var values = request.FormData.GetValues(name);
-                    if (values.Count == 1)
+                    foreach (var name in formData.Keys)
                     {
-                        map[name] = values[0];
-                    }
-                    else
-                    {
-                        for (var i = 0; i < values.Count; i++)
+                        if (name == null) continue; //thank you ASP.NET
+
+                        var values = formData.GetValues(name);
+                        if (values.Count == 1)
+                        {
+                            map[name] = values[0];
+                        }
+                        else
                         {
-                            map[name + (i == 0 ? "" : "#" + i)] = values[i];
+                            for (var i = 0; i < values.Count; i++)
+                            {
+                                map[name + (i == 0 ? "" : "#" + i)] = values[i];
+                            }
                         }
                     }
                 }
@@ -270,12 +268,16 @@ namespace Emby.Server.Implementations.Services
                 map[name] = request.QueryString[name];
             }
 
-            if ((IsMethod(request.Verb, "POST") || IsMethod(request.Verb, "PUT")) && request.FormData != null)
+            if ((IsMethod(request.Verb, "POST") || IsMethod(request.Verb, "PUT")))
             {
-                foreach (var name in request.FormData.Keys)
+                var formData = request.FormData;
+                if (formData != null)
                 {
-                    if (name == null) continue; //thank you ASP.NET
-                    map[name] = request.FormData[name];
+                    foreach (var name in formData.Keys)
+                    {
+                        if (name == null) continue; //thank you ASP.NET
+                        map[name] = formData[name];
+                    }
                 }
             }
 

+ 0 - 3
MediaBrowser.Model/Net/IAcceptSocket.cs

@@ -12,9 +12,6 @@ namespace MediaBrowser.Model.Net
         void Listen(int backlog);
         void Bind(IpEndPointInfo endpoint);
         void Connect(IpEndPointInfo endPoint);
-        void StartAccept(Action<IAcceptSocket> onAccept, Func<bool> isClosed);
-        IAsyncResult BeginSendFile(string path, byte[] preBuffer, byte[] postBuffer, AsyncCallback callback, object state);
-        void EndSendFile(IAsyncResult result);
     }
 
     public class SocketCreateException : Exception

+ 0 - 5
MediaBrowser.Model/Services/IRequest.cs

@@ -48,11 +48,6 @@ namespace MediaBrowser.Model.Services
         /// </summary>
         string ResponseContentType { get; set; }
 
-        /// <summary>
-        /// Whether the ResponseContentType has been explicitly overrided or whether it was just the default
-        /// </summary>
-        bool HasExplicitResponseContentType { get; }
-
         /// <summary>
         /// Attach any data to this request that all filters and services can access.
         /// </summary>

+ 1 - 1
SharedVersion.cs

@@ -1,3 +1,3 @@
 using System.Reflection;
 
-[assembly: AssemblyVersion("3.2.30.5")]
+[assembly: AssemblyVersion("3.2.30.6")]

+ 50 - 17
SocketHttpListener/Net/EndPointListener.cs

@@ -3,6 +3,8 @@ using System.Collections;
 using System.Collections.Generic;
 using System.IO;
 using System.Net;
+using System.Net.Sockets;
+using System.Security.Cryptography.X509Certificates;
 using System.Threading;
 using MediaBrowser.Model.Cryptography;
 using MediaBrowser.Model.IO;
@@ -11,37 +13,37 @@ using MediaBrowser.Model.Net;
 using MediaBrowser.Model.System;
 using MediaBrowser.Model.Text;
 using SocketHttpListener.Primitives;
+using ProtocolType = MediaBrowser.Model.Net.ProtocolType;
+using SocketType = MediaBrowser.Model.Net.SocketType;
 
 namespace SocketHttpListener.Net
 {
     sealed class EndPointListener
     {
         HttpListener listener;
-        IpEndPointInfo endpoint;
-        IAcceptSocket sock;
-        Dictionary<ListenerPrefix,HttpListener> prefixes;  // Dictionary <ListenerPrefix, HttpListener>
+        IPEndPoint endpoint;
+        Socket sock;
+        Dictionary<ListenerPrefix, HttpListener> prefixes;  // Dictionary <ListenerPrefix, HttpListener>
         List<ListenerPrefix> unhandled; // List<ListenerPrefix> unhandled; host = '*'
         List<ListenerPrefix> all;       // List<ListenerPrefix> all;  host = '+'
-        ICertificate cert;
+        X509Certificate cert;
         bool secure;
         Dictionary<HttpConnection, HttpConnection> unregistered;
         private readonly ILogger _logger;
         private bool _closed;
         private bool _enableDualMode;
         private readonly ICryptoProvider _cryptoProvider;
-        private readonly IStreamFactory _streamFactory;
         private readonly ISocketFactory _socketFactory;
         private readonly ITextEncoding _textEncoding;
         private readonly IMemoryStreamFactory _memoryStreamFactory;
         private readonly IFileSystem _fileSystem;
         private readonly IEnvironmentInfo _environment;
 
-        public EndPointListener(HttpListener listener, IpAddressInfo addr, int port, bool secure, ICertificate cert, ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
+        public EndPointListener(HttpListener listener, IPAddress addr, int port, bool secure, X509Certificate cert, ILogger logger, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
         {
             this.listener = listener;
             _logger = logger;
             _cryptoProvider = cryptoProvider;
-            _streamFactory = streamFactory;
             _socketFactory = socketFactory;
             _memoryStreamFactory = memoryStreamFactory;
             _textEncoding = textEncoding;
@@ -51,8 +53,8 @@ namespace SocketHttpListener.Net
             this.secure = secure;
             this.cert = cert;
 
-            _enableDualMode = addr.Equals(IpAddressInfo.IPv6Any);
-            endpoint = new IpEndPointInfo(addr, port);
+            _enableDualMode = addr.Equals(IPAddress.IPv6Any);
+            endpoint = new IPEndPoint(addr, port);
 
             prefixes = new Dictionary<ListenerPrefix, HttpListener>();
             unregistered = new Dictionary<HttpConnection, HttpConnection>();
@@ -72,18 +74,18 @@ namespace SocketHttpListener.Net
         {
             try
             {
-                sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode);
+                sock = CreateSocket(endpoint.Address.AddressFamily, _enableDualMode);
             }
             catch (SocketCreateException ex)
             {
-                if (_enableDualMode && endpoint.IpAddress.Equals(IpAddressInfo.IPv6Any) && 
-                    (string.Equals(ex.ErrorCode, "AddressFamilyNotSupported", StringComparison.OrdinalIgnoreCase) || 
+                if (_enableDualMode && endpoint.Address.Equals(IPAddress.IPv6Any) &&
+                    (string.Equals(ex.ErrorCode, "AddressFamilyNotSupported", StringComparison.OrdinalIgnoreCase) ||
                     // mono on bsd is throwing this
                     string.Equals(ex.ErrorCode, "ProtocolNotSupported", StringComparison.OrdinalIgnoreCase)))
                 {
-                    endpoint = new IpEndPointInfo(IpAddressInfo.Any, endpoint.Port);
+                    endpoint = new IPEndPoint(IPAddress.Any, endpoint.Port);
                     _enableDualMode = false;
-                    sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode);
+                    sock = CreateSocket(endpoint.Address.AddressFamily, _enableDualMode);
                 }
                 else
                 {
@@ -96,11 +98,42 @@ namespace SocketHttpListener.Net
             // This is the number TcpListener uses.
             sock.Listen(2147483647);
 
-            sock.StartAccept(ProcessAccept, () => _closed);
+            new SocketAcceptor(_logger, sock, ProcessAccept, () => _closed).StartAccept();
             _closed = false;
         }
 
-        private async void ProcessAccept(IAcceptSocket accepted)
+        private Socket CreateSocket(AddressFamily addressFamily, bool dualMode)
+        {
+            try
+            {
+                var socket = new Socket(addressFamily, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
+
+                if (dualMode)
+                {
+                    socket.DualMode = true;
+                }
+
+                return socket;
+            }
+            catch (SocketException ex)
+            {
+                throw new SocketCreateException(ex.SocketErrorCode.ToString(), ex);
+            }
+            catch (ArgumentException ex)
+            {
+                if (dualMode)
+                {
+                    // Mono for BSD incorrectly throws ArgumentException instead of SocketException
+                    throw new SocketCreateException("AddressFamilyNotSupported", ex);
+                }
+                else
+                {
+                    throw;
+                }
+            }
+        }
+
+        private async void ProcessAccept(Socket accepted)
         {
             try
             {
@@ -112,7 +145,7 @@ namespace SocketHttpListener.Net
                     return;
                 }
 
-                HttpConnection conn = await HttpConnection.Create(_logger, accepted, listener, listener.secure, listener.cert, _cryptoProvider, _streamFactory, _memoryStreamFactory, _textEncoding, _fileSystem, _environment).ConfigureAwait(false);
+                HttpConnection conn = await HttpConnection.Create(_logger, accepted, listener, listener.secure, listener.cert, _cryptoProvider, _memoryStreamFactory, _textEncoding, _fileSystem, _environment).ConfigureAwait(false);
 
                 //_logger.Debug("Adding unregistered connection to {0}. Id: {1}", accepted.RemoteEndPoint, connectionId);
                 lock (listener.unregistered)

+ 11 - 11
SocketHttpListener/Net/EndPointManager.cs

@@ -66,25 +66,25 @@ namespace SocketHttpListener.Net
             epl.AddPrefix(lp, listener);
         }
 
-        private static IpAddressInfo GetIpAnyAddress(HttpListener listener)
+        private static IPAddress GetIpAnyAddress(HttpListener listener)
         {
-            return listener.EnableDualMode ? IpAddressInfo.IPv6Any : IpAddressInfo.Any;
+            return listener.EnableDualMode ? IPAddress.IPv6Any : IPAddress.Any;
         }
 
         static async Task<EndPointListener> GetEPListener(ILogger logger, string host, int port, HttpListener listener, bool secure)
         {
             var networkManager = listener.NetworkManager;
 
-            IpAddressInfo addr;
+            IPAddress addr;
             if (host == "*" || host == "+")
                 addr = GetIpAnyAddress(listener);
-            else if (networkManager.TryParseIpAddress(host, out addr) == false)
+            else if (IPAddress.TryParse(host, out addr) == false)
             {
                 try
                 {
                     var all = (await networkManager.GetHostAddressesAsync(host).ConfigureAwait(false));
 
-                    addr = (all.Length == 0 ? null : all[0]) ?? 
+                    addr = (all.Length == 0 ? null : IPAddress.Parse(all[0].Address)) ?? 
                         GetIpAnyAddress(listener);
                 }
                 catch
@@ -94,10 +94,10 @@ namespace SocketHttpListener.Net
             }
 
             Dictionary<int, EndPointListener> p = null;  // Dictionary<int, EndPointListener>
-            if (!ip_to_endpoints.TryGetValue(addr.Address, out p))
+            if (!ip_to_endpoints.TryGetValue(addr.ToString(), out p))
             {
                 p = new Dictionary<int, EndPointListener>();
-                ip_to_endpoints[addr.Address] = p;
+                ip_to_endpoints[addr.ToString()] = p;
             }
 
             EndPointListener epl = null;
@@ -107,25 +107,25 @@ namespace SocketHttpListener.Net
             }
             else
             {
-                epl = new EndPointListener(listener, addr, port, secure, listener.Certificate, logger, listener.CryptoProvider, listener.StreamFactory, listener.SocketFactory, listener.MemoryStreamFactory, listener.TextEncoding, listener.FileSystem, listener.EnvironmentInfo);
+                epl = new EndPointListener(listener, addr, port, secure, listener.Certificate, logger, listener.CryptoProvider, listener.SocketFactory, listener.MemoryStreamFactory, listener.TextEncoding, listener.FileSystem, listener.EnvironmentInfo);
                 p[port] = epl;
             }
 
             return epl;
         }
 
-        public static void RemoveEndPoint(EndPointListener epl, IpEndPointInfo ep)
+        public static void RemoveEndPoint(EndPointListener epl, IPEndPoint ep)
         {
             lock (ip_to_endpoints)
             {
                 // Dictionary<int, EndPointListener> p
                 Dictionary<int, EndPointListener> p;
-                if (ip_to_endpoints.TryGetValue(ep.IpAddress.Address, out p))
+                if (ip_to_endpoints.TryGetValue(ep.Address.ToString(), out p))
                 {
                     p.Remove(ep.Port);
                     if (p.Count == 0)
                     {
-                        ip_to_endpoints.Remove(ep.IpAddress.Address);
+                        ip_to_endpoints.Remove(ep.Address.ToString());
                     }
                 }
                 epl.Close();

+ 20 - 18
SocketHttpListener/Net/HttpConnection.cs

@@ -1,5 +1,9 @@
 using System;
 using System.IO;
+using System.Net;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Security.Cryptography.X509Certificates;
 using System.Text;
 using System.Threading.Tasks;
 using MediaBrowser.Model.Cryptography;
@@ -16,7 +20,7 @@ namespace SocketHttpListener.Net
     {
         private static AsyncCallback s_onreadCallback = new AsyncCallback(OnRead);
         const int BufferSize = 8192;
-        IAcceptSocket _socket;
+        Socket _socket;
         Stream _stream;
         EndPointListener _epl;
         MemoryStream _memoryStream;
@@ -31,21 +35,20 @@ namespace SocketHttpListener.Net
         bool _contextBound;
         bool secure;
         int _timeout = 300000; // 90k ms for first request, 15k ms from then on
-        IpEndPointInfo local_ep;
+        IPEndPoint local_ep;
         HttpListener _lastListener;
         int[] client_cert_errors;
-        ICertificate cert;
-        Stream ssl_stream;
+        X509Certificate cert;
+        SslStream ssl_stream;
 
         private readonly ILogger _logger;
         private readonly ICryptoProvider _cryptoProvider;
         private readonly IMemoryStreamFactory _memoryStreamFactory;
         private readonly ITextEncoding _textEncoding;
-        private readonly IStreamFactory _streamFactory;
         private readonly IFileSystem _fileSystem;
         private readonly IEnvironmentInfo _environment;
 
-        private HttpConnection(ILogger logger, IAcceptSocket socket, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
+        private HttpConnection(ILogger logger, Socket socket, EndPointListener epl, bool secure, X509Certificate cert, ICryptoProvider cryptoProvider, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
         {
             _logger = logger;
             this._socket = socket;
@@ -57,14 +60,13 @@ namespace SocketHttpListener.Net
             _textEncoding = textEncoding;
             _fileSystem = fileSystem;
             _environment = environment;
-            _streamFactory = streamFactory;
         }
 
         private async Task InitStream()
         {
             if (secure == false)
             {
-                _stream = _streamFactory.CreateNetworkStream(_socket, false);
+                _stream = new SocketStream(_socket, false);
             }
             else
             {
@@ -81,16 +83,16 @@ namespace SocketHttpListener.Net
                 //});
                 //_stream = ssl_stream.AuthenticatedStream;
 
-                ssl_stream = _streamFactory.CreateSslStream(_streamFactory.CreateNetworkStream(_socket, false), false);
-                await _streamFactory.AuthenticateSslStreamAsServer(ssl_stream, cert).ConfigureAwait(false);
+                ssl_stream = new SslStream(new SocketStream(_socket, false), false);
+                await ssl_stream.AuthenticateAsServerAsync(cert).ConfigureAwait(false);
                 _stream = ssl_stream;
             }
             Init();
         }
 
-        public static async Task<HttpConnection> Create(ILogger logger, IAcceptSocket sock, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
+        public static async Task<HttpConnection> Create(ILogger logger, Socket sock, EndPointListener epl, bool secure, X509Certificate cert, ICryptoProvider cryptoProvider, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
         {
-            var connection = new HttpConnection(logger, sock, epl, secure, cert, cryptoProvider, streamFactory, memoryStreamFactory, textEncoding, fileSystem, environment);
+            var connection = new HttpConnection(logger, sock, epl, secure, cert, cryptoProvider, memoryStreamFactory, textEncoding, fileSystem, environment);
 
             await connection.InitStream().ConfigureAwait(false);
 
@@ -134,21 +136,21 @@ namespace SocketHttpListener.Net
             get { return _reuses; }
         }
 
-        public IpEndPointInfo LocalEndPoint
+        public IPEndPoint LocalEndPoint
         {
             get
             {
                 if (local_ep != null)
                     return local_ep;
 
-                local_ep = (IpEndPointInfo)_socket.LocalEndPoint;
+                local_ep = (IPEndPoint)_socket.LocalEndPoint;
                 return local_ep;
             }
         }
 
-        public IpEndPointInfo RemoteEndPoint
+        public IPEndPoint RemoteEndPoint
         {
-            get { return (IpEndPointInfo)_socket.RemoteEndPoint; }
+            get { return _socket.RemoteEndPoint as IPEndPoint; }
         }
 
         public bool IsSecure
@@ -513,12 +515,12 @@ namespace SocketHttpListener.Net
                     return;
                 }
 
-                IAcceptSocket s = _socket;
+                Socket s = _socket;
                 _socket = null;
                 try
                 {
                     if (s != null)
-                        s.Shutdown(true);
+                        s.Shutdown(SocketShutdown.Both);
                 }
                 catch
                 {

+ 9 - 10
SocketHttpListener/Net/HttpListener.cs

@@ -3,6 +3,7 @@ using System.Collections;
 using System.Collections.Generic;
 using System.IO;
 using System.Net;
+using System.Security.Cryptography.X509Certificates;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Model.Cryptography;
 using MediaBrowser.Model.IO;
@@ -17,7 +18,6 @@ namespace SocketHttpListener.Net
     public sealed class HttpListener : IDisposable
     {
         internal ICryptoProvider CryptoProvider { get; private set; }
-        internal IStreamFactory StreamFactory { get; private set; }
         internal ISocketFactory SocketFactory { get; private set; }
         internal IFileSystem FileSystem { get; private set; }
         internal ITextEncoding TextEncoding { get; private set; }
@@ -38,15 +38,14 @@ namespace SocketHttpListener.Net
         Dictionary<HttpListenerContext, HttpListenerContext> registry;   // Dictionary<HttpListenerContext,HttpListenerContext> 
         Dictionary<HttpConnection, HttpConnection> connections;
         private ILogger _logger;
-        private ICertificate _certificate;
+        private X509Certificate _certificate;
 
         public Action<HttpListenerContext> OnContext { get; set; }
 
-        public HttpListener(ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
+        public HttpListener(ILogger logger, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
         {
             _logger = logger;
             CryptoProvider = cryptoProvider;
-            StreamFactory = streamFactory;
             SocketFactory = socketFactory;
             NetworkManager = networkManager;
             TextEncoding = textEncoding;
@@ -59,18 +58,18 @@ namespace SocketHttpListener.Net
             auth_schemes = AuthenticationSchemes.Anonymous;
         }
 
-        public HttpListener(ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
-            :this(new NullLogger(), certificate, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo)
+        public HttpListener(X509Certificate certificate, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
+            :this(new NullLogger(), certificate, cryptoProvider, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo)
         {
         }
 
-        public HttpListener(ILogger logger, ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
-            : this(logger, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo)
+        public HttpListener(ILogger logger, X509Certificate certificate, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
+            : this(logger, cryptoProvider, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo)
         {
             _certificate = certificate;
         }
 
-        public void LoadCert(ICertificate cert)
+        public void LoadCert(X509Certificate cert)
         {
             _certificate = cert;
         }
@@ -150,7 +149,7 @@ namespace SocketHttpListener.Net
         //    }
         //}
 
-        internal ICertificate Certificate
+        internal X509Certificate Certificate
         {
             get { return _certificate; }
         }

+ 11 - 8
SocketHttpListener/Net/HttpListenerRequest.cs

@@ -3,6 +3,7 @@ using System.Collections.Specialized;
 using System.Globalization;
 using System.IO;
 using System.Net;
+using System.Security.Cryptography.X509Certificates;
 using System.Text;
 using System.Threading.Tasks;
 using MediaBrowser.Model.Net;
@@ -513,7 +514,14 @@ namespace SocketHttpListener.Net
 
         public bool IsLocal
         {
-            get { return RemoteEndPoint.IpAddress.Equals(IpAddressInfo.Loopback) || RemoteEndPoint.IpAddress.Equals(IpAddressInfo.IPv6Loopback) || LocalEndPoint.IpAddress.Equals(RemoteEndPoint.IpAddress); }
+            get
+            {
+                var remoteEndPoint = RemoteEndPoint;
+
+                return remoteEndPoint.Address.Equals(IPAddress.Loopback) ||
+                       remoteEndPoint.Address.Equals(IPAddress.IPv6Loopback) || 
+                        LocalEndPoint.Address.Equals(remoteEndPoint.Address);
+            }
         }
 
         public bool IsSecureConnection
@@ -557,7 +565,7 @@ namespace SocketHttpListener.Net
             }
         }
 
-        public IpEndPointInfo LocalEndPoint
+        public IPEndPoint LocalEndPoint
         {
             get { return context.Connection.LocalEndPoint; }
         }
@@ -577,7 +585,7 @@ namespace SocketHttpListener.Net
             get { return raw_url; }
         }
 
-        public IpEndPointInfo RemoteEndPoint
+        public IPEndPoint RemoteEndPoint
         {
             get { return context.Connection.RemoteEndPoint; }
         }
@@ -651,10 +659,5 @@ namespace SocketHttpListener.Net
                 return _websocketRequest;
             }
         }
-
-        public Task<ICertificate> GetClientCertificateAsync()
-        {
-            return Task.FromResult<ICertificate>(null);
-        }
     }
 }

+ 2 - 57
SocketHttpListener/Net/HttpResponseStream.Managed.cs

@@ -51,13 +51,13 @@ namespace SocketHttpListener.Net
         private bool _trailer_sent;
         private Stream _stream;
         private readonly IMemoryStreamFactory _memoryStreamFactory;
-        private readonly IAcceptSocket _socket;
+        private readonly Socket _socket;
         private readonly bool _supportsDirectSocketAccess;
         private readonly IEnvironmentInfo _environment;
         private readonly IFileSystem _fileSystem;
         private readonly ILogger _logger;
 
-        internal HttpResponseStream(Stream stream, HttpListenerResponse response, bool ignore_errors, IMemoryStreamFactory memoryStreamFactory, IAcceptSocket socket, bool supportsDirectSocketAccess, IEnvironmentInfo environment, IFileSystem fileSystem, ILogger logger)
+        internal HttpResponseStream(Stream stream, HttpListenerResponse response, bool ignore_errors, IMemoryStreamFactory memoryStreamFactory, Socket socket, bool supportsDirectSocketAccess, IEnvironmentInfo environment, IFileSystem fileSystem, ILogger logger)
         {
             _response = response;
             _ignore_errors = ignore_errors;
@@ -289,64 +289,9 @@ namespace SocketHttpListener.Net
 
         public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
         {
-            if (_supportsDirectSocketAccess && offset == 0 && count == 0 && !_response.SendChunked && _response.ContentLength64 > 8192)
-            {
-                if (EnableSendFileWithSocket)
-                {
-                    return TransmitFileOverSocket(path, offset, count, fileShareMode, cancellationToken);
-                }
-            }
             return TransmitFileManaged(path, offset, count, fileShareMode, cancellationToken);
         }
 
-        private readonly byte[] _emptyBuffer = new byte[] { };
-        private Task TransmitFileOverSocket(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
-        {
-            var ms = GetHeaders(false);
-
-            byte[] preBuffer;
-            if (ms != null)
-            {
-                using (var msCopy = new MemoryStream())
-                {
-                    ms.CopyTo(msCopy);
-                    preBuffer = msCopy.ToArray();
-                }
-            }
-            else
-            {
-                return TransmitFileManaged(path, offset, count, fileShareMode, cancellationToken);
-            }
-
-            //_logger.Info("Socket sending file {0} {1}", path, response.ContentLength64);
-
-            var taskCompletion = new TaskCompletionSource<bool>();
-
-            Action<IAsyncResult> callback = callbackResult =>
-            {
-                try
-                {
-                    _socket.EndSendFile(callbackResult);
-                    taskCompletion.TrySetResult(true);
-                }
-                catch (Exception ex)
-                {
-                    taskCompletion.TrySetException(ex);
-                }
-            };
-
-            var result = _socket.BeginSendFile(path, preBuffer, _emptyBuffer, new AsyncCallback(callback), null);
-
-            if (result.CompletedSynchronously)
-            {
-                callback(result);
-            }
-
-            cancellationToken.Register(() => taskCompletion.TrySetCanceled());
-
-            return taskCompletion.Task;
-        }
-
         const int StreamCopyToBufferSize = 81920;
         private async Task TransmitFileManaged(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
         {

+ 2 - 2
SocketHttpListener/Net/ListenerPrefix.cs

@@ -11,7 +11,7 @@ namespace SocketHttpListener.Net
         ushort port;
         string path;
         bool secure;
-        IpAddressInfo[] addresses;
+        IPAddress[] addresses;
         public HttpListener Listener;
 
         public ListenerPrefix(string prefix)
@@ -25,7 +25,7 @@ namespace SocketHttpListener.Net
             return original;
         }
 
-        public IpAddressInfo[] Addresses
+        public IPAddress[] Addresses
         {
             get { return addresses; }
             set { addresses = value; }

+ 4 - 7
Emby.Server.Implementations/Net/SocketAcceptor.cs → SocketHttpListener/Net/SocketAcceptor.cs

@@ -1,19 +1,17 @@
 using System;
 using System.Net.Sockets;
 using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
 
-namespace Emby.Server.Implementations.Net
+namespace SocketHttpListener.Net
 {
     public class SocketAcceptor
     {
         private readonly ILogger _logger;
         private readonly Socket _originalSocket;
         private readonly Func<bool> _isClosed;
-        private readonly Action<IAcceptSocket> _onAccept;
-        private readonly bool _isDualMode;
+        private readonly Action<Socket> _onAccept;
 
-        public SocketAcceptor(ILogger logger, Socket originalSocket, Action<IAcceptSocket> onAccept, Func<bool> isClosed, bool isDualMode)
+        public SocketAcceptor(ILogger logger, Socket originalSocket, Action<Socket> onAccept, Func<bool> isClosed)
         {
             if (logger == null)
             {
@@ -35,7 +33,6 @@ namespace Emby.Server.Implementations.Net
             _logger = logger;
             _originalSocket = originalSocket;
             _isClosed = isClosed;
-            _isDualMode = isDualMode;
             _onAccept = onAccept;
         }
 
@@ -117,7 +114,7 @@ namespace Emby.Server.Implementations.Net
             if (acceptSocket != null)
             {
                 //ProcessAccept(acceptSocket);
-                _onAccept(new NetAcceptSocket(acceptSocket, _logger, _isDualMode));
+                _onAccept(acceptSocket);
             }
 
             // Accept the next connection request

+ 2 - 2
SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs

@@ -254,7 +254,7 @@ namespace SocketHttpListener.Net.WebSockets
         /// </summary>
         /// <value>
         /// </value>
-        public override IpEndPointInfo ServerEndPoint
+        public override IPEndPoint ServerEndPoint
         {
             get
             {
@@ -281,7 +281,7 @@ namespace SocketHttpListener.Net.WebSockets
         /// </summary>
         /// <value>
         /// </value>
-        public override IpEndPointInfo UserEndPoint
+        public override IPEndPoint UserEndPoint
         {
             get
             {

+ 2 - 2
SocketHttpListener/Net/WebSockets/WebSocketContext.cs

@@ -151,7 +151,7 @@ namespace SocketHttpListener.Net.WebSockets
         /// <value>
         /// A <see cref="System.Net.IPEndPoint"/> that represents the server endpoint.
         /// </value>
-        public abstract IpEndPointInfo ServerEndPoint { get; }
+        public abstract IPEndPoint ServerEndPoint { get; }
 
         /// <summary>
         /// Gets the client information (identity, authentication, and security roles).
@@ -167,7 +167,7 @@ namespace SocketHttpListener.Net.WebSockets
         /// <value>
         /// A <see cref="System.Net.IPEndPoint"/> that represents the client endpoint.
         /// </value>
-        public abstract IpEndPointInfo UserEndPoint { get; }
+        public abstract IPEndPoint UserEndPoint { get; }
 
         /// <summary>
         /// Gets the <see cref="SocketHttpListener.WebSocket"/> instance used for two-way communication

+ 0 - 11
SocketHttpListener/Primitives/ICertificate.cs

@@ -1,11 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace SocketHttpListener.Primitives
-{
-    public interface ICertificate
-    {
-    }
-}

+ 0 - 17
SocketHttpListener/Primitives/IStreamFactory.cs

@@ -1,17 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Net;
-
-namespace SocketHttpListener.Primitives
-{
-    public interface IStreamFactory
-    {
-        Stream CreateNetworkStream(IAcceptSocket acceptSocket, bool ownsSocket);
-        Stream CreateSslStream(Stream innerStream, bool leaveInnerStreamOpen);
-
-        Task AuthenticateSslStreamAsServer(Stream stream, ICertificate certificate);
-    }
-}

+ 2 - 2
SocketHttpListener/SocketHttpListener.csproj

@@ -82,6 +82,7 @@
     <Compile Include="Net\HttpStreamAsyncResult.cs" />
     <Compile Include="Net\HttpVersion.cs" />
     <Compile Include="Net\ListenerPrefix.cs" />
+    <Compile Include="Net\SocketAcceptor.cs" />
     <Compile Include="Net\UriScheme.cs" />
     <Compile Include="Net\WebHeaderCollection.cs" />
     <Compile Include="Net\WebHeaderEncoding.cs" />
@@ -89,11 +90,10 @@
     <Compile Include="Net\WebSockets\WebSocketContext.cs" />
     <Compile Include="Opcode.cs" />
     <Compile Include="PayloadData.cs" />
-    <Compile Include="Primitives\ICertificate.cs" />
-    <Compile Include="Primitives\IStreamFactory.cs" />
     <Compile Include="Primitives\ITextEncoding.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Rsv.cs" />
+    <Compile Include="SocketStream.cs" />
     <Compile Include="WebSocket.cs" />
     <Compile Include="WebSocketException.cs" />
     <Compile Include="WebSocketFrame.cs" />

+ 86 - 0
SocketHttpListener/SocketStream.cs

@@ -0,0 +1,86 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SocketHttpListener
+{
+    public class SocketStream : Stream
+    {
+        private readonly Socket _socket;
+
+        public SocketStream(Socket socket, bool ownsSocket)
+        {
+            _socket = socket;
+        }
+
+        public override void Flush()
+        {
+        }
+
+        public override bool CanRead
+        {
+            get { return true; }
+        }
+        public override bool CanSeek
+        {
+            get { return false; }
+        }
+        public override bool CanWrite
+        {
+            get { return true; }
+        }
+        public override long Length
+        {
+            get { throw new NotImplementedException(); }
+        }
+        public override long Position
+        {
+            get { throw new NotImplementedException(); }
+            set { throw new NotImplementedException(); }
+        }
+
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            _socket.Send(buffer, offset, count, SocketFlags.None);
+        }
+
+        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+        {
+            return _socket.BeginSend(buffer, offset, count, SocketFlags.None, callback, state);
+        }
+
+        public override void EndWrite(IAsyncResult asyncResult)
+        {
+            _socket.EndSend(asyncResult);
+        }
+
+        public override void SetLength(long value)
+        {
+            throw new NotImplementedException();
+        }
+
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            throw new NotImplementedException();
+        }
+
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            return _socket.Receive(buffer, offset, count, SocketFlags.None);
+        }
+
+        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+        {
+            return _socket.BeginReceive(buffer, offset, count, SocketFlags.None, callback, state);
+        }
+
+        public override int EndRead(IAsyncResult asyncResult)
+        {
+            return _socket.EndReceive(asyncResult);
+        }
+    }
+}