Merge pull request #2862 from MediaBrowser/dev

Dev
This commit is contained in:
Luke 2017-09-03 03:29:18 -04:00 committed by GitHub
commit 9cf5cd1e5b
29 changed files with 329 additions and 385 deletions

View file

@ -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()
{

View file

@ -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" />

View file

@ -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;

View file

@ -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();
}
}

View file

@ -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()

View file

@ -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(

View file

@ -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
{

View file

@ -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; }
}
}

View file

@ -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();

View file

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

View file

@ -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);

View file

@ -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
foreach (var name in formData.Keys)
{
if (name == null) continue; //thank you ASP.NET
var values = request.FormData.GetValues(name);
if (values.Count == 1)
{
map[name] = values[0];
}
else
{
for (var i = 0; i < values.Count; i++)
var values = formData.GetValues(name);
if (values.Count == 1)
{
map[name + (i == 0 ? "" : "#" + i)] = values[i];
map[name] = values[0];
}
else
{
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];
}
}
}

View file

@ -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

View file

@ -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>

View file

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

View file

@ -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)

View file

@ -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();

View file

@ -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
{

View file

@ -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; }
}

View file

@ -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);
}
}
}

View file

@ -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)
{

View file

@ -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; }

View file

@ -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

View file

@ -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
{

View file

@ -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

View file

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

View file

@ -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);
}
}

View file

@ -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" />

View file

@ -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);
}
}
}