diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index b3d39a5206..b264cffe65 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/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 GetUrlPrefixes() { diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 84ec214c9b..75a9d85886 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -440,7 +440,6 @@ - diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index a9ce513247..86df798d0e 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/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> _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> 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> 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 /// /// Overridable method that can be used to implement a custom hnandler /// - 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; diff --git a/Emby.Server.Implementations/HttpServer/IHttpListener.cs b/Emby.Server.Implementations/HttpServer/IHttpListener.cs index 82175dbed6..9feb2311d7 100644 --- a/Emby.Server.Implementations/HttpServer/IHttpListener.cs +++ b/Emby.Server.Implementations/HttpServer/IHttpListener.cs @@ -19,7 +19,7 @@ namespace Emby.Server.Implementations.HttpServer /// Gets or sets the request handler. /// /// The request handler. - Func RequestHandler { get; set; } + Func RequestHandler { get; set; } /// /// Gets or sets the web socket handler. @@ -42,6 +42,6 @@ namespace Emby.Server.Implementations.HttpServer /// /// Stops this instance. /// - void Stop(); + Task Stop(); } } diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs index e648838b2f..10aaa40322 100644 --- a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs +++ b/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 _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 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 ErrorHandler { get; set; } - public Func RequestHandler { get; set; } + public Func RequestHandler { get; set; } public Action WebSocketConnecting { get; set; } @@ -65,7 +62,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp public void Start(IEnumerable 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() diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs index 2dfe6a9e3e..522377f0cc 100644 --- a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs +++ b/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( diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs index d6762d94b0..5b51c0cf1f 100644 --- a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs +++ b/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 Items { get; private set; } public object OriginalResponse { diff --git a/Emby.Server.Implementations/HttpServerFactory.cs b/Emby.Server.Implementations/HttpServerFactory.cs index 007f5c8293..717c50e7b5 100644 --- a/Emby.Server.Implementations/HttpServerFactory.cs +++ b/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; } - } } diff --git a/Emby.Server.Implementations/Net/NetAcceptSocket.cs b/Emby.Server.Implementations/Net/NetAcceptSocket.cs index 936a66c0b0..93638a3673 100644 --- a/Emby.Server.Implementations/Net/NetAcceptSocket.cs +++ b/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 onAccept, Func 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(); - - var result = Socket.BeginSendFile(path, preBuffer, postBuffer, options, new AsyncCallback(FileSendCallback), new Tuple>(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> data = (Tuple>)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(); diff --git a/Emby.Server.Implementations/Services/HttpResult.cs b/Emby.Server.Implementations/Services/HttpResult.cs index dfad09f7b3..91314c15ae 100644 --- a/Emby.Server.Implementations/Services/HttpResult.cs +++ b/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; } diff --git a/Emby.Server.Implementations/Services/ResponseHelper.cs b/Emby.Server.Implementations/Services/ResponseHelper.cs index 84dc343c39..22e1bc4aa5 100644 --- a/Emby.Server.Implementations/Services/ResponseHelper.cs +++ b/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); diff --git a/Emby.Server.Implementations/Services/ServiceHandler.cs b/Emby.Server.Implementations/Services/ServiceHandler.cs index f9fcfdbabd..d500595ce4 100644 --- a/Emby.Server.Implementations/Services/ServiceHandler.cs +++ b/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 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]; + } } } diff --git a/MediaBrowser.Model/Net/IAcceptSocket.cs b/MediaBrowser.Model/Net/IAcceptSocket.cs index 2b5d33dce6..343e12ab62 100644 --- a/MediaBrowser.Model/Net/IAcceptSocket.cs +++ b/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 onAccept, Func isClosed); - IAsyncResult BeginSendFile(string path, byte[] preBuffer, byte[] postBuffer, AsyncCallback callback, object state); - void EndSendFile(IAsyncResult result); } public class SocketCreateException : Exception diff --git a/MediaBrowser.Model/Services/IRequest.cs b/MediaBrowser.Model/Services/IRequest.cs index f056c7410a..5a895815ed 100644 --- a/MediaBrowser.Model/Services/IRequest.cs +++ b/MediaBrowser.Model/Services/IRequest.cs @@ -48,11 +48,6 @@ namespace MediaBrowser.Model.Services /// string ResponseContentType { get; set; } - /// - /// Whether the ResponseContentType has been explicitly overrided or whether it was just the default - /// - bool HasExplicitResponseContentType { get; } - /// /// Attach any data to this request that all filters and services can access. /// diff --git a/SharedVersion.cs b/SharedVersion.cs index b99f1bdc4b..00bdebb128 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,3 +1,3 @@ using System.Reflection; -[assembly: AssemblyVersion("3.2.30.5")] +[assembly: AssemblyVersion("3.2.30.6")] diff --git a/SocketHttpListener/Net/EndPointListener.cs b/SocketHttpListener/Net/EndPointListener.cs index 2106bbec56..2b1479e423 100644 --- a/SocketHttpListener/Net/EndPointListener.cs +++ b/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 prefixes; // Dictionary + IPEndPoint endpoint; + Socket sock; + Dictionary prefixes; // Dictionary List unhandled; // List unhandled; host = '*' List all; // List all; host = '+' - ICertificate cert; + X509Certificate cert; bool secure; Dictionary 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(); unregistered = new Dictionary(); @@ -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) diff --git a/SocketHttpListener/Net/EndPointManager.cs b/SocketHttpListener/Net/EndPointManager.cs index ddb110ec16..557caa59a3 100644 --- a/SocketHttpListener/Net/EndPointManager.cs +++ b/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 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 p = null; // Dictionary - if (!ip_to_endpoints.TryGetValue(addr.Address, out p)) + if (!ip_to_endpoints.TryGetValue(addr.ToString(), out p)) { p = new Dictionary(); - 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 p Dictionary 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(); diff --git a/SocketHttpListener/Net/HttpConnection.cs b/SocketHttpListener/Net/HttpConnection.cs index e66443c590..4e81589646 100644 --- a/SocketHttpListener/Net/HttpConnection.cs +++ b/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 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 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 { diff --git a/SocketHttpListener/Net/HttpListener.cs b/SocketHttpListener/Net/HttpListener.cs index b3e01425ca..4ae472f9ea 100644 --- a/SocketHttpListener/Net/HttpListener.cs +++ b/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 registry; // Dictionary Dictionary connections; private ILogger _logger; - private ICertificate _certificate; + private X509Certificate _certificate; public Action 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; } } diff --git a/SocketHttpListener/Net/HttpListenerRequest.cs b/SocketHttpListener/Net/HttpListenerRequest.cs index f9df525934..5e391424f0 100644 --- a/SocketHttpListener/Net/HttpListenerRequest.cs +++ b/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 GetClientCertificateAsync() - { - return Task.FromResult(null); - } } } diff --git a/SocketHttpListener/Net/HttpResponseStream.Managed.cs b/SocketHttpListener/Net/HttpResponseStream.Managed.cs index b700c293d7..d5ef0b3207 100644 --- a/SocketHttpListener/Net/HttpResponseStream.Managed.cs +++ b/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(); - - Action 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) { diff --git a/SocketHttpListener/Net/ListenerPrefix.cs b/SocketHttpListener/Net/ListenerPrefix.cs index 2c314da506..605b7b88cf 100644 --- a/SocketHttpListener/Net/ListenerPrefix.cs +++ b/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; } diff --git a/Emby.Server.Implementations/Net/SocketAcceptor.cs b/SocketHttpListener/Net/SocketAcceptor.cs similarity index 90% rename from Emby.Server.Implementations/Net/SocketAcceptor.cs rename to SocketHttpListener/Net/SocketAcceptor.cs index 288ba93adb..36332f52b6 100644 --- a/Emby.Server.Implementations/Net/SocketAcceptor.cs +++ b/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 _isClosed; - private readonly Action _onAccept; - private readonly bool _isDualMode; + private readonly Action _onAccept; - public SocketAcceptor(ILogger logger, Socket originalSocket, Action onAccept, Func isClosed, bool isDualMode) + public SocketAcceptor(ILogger logger, Socket originalSocket, Action onAccept, Func 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 diff --git a/SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs b/SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs index 034ac17d20..803c67b83e 100644 --- a/SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs +++ b/SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs @@ -254,7 +254,7 @@ namespace SocketHttpListener.Net.WebSockets /// /// /// - public override IpEndPointInfo ServerEndPoint + public override IPEndPoint ServerEndPoint { get { @@ -281,7 +281,7 @@ namespace SocketHttpListener.Net.WebSockets /// /// /// - public override IpEndPointInfo UserEndPoint + public override IPEndPoint UserEndPoint { get { diff --git a/SocketHttpListener/Net/WebSockets/WebSocketContext.cs b/SocketHttpListener/Net/WebSockets/WebSocketContext.cs index 3ffa6e639a..9665ab7893 100644 --- a/SocketHttpListener/Net/WebSockets/WebSocketContext.cs +++ b/SocketHttpListener/Net/WebSockets/WebSocketContext.cs @@ -151,7 +151,7 @@ namespace SocketHttpListener.Net.WebSockets /// /// A that represents the server endpoint. /// - public abstract IpEndPointInfo ServerEndPoint { get; } + public abstract IPEndPoint ServerEndPoint { get; } /// /// Gets the client information (identity, authentication, and security roles). @@ -167,7 +167,7 @@ namespace SocketHttpListener.Net.WebSockets /// /// A that represents the client endpoint. /// - public abstract IpEndPointInfo UserEndPoint { get; } + public abstract IPEndPoint UserEndPoint { get; } /// /// Gets the instance used for two-way communication diff --git a/SocketHttpListener/Primitives/ICertificate.cs b/SocketHttpListener/Primitives/ICertificate.cs deleted file mode 100644 index ec21e9445d..0000000000 --- a/SocketHttpListener/Primitives/ICertificate.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace SocketHttpListener.Primitives -{ - public interface ICertificate - { - } -} diff --git a/SocketHttpListener/Primitives/IStreamFactory.cs b/SocketHttpListener/Primitives/IStreamFactory.cs deleted file mode 100644 index 4b623b940f..0000000000 --- a/SocketHttpListener/Primitives/IStreamFactory.cs +++ /dev/null @@ -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); - } -} diff --git a/SocketHttpListener/SocketHttpListener.csproj b/SocketHttpListener/SocketHttpListener.csproj index 1aa7889316..6ed42ea882 100644 --- a/SocketHttpListener/SocketHttpListener.csproj +++ b/SocketHttpListener/SocketHttpListener.csproj @@ -82,6 +82,7 @@ + @@ -89,11 +90,10 @@ - - + diff --git a/SocketHttpListener/SocketStream.cs b/SocketHttpListener/SocketStream.cs new file mode 100644 index 0000000000..a4f31eab9b --- /dev/null +++ b/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); + } + } +}