commit
9cf5cd1e5b
|
@ -128,6 +128,7 @@ using MediaBrowser.Model.Events;
|
||||||
using MediaBrowser.Model.Tasks;
|
using MediaBrowser.Model.Tasks;
|
||||||
using MediaBrowser.Model.Threading;
|
using MediaBrowser.Model.Threading;
|
||||||
using StringExtensions = MediaBrowser.Controller.Extensions.StringExtensions;
|
using StringExtensions = MediaBrowser.Controller.Extensions.StringExtensions;
|
||||||
|
using X509Certificate = System.Security.Cryptography.X509Certificates.X509Certificate;
|
||||||
|
|
||||||
namespace Emby.Server.Implementations
|
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;
|
var certificateLocation = info == null ? null : info.Path;
|
||||||
|
|
||||||
|
@ -1195,7 +1196,7 @@ namespace Emby.Server.Implementations
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Certificate(localCert);
|
return localCert;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -1584,7 +1585,7 @@ namespace Emby.Server.Implementations
|
||||||
}
|
}
|
||||||
|
|
||||||
private CertificateInfo CertificateInfo { get; set; }
|
private CertificateInfo CertificateInfo { get; set; }
|
||||||
private ICertificate Certificate { get; set; }
|
private X509Certificate Certificate { get; set; }
|
||||||
|
|
||||||
private IEnumerable<string> GetUrlPrefixes()
|
private IEnumerable<string> GetUrlPrefixes()
|
||||||
{
|
{
|
||||||
|
|
|
@ -440,7 +440,6 @@
|
||||||
<Compile Include="Networking\NetworkManager.cs" />
|
<Compile Include="Networking\NetworkManager.cs" />
|
||||||
<Compile Include="Net\DisposableManagedObjectBase.cs" />
|
<Compile Include="Net\DisposableManagedObjectBase.cs" />
|
||||||
<Compile Include="Net\NetAcceptSocket.cs" />
|
<Compile Include="Net\NetAcceptSocket.cs" />
|
||||||
<Compile Include="Net\SocketAcceptor.cs" />
|
|
||||||
<Compile Include="Net\SocketFactory.cs" />
|
<Compile Include="Net\SocketFactory.cs" />
|
||||||
<Compile Include="Net\UdpSocket.cs" />
|
<Compile Include="Net\UdpSocket.cs" />
|
||||||
<Compile Include="News\NewsEntryPoint.cs" />
|
<Compile Include="News\NewsEntryPoint.cs" />
|
||||||
|
|
|
@ -7,6 +7,7 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -23,8 +24,6 @@ using MediaBrowser.Model.Serialization;
|
||||||
using MediaBrowser.Model.Services;
|
using MediaBrowser.Model.Services;
|
||||||
using MediaBrowser.Model.System;
|
using MediaBrowser.Model.System;
|
||||||
using MediaBrowser.Model.Text;
|
using MediaBrowser.Model.Text;
|
||||||
using SocketHttpListener.Net;
|
|
||||||
using SocketHttpListener.Primitives;
|
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.HttpServer
|
namespace Emby.Server.Implementations.HttpServer
|
||||||
{
|
{
|
||||||
|
@ -55,9 +54,8 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly IJsonSerializer _jsonSerializer;
|
private readonly IJsonSerializer _jsonSerializer;
|
||||||
private readonly IXmlSerializer _xmlSerializer;
|
private readonly IXmlSerializer _xmlSerializer;
|
||||||
private readonly ICertificate _certificate;
|
private readonly X509Certificate _certificate;
|
||||||
private readonly IEnvironmentInfo _environment;
|
private readonly IEnvironmentInfo _environment;
|
||||||
private readonly IStreamFactory _streamFactory;
|
|
||||||
private readonly Func<Type, Func<string, object>> _funcParseFn;
|
private readonly Func<Type, Func<string, object>> _funcParseFn;
|
||||||
private readonly bool _enableDualModeSockets;
|
private readonly bool _enableDualModeSockets;
|
||||||
|
|
||||||
|
@ -71,7 +69,7 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
IServerConfigurationManager config,
|
IServerConfigurationManager config,
|
||||||
string serviceName,
|
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;
|
Instance = this;
|
||||||
|
|
||||||
|
@ -86,7 +84,6 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
_xmlSerializer = xmlSerializer;
|
_xmlSerializer = xmlSerializer;
|
||||||
_environment = environment;
|
_environment = environment;
|
||||||
_certificate = certificate;
|
_certificate = certificate;
|
||||||
_streamFactory = streamFactory;
|
|
||||||
_funcParseFn = funcParseFn;
|
_funcParseFn = funcParseFn;
|
||||||
_enableDualModeSockets = enableDualModeSockets;
|
_enableDualModeSockets = enableDualModeSockets;
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
|
@ -183,20 +180,10 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
return attributes;
|
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()
|
private IHttpListener GetListener()
|
||||||
{
|
{
|
||||||
|
//return new KestrelHost.KestrelListener(_logger, _environment, _fileSystem);
|
||||||
|
|
||||||
return new WebSocketSharpListener(_logger,
|
return new WebSocketSharpListener(_logger,
|
||||||
_certificate,
|
_certificate,
|
||||||
_memoryStreamProvider,
|
_memoryStreamProvider,
|
||||||
|
@ -204,22 +191,11 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
_networkManager,
|
_networkManager,
|
||||||
_socketFactory,
|
_socketFactory,
|
||||||
_cryptoProvider,
|
_cryptoProvider,
|
||||||
_streamFactory,
|
|
||||||
_enableDualModeSockets,
|
_enableDualModeSockets,
|
||||||
GetRequest,
|
|
||||||
_fileSystem,
|
_fileSystem,
|
||||||
_environment);
|
_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)
|
private void OnWebSocketConnecting(WebSocketConnectingEventArgs args)
|
||||||
{
|
{
|
||||||
if (_disposed)
|
if (_disposed)
|
||||||
|
@ -332,7 +308,8 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
if (_listener != null)
|
if (_listener != null)
|
||||||
{
|
{
|
||||||
_logger.Info("Stopping HttpListener...");
|
_logger.Info("Stopping HttpListener...");
|
||||||
_listener.Stop();
|
var task = _listener.Stop();
|
||||||
|
Task.WaitAll(task);
|
||||||
_logger.Info("HttpListener stopped");
|
_logger.Info("HttpListener stopped");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -418,7 +395,7 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
return address.Trim('/');
|
return address.Trim('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ValidateHost(Uri url)
|
private bool ValidateHost(string host)
|
||||||
{
|
{
|
||||||
var hosts = _config
|
var hosts = _config
|
||||||
.Configuration
|
.Configuration
|
||||||
|
@ -431,7 +408,7 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var host = url.Host ?? string.Empty;
|
host = host ?? string.Empty;
|
||||||
|
|
||||||
_logger.Debug("Validating host {0}", host);
|
_logger.Debug("Validating host {0}", host);
|
||||||
|
|
||||||
|
@ -449,7 +426,7 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Overridable method that can be used to implement a custom hnandler
|
/// Overridable method that can be used to implement a custom hnandler
|
||||||
/// </summary>
|
/// </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 date = DateTime.Now;
|
||||||
var httpRes = httpReq.Response;
|
var httpRes = httpReq.Response;
|
||||||
|
@ -468,7 +445,7 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ValidateHost(url))
|
if (!ValidateHost(host))
|
||||||
{
|
{
|
||||||
httpRes.StatusCode = 400;
|
httpRes.StatusCode = 400;
|
||||||
httpRes.ContentType = "text/plain";
|
httpRes.ContentType = "text/plain";
|
||||||
|
@ -488,9 +465,7 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
}
|
}
|
||||||
|
|
||||||
var operationName = httpReq.OperationName;
|
var operationName = httpReq.OperationName;
|
||||||
var localPath = url.LocalPath;
|
|
||||||
|
|
||||||
var urlString = url.OriginalString;
|
|
||||||
enableLog = EnableLogging(urlString, localPath);
|
enableLog = EnableLogging(urlString, localPath);
|
||||||
urlToLog = urlString;
|
urlToLog = urlString;
|
||||||
logHeaders = enableLog && urlToLog.IndexOf("/videos/", StringComparison.OrdinalIgnoreCase) != -1;
|
logHeaders = enableLog && urlToLog.IndexOf("/videos/", StringComparison.OrdinalIgnoreCase) != -1;
|
||||||
|
@ -710,12 +685,19 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
Summary = route.Summary
|
Summary = route.Summary
|
||||||
});
|
});
|
||||||
|
|
||||||
routes.Add(new RouteAttribute(DoubleNormalizeEmbyRoutePath(route.Path), route.Verbs)
|
routes.Add(new RouteAttribute(NormalizeMediaBrowserRoutePath(route.Path), route.Verbs)
|
||||||
{
|
{
|
||||||
Notes = route.Notes,
|
Notes = route.Notes,
|
||||||
Priority = route.Priority,
|
Priority = route.Priority,
|
||||||
Summary = route.Summary
|
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);
|
return routes.ToArray(routes.Count);
|
||||||
|
@ -756,6 +738,16 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
return "emby/" + path;
|
return "emby/" + path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string NormalizeMediaBrowserRoutePath(string path)
|
||||||
|
{
|
||||||
|
if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return "/mediabrowser" + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "mediabrowser/" + path;
|
||||||
|
}
|
||||||
|
|
||||||
private string DoubleNormalizeEmbyRoutePath(string path)
|
private string DoubleNormalizeEmbyRoutePath(string path)
|
||||||
{
|
{
|
||||||
if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase))
|
if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase))
|
||||||
|
@ -795,8 +787,6 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
{
|
{
|
||||||
UrlPrefixes = urlPrefixes;
|
UrlPrefixes = urlPrefixes;
|
||||||
|
|
||||||
WebSocketSharpRequest.HandlerFactoryPath = GetHandlerPathIfAny(UrlPrefixes[0]);
|
|
||||||
|
|
||||||
_listener = GetListener();
|
_listener = GetListener();
|
||||||
|
|
||||||
_listener.WebSocketConnected = OnWebSocketConnected;
|
_listener.WebSocketConnected = OnWebSocketConnected;
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
/// Gets or sets the request handler.
|
/// Gets or sets the request handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The request handler.</value>
|
/// <value>The request handler.</value>
|
||||||
Func<IHttpRequest, Uri, CancellationToken, Task> RequestHandler { get; set; }
|
Func<IHttpRequest, string, string, string, CancellationToken, Task> RequestHandler { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the web socket handler.
|
/// Gets or sets the web socket handler.
|
||||||
|
@ -42,6 +42,6 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stops this instance.
|
/// Stops this instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Stop();
|
Task Stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ using SocketHttpListener.Net;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
|
@ -22,22 +23,20 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
|
||||||
private HttpListener _listener;
|
private HttpListener _listener;
|
||||||
|
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly ICertificate _certificate;
|
private readonly X509Certificate _certificate;
|
||||||
private readonly IMemoryStreamFactory _memoryStreamProvider;
|
private readonly IMemoryStreamFactory _memoryStreamProvider;
|
||||||
private readonly ITextEncoding _textEncoding;
|
private readonly ITextEncoding _textEncoding;
|
||||||
private readonly INetworkManager _networkManager;
|
private readonly INetworkManager _networkManager;
|
||||||
private readonly ISocketFactory _socketFactory;
|
private readonly ISocketFactory _socketFactory;
|
||||||
private readonly ICryptoProvider _cryptoProvider;
|
private readonly ICryptoProvider _cryptoProvider;
|
||||||
private readonly IStreamFactory _streamFactory;
|
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly Func<HttpListenerContext, IHttpRequest> _httpRequestFactory;
|
|
||||||
private readonly bool _enableDualMode;
|
private readonly bool _enableDualMode;
|
||||||
private readonly IEnvironmentInfo _environment;
|
private readonly IEnvironmentInfo _environment;
|
||||||
|
|
||||||
private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
|
private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
|
||||||
private CancellationToken _disposeCancellationToken;
|
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;
|
_logger = logger;
|
||||||
_certificate = certificate;
|
_certificate = certificate;
|
||||||
|
@ -46,9 +45,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
|
||||||
_networkManager = networkManager;
|
_networkManager = networkManager;
|
||||||
_socketFactory = socketFactory;
|
_socketFactory = socketFactory;
|
||||||
_cryptoProvider = cryptoProvider;
|
_cryptoProvider = cryptoProvider;
|
||||||
_streamFactory = streamFactory;
|
|
||||||
_enableDualMode = enableDualMode;
|
_enableDualMode = enableDualMode;
|
||||||
_httpRequestFactory = httpRequestFactory;
|
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
_environment = environment;
|
_environment = environment;
|
||||||
|
|
||||||
|
@ -56,7 +53,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
|
||||||
}
|
}
|
||||||
|
|
||||||
public Action<Exception, IRequest, bool> ErrorHandler { get; set; }
|
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; }
|
public Action<WebSocketConnectingEventArgs> WebSocketConnecting { get; set; }
|
||||||
|
|
||||||
|
@ -65,7 +62,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
|
||||||
public void Start(IEnumerable<string> urlPrefixes)
|
public void Start(IEnumerable<string> urlPrefixes)
|
||||||
{
|
{
|
||||||
if (_listener == null)
|
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;
|
_listener.EnableDualMode = _enableDualMode;
|
||||||
|
|
||||||
|
@ -117,7 +114,9 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
|
||||||
return Task.FromResult(true);
|
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)
|
private void ProcessWebSocketRequest(HttpListenerContext ctx)
|
||||||
|
@ -173,10 +172,14 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
|
||||||
|
|
||||||
private IHttpRequest GetRequest(HttpListenerContext httpContext)
|
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();
|
_disposeCancellationTokenSource.Cancel();
|
||||||
|
|
||||||
|
@ -189,6 +192,8 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
|
||||||
|
|
||||||
_listener.Close();
|
_listener.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|
|
@ -27,6 +27,20 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
|
||||||
_memoryStreamProvider = memoryStreamProvider;
|
_memoryStreamProvider = memoryStreamProvider;
|
||||||
this.request = httpContext.Request;
|
this.request = httpContext.Request;
|
||||||
this.response = new WebSocketSharpResponse(logger, httpContext.Response, this);
|
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
|
public HttpListenerRequest HttpRequest
|
||||||
|
@ -108,7 +122,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
|
||||||
return remoteIp ??
|
return remoteIp ??
|
||||||
(remoteIp = (CheckBadChars(XForwardedFor)) ??
|
(remoteIp = (CheckBadChars(XForwardedFor)) ??
|
||||||
(NormalizeIp(CheckBadChars(XRealIp)) ??
|
(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
|
set
|
||||||
{
|
{
|
||||||
this.responseContentType = value;
|
this.responseContentType = value;
|
||||||
HasExplicitResponseContentType = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public const string FormUrlEncoded = "application/x-www-form-urlencoded";
|
public const string FormUrlEncoded = "application/x-www-form-urlencoded";
|
||||||
public const string MultiPartFormData = "multipart/form-data";
|
public const string MultiPartFormData = "multipart/form-data";
|
||||||
private static string GetResponseContentType(IRequest httpReq)
|
public static string GetResponseContentType(IRequest httpReq)
|
||||||
{
|
{
|
||||||
var specifiedContentType = GetQueryStringContentType(httpReq);
|
var specifiedContentType = GetQueryStringContentType(httpReq);
|
||||||
if (!string.IsNullOrEmpty(specifiedContentType)) return specifiedContentType;
|
if (!string.IsNullOrEmpty(specifiedContentType)) return specifiedContentType;
|
||||||
|
@ -346,8 +359,6 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
|
||||||
: strVal.Substring(0, pos);
|
: strVal.Substring(0, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasExplicitResponseContentType { get; private set; }
|
|
||||||
|
|
||||||
public static string HandlerFactoryPath;
|
public static string HandlerFactoryPath;
|
||||||
|
|
||||||
private string pathInfo;
|
private string pathInfo;
|
||||||
|
@ -490,13 +501,6 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
|
||||||
get { return HttpMethod; }
|
get { return HttpMethod; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Param(string name)
|
|
||||||
{
|
|
||||||
return Headers[name]
|
|
||||||
?? QueryString[name]
|
|
||||||
?? FormData[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ContentType
|
public string ContentType
|
||||||
{
|
{
|
||||||
get { return request.ContentType; }
|
get { return request.ContentType; }
|
||||||
|
@ -584,18 +588,6 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
|
||||||
return stream;
|
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)
|
public static string NormalizePathInfo(string pathInfo, string handlerPath)
|
||||||
{
|
{
|
||||||
if (handlerPath != null && pathInfo.TrimStart('/').StartsWith(
|
if (handlerPath != null && pathInfo.TrimStart('/').StartsWith(
|
||||||
|
|
|
@ -29,7 +29,6 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
|
||||||
}
|
}
|
||||||
|
|
||||||
public IRequest Request { get; private set; }
|
public IRequest Request { get; private set; }
|
||||||
public bool UseBufferedStream { get; set; }
|
|
||||||
public Dictionary<string, object> Items { get; private set; }
|
public Dictionary<string, object> Items { get; private set; }
|
||||||
public object OriginalResponse
|
public object OriginalResponse
|
||||||
{
|
{
|
||||||
|
|
|
@ -43,7 +43,7 @@ namespace Emby.Server.Implementations
|
||||||
IJsonSerializer json,
|
IJsonSerializer json,
|
||||||
IXmlSerializer xml,
|
IXmlSerializer xml,
|
||||||
IEnvironmentInfo environment,
|
IEnvironmentInfo environment,
|
||||||
ICertificate certificate,
|
X509Certificate certificate,
|
||||||
IFileSystem fileSystem,
|
IFileSystem fileSystem,
|
||||||
bool enableDualModeSockets)
|
bool enableDualModeSockets)
|
||||||
{
|
{
|
||||||
|
@ -63,7 +63,6 @@ namespace Emby.Server.Implementations
|
||||||
xml,
|
xml,
|
||||||
environment,
|
environment,
|
||||||
certificate,
|
certificate,
|
||||||
new StreamFactory(),
|
|
||||||
GetParseFn,
|
GetParseFn,
|
||||||
enableDualModeSockets,
|
enableDualModeSockets,
|
||||||
fileSystem);
|
fileSystem);
|
||||||
|
@ -74,37 +73,4 @@ namespace Emby.Server.Implementations
|
||||||
return s => JsvReader.GetParseFn(propertyType)(s);
|
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; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,63 +89,6 @@ namespace Emby.Server.Implementations.Net
|
||||||
Socket.Bind(nativeEndpoint);
|
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()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Socket.Dispose();
|
Socket.Dispose();
|
||||||
|
|
|
@ -45,10 +45,15 @@ namespace Emby.Server.Implementations.Services
|
||||||
var bytesResponse = this.Response as byte[];
|
var bytesResponse = this.Response as byte[];
|
||||||
if (bytesResponse != null)
|
if (bytesResponse != null)
|
||||||
{
|
{
|
||||||
if (response != null)
|
var contentLength = bytesResponse.Length;
|
||||||
response.SetContentLength(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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,11 +41,11 @@ namespace Emby.Server.Implementations.Services
|
||||||
|
|
||||||
response.StatusCode = httpResult.Status;
|
response.StatusCode = httpResult.Status;
|
||||||
response.StatusDescription = httpResult.StatusCode.ToString();
|
response.StatusDescription = httpResult.StatusCode.ToString();
|
||||||
if (string.IsNullOrEmpty(httpResult.ContentType))
|
//if (string.IsNullOrEmpty(httpResult.ContentType))
|
||||||
{
|
//{
|
||||||
httpResult.ContentType = defaultContentType;
|
// httpResult.ContentType = defaultContentType;
|
||||||
}
|
//}
|
||||||
response.ContentType = httpResult.ContentType;
|
//response.ContentType = httpResult.ContentType;
|
||||||
|
|
||||||
if (httpResult.Cookies != null)
|
if (httpResult.Cookies != null)
|
||||||
{
|
{
|
||||||
|
@ -124,7 +124,10 @@ namespace Emby.Server.Implementations.Services
|
||||||
response.ContentType = "application/octet-stream";
|
response.ContentType = "application/octet-stream";
|
||||||
response.SetContentLength(bytes.Length);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +136,10 @@ namespace Emby.Server.Implementations.Services
|
||||||
{
|
{
|
||||||
bytes = Encoding.UTF8.GetBytes(responseText);
|
bytes = Encoding.UTF8.GetBytes(responseText);
|
||||||
response.SetContentLength(bytes.Length);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,8 +156,15 @@ namespace Emby.Server.Implementations.Services
|
||||||
serializer(result, ms);
|
serializer(result, ms);
|
||||||
|
|
||||||
ms.Position = 0;
|
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);
|
//serializer(result, outputStream);
|
||||||
|
|
|
@ -162,7 +162,11 @@ namespace Emby.Server.Implementations.Services
|
||||||
if (RequireqRequestStream(requestType))
|
if (RequireqRequestStream(requestType))
|
||||||
{
|
{
|
||||||
// Used by IRequiresRequestStream
|
// 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);
|
var requestParams = GetFlattenedRequestParams(httpReq);
|
||||||
|
@ -176,16 +180,6 @@ namespace Emby.Server.Implementations.Services
|
||||||
return requiresRequestStreamTypeInfo.IsAssignableFrom(requestType.GetTypeInfo());
|
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)
|
public static object CreateRequest(HttpListenerHost host, IRequest httpReq, RestPath restPath, Dictionary<string, string> requestParams)
|
||||||
{
|
{
|
||||||
var requestDto = CreateContentTypeRequest(host, httpReq, restPath.RequestType, httpReq.ContentType);
|
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);
|
var values = formData.GetValues(name);
|
||||||
if (values.Count == 1)
|
if (values.Count == 1)
|
||||||
{
|
|
||||||
map[name] = values[0];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (var i = 0; i < values.Count; i++)
|
|
||||||
{
|
{
|
||||||
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];
|
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
|
foreach (var name in formData.Keys)
|
||||||
map[name] = request.FormData[name];
|
{
|
||||||
|
if (name == null) continue; //thank you ASP.NET
|
||||||
|
map[name] = formData[name];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,6 @@ namespace MediaBrowser.Model.Net
|
||||||
void Listen(int backlog);
|
void Listen(int backlog);
|
||||||
void Bind(IpEndPointInfo endpoint);
|
void Bind(IpEndPointInfo endpoint);
|
||||||
void Connect(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
|
public class SocketCreateException : Exception
|
||||||
|
|
|
@ -48,11 +48,6 @@ namespace MediaBrowser.Model.Services
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string ResponseContentType { get; set; }
|
string ResponseContentType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the ResponseContentType has been explicitly overrided or whether it was just the default
|
|
||||||
/// </summary>
|
|
||||||
bool HasExplicitResponseContentType { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attach any data to this request that all filters and services can access.
|
/// Attach any data to this request that all filters and services can access.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
[assembly: AssemblyVersion("3.2.30.5")]
|
[assembly: AssemblyVersion("3.2.30.6")]
|
||||||
|
|
|
@ -3,6 +3,8 @@ using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using MediaBrowser.Model.Cryptography;
|
using MediaBrowser.Model.Cryptography;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
@ -11,37 +13,37 @@ using MediaBrowser.Model.Net;
|
||||||
using MediaBrowser.Model.System;
|
using MediaBrowser.Model.System;
|
||||||
using MediaBrowser.Model.Text;
|
using MediaBrowser.Model.Text;
|
||||||
using SocketHttpListener.Primitives;
|
using SocketHttpListener.Primitives;
|
||||||
|
using ProtocolType = MediaBrowser.Model.Net.ProtocolType;
|
||||||
|
using SocketType = MediaBrowser.Model.Net.SocketType;
|
||||||
|
|
||||||
namespace SocketHttpListener.Net
|
namespace SocketHttpListener.Net
|
||||||
{
|
{
|
||||||
sealed class EndPointListener
|
sealed class EndPointListener
|
||||||
{
|
{
|
||||||
HttpListener listener;
|
HttpListener listener;
|
||||||
IpEndPointInfo endpoint;
|
IPEndPoint endpoint;
|
||||||
IAcceptSocket sock;
|
Socket sock;
|
||||||
Dictionary<ListenerPrefix,HttpListener> prefixes; // Dictionary <ListenerPrefix, HttpListener>
|
Dictionary<ListenerPrefix, HttpListener> prefixes; // Dictionary <ListenerPrefix, HttpListener>
|
||||||
List<ListenerPrefix> unhandled; // List<ListenerPrefix> unhandled; host = '*'
|
List<ListenerPrefix> unhandled; // List<ListenerPrefix> unhandled; host = '*'
|
||||||
List<ListenerPrefix> all; // List<ListenerPrefix> all; host = '+'
|
List<ListenerPrefix> all; // List<ListenerPrefix> all; host = '+'
|
||||||
ICertificate cert;
|
X509Certificate cert;
|
||||||
bool secure;
|
bool secure;
|
||||||
Dictionary<HttpConnection, HttpConnection> unregistered;
|
Dictionary<HttpConnection, HttpConnection> unregistered;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private bool _closed;
|
private bool _closed;
|
||||||
private bool _enableDualMode;
|
private bool _enableDualMode;
|
||||||
private readonly ICryptoProvider _cryptoProvider;
|
private readonly ICryptoProvider _cryptoProvider;
|
||||||
private readonly IStreamFactory _streamFactory;
|
|
||||||
private readonly ISocketFactory _socketFactory;
|
private readonly ISocketFactory _socketFactory;
|
||||||
private readonly ITextEncoding _textEncoding;
|
private readonly ITextEncoding _textEncoding;
|
||||||
private readonly IMemoryStreamFactory _memoryStreamFactory;
|
private readonly IMemoryStreamFactory _memoryStreamFactory;
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly IEnvironmentInfo _environment;
|
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;
|
this.listener = listener;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_cryptoProvider = cryptoProvider;
|
_cryptoProvider = cryptoProvider;
|
||||||
_streamFactory = streamFactory;
|
|
||||||
_socketFactory = socketFactory;
|
_socketFactory = socketFactory;
|
||||||
_memoryStreamFactory = memoryStreamFactory;
|
_memoryStreamFactory = memoryStreamFactory;
|
||||||
_textEncoding = textEncoding;
|
_textEncoding = textEncoding;
|
||||||
|
@ -51,8 +53,8 @@ namespace SocketHttpListener.Net
|
||||||
this.secure = secure;
|
this.secure = secure;
|
||||||
this.cert = cert;
|
this.cert = cert;
|
||||||
|
|
||||||
_enableDualMode = addr.Equals(IpAddressInfo.IPv6Any);
|
_enableDualMode = addr.Equals(IPAddress.IPv6Any);
|
||||||
endpoint = new IpEndPointInfo(addr, port);
|
endpoint = new IPEndPoint(addr, port);
|
||||||
|
|
||||||
prefixes = new Dictionary<ListenerPrefix, HttpListener>();
|
prefixes = new Dictionary<ListenerPrefix, HttpListener>();
|
||||||
unregistered = new Dictionary<HttpConnection, HttpConnection>();
|
unregistered = new Dictionary<HttpConnection, HttpConnection>();
|
||||||
|
@ -72,18 +74,18 @@ namespace SocketHttpListener.Net
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode);
|
sock = CreateSocket(endpoint.Address.AddressFamily, _enableDualMode);
|
||||||
}
|
}
|
||||||
catch (SocketCreateException ex)
|
catch (SocketCreateException ex)
|
||||||
{
|
{
|
||||||
if (_enableDualMode && endpoint.IpAddress.Equals(IpAddressInfo.IPv6Any) &&
|
if (_enableDualMode && endpoint.Address.Equals(IPAddress.IPv6Any) &&
|
||||||
(string.Equals(ex.ErrorCode, "AddressFamilyNotSupported", StringComparison.OrdinalIgnoreCase) ||
|
(string.Equals(ex.ErrorCode, "AddressFamilyNotSupported", StringComparison.OrdinalIgnoreCase) ||
|
||||||
// mono on bsd is throwing this
|
// mono on bsd is throwing this
|
||||||
string.Equals(ex.ErrorCode, "ProtocolNotSupported", StringComparison.OrdinalIgnoreCase)))
|
string.Equals(ex.ErrorCode, "ProtocolNotSupported", StringComparison.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
endpoint = new IpEndPointInfo(IpAddressInfo.Any, endpoint.Port);
|
endpoint = new IPEndPoint(IPAddress.Any, endpoint.Port);
|
||||||
_enableDualMode = false;
|
_enableDualMode = false;
|
||||||
sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode);
|
sock = CreateSocket(endpoint.Address.AddressFamily, _enableDualMode);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -96,11 +98,42 @@ namespace SocketHttpListener.Net
|
||||||
// This is the number TcpListener uses.
|
// This is the number TcpListener uses.
|
||||||
sock.Listen(2147483647);
|
sock.Listen(2147483647);
|
||||||
|
|
||||||
sock.StartAccept(ProcessAccept, () => _closed);
|
new SocketAcceptor(_logger, sock, ProcessAccept, () => _closed).StartAccept();
|
||||||
_closed = false;
|
_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
|
try
|
||||||
{
|
{
|
||||||
|
@ -112,7 +145,7 @@ namespace SocketHttpListener.Net
|
||||||
return;
|
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);
|
//_logger.Debug("Adding unregistered connection to {0}. Id: {1}", accepted.RemoteEndPoint, connectionId);
|
||||||
lock (listener.unregistered)
|
lock (listener.unregistered)
|
||||||
|
|
|
@ -66,25 +66,25 @@ namespace SocketHttpListener.Net
|
||||||
epl.AddPrefix(lp, listener);
|
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)
|
static async Task<EndPointListener> GetEPListener(ILogger logger, string host, int port, HttpListener listener, bool secure)
|
||||||
{
|
{
|
||||||
var networkManager = listener.NetworkManager;
|
var networkManager = listener.NetworkManager;
|
||||||
|
|
||||||
IpAddressInfo addr;
|
IPAddress addr;
|
||||||
if (host == "*" || host == "+")
|
if (host == "*" || host == "+")
|
||||||
addr = GetIpAnyAddress(listener);
|
addr = GetIpAnyAddress(listener);
|
||||||
else if (networkManager.TryParseIpAddress(host, out addr) == false)
|
else if (IPAddress.TryParse(host, out addr) == false)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var all = (await networkManager.GetHostAddressesAsync(host).ConfigureAwait(false));
|
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);
|
GetIpAnyAddress(listener);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
@ -94,10 +94,10 @@ namespace SocketHttpListener.Net
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary<int, EndPointListener> p = null; // Dictionary<int, EndPointListener>
|
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>();
|
p = new Dictionary<int, EndPointListener>();
|
||||||
ip_to_endpoints[addr.Address] = p;
|
ip_to_endpoints[addr.ToString()] = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
EndPointListener epl = null;
|
EndPointListener epl = null;
|
||||||
|
@ -107,25 +107,25 @@ namespace SocketHttpListener.Net
|
||||||
}
|
}
|
||||||
else
|
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;
|
p[port] = epl;
|
||||||
}
|
}
|
||||||
|
|
||||||
return epl;
|
return epl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RemoveEndPoint(EndPointListener epl, IpEndPointInfo ep)
|
public static void RemoveEndPoint(EndPointListener epl, IPEndPoint ep)
|
||||||
{
|
{
|
||||||
lock (ip_to_endpoints)
|
lock (ip_to_endpoints)
|
||||||
{
|
{
|
||||||
// Dictionary<int, EndPointListener> p
|
// Dictionary<int, EndPointListener> p
|
||||||
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);
|
p.Remove(ep.Port);
|
||||||
if (p.Count == 0)
|
if (p.Count == 0)
|
||||||
{
|
{
|
||||||
ip_to_endpoints.Remove(ep.IpAddress.Address);
|
ip_to_endpoints.Remove(ep.Address.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
epl.Close();
|
epl.Close();
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Security;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Model.Cryptography;
|
using MediaBrowser.Model.Cryptography;
|
||||||
|
@ -16,7 +20,7 @@ namespace SocketHttpListener.Net
|
||||||
{
|
{
|
||||||
private static AsyncCallback s_onreadCallback = new AsyncCallback(OnRead);
|
private static AsyncCallback s_onreadCallback = new AsyncCallback(OnRead);
|
||||||
const int BufferSize = 8192;
|
const int BufferSize = 8192;
|
||||||
IAcceptSocket _socket;
|
Socket _socket;
|
||||||
Stream _stream;
|
Stream _stream;
|
||||||
EndPointListener _epl;
|
EndPointListener _epl;
|
||||||
MemoryStream _memoryStream;
|
MemoryStream _memoryStream;
|
||||||
|
@ -31,21 +35,20 @@ namespace SocketHttpListener.Net
|
||||||
bool _contextBound;
|
bool _contextBound;
|
||||||
bool secure;
|
bool secure;
|
||||||
int _timeout = 300000; // 90k ms for first request, 15k ms from then on
|
int _timeout = 300000; // 90k ms for first request, 15k ms from then on
|
||||||
IpEndPointInfo local_ep;
|
IPEndPoint local_ep;
|
||||||
HttpListener _lastListener;
|
HttpListener _lastListener;
|
||||||
int[] client_cert_errors;
|
int[] client_cert_errors;
|
||||||
ICertificate cert;
|
X509Certificate cert;
|
||||||
Stream ssl_stream;
|
SslStream ssl_stream;
|
||||||
|
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly ICryptoProvider _cryptoProvider;
|
private readonly ICryptoProvider _cryptoProvider;
|
||||||
private readonly IMemoryStreamFactory _memoryStreamFactory;
|
private readonly IMemoryStreamFactory _memoryStreamFactory;
|
||||||
private readonly ITextEncoding _textEncoding;
|
private readonly ITextEncoding _textEncoding;
|
||||||
private readonly IStreamFactory _streamFactory;
|
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly IEnvironmentInfo _environment;
|
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;
|
_logger = logger;
|
||||||
this._socket = socket;
|
this._socket = socket;
|
||||||
|
@ -57,14 +60,13 @@ namespace SocketHttpListener.Net
|
||||||
_textEncoding = textEncoding;
|
_textEncoding = textEncoding;
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
_environment = environment;
|
_environment = environment;
|
||||||
_streamFactory = streamFactory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task InitStream()
|
private async Task InitStream()
|
||||||
{
|
{
|
||||||
if (secure == false)
|
if (secure == false)
|
||||||
{
|
{
|
||||||
_stream = _streamFactory.CreateNetworkStream(_socket, false);
|
_stream = new SocketStream(_socket, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -81,16 +83,16 @@ namespace SocketHttpListener.Net
|
||||||
//});
|
//});
|
||||||
//_stream = ssl_stream.AuthenticatedStream;
|
//_stream = ssl_stream.AuthenticatedStream;
|
||||||
|
|
||||||
ssl_stream = _streamFactory.CreateSslStream(_streamFactory.CreateNetworkStream(_socket, false), false);
|
ssl_stream = new SslStream(new SocketStream(_socket, false), false);
|
||||||
await _streamFactory.AuthenticateSslStreamAsServer(ssl_stream, cert).ConfigureAwait(false);
|
await ssl_stream.AuthenticateAsServerAsync(cert).ConfigureAwait(false);
|
||||||
_stream = ssl_stream;
|
_stream = ssl_stream;
|
||||||
}
|
}
|
||||||
Init();
|
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);
|
await connection.InitStream().ConfigureAwait(false);
|
||||||
|
|
||||||
|
@ -134,21 +136,21 @@ namespace SocketHttpListener.Net
|
||||||
get { return _reuses; }
|
get { return _reuses; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public IpEndPointInfo LocalEndPoint
|
public IPEndPoint LocalEndPoint
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (local_ep != null)
|
if (local_ep != null)
|
||||||
return local_ep;
|
return local_ep;
|
||||||
|
|
||||||
local_ep = (IpEndPointInfo)_socket.LocalEndPoint;
|
local_ep = (IPEndPoint)_socket.LocalEndPoint;
|
||||||
return local_ep;
|
return local_ep;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IpEndPointInfo RemoteEndPoint
|
public IPEndPoint RemoteEndPoint
|
||||||
{
|
{
|
||||||
get { return (IpEndPointInfo)_socket.RemoteEndPoint; }
|
get { return _socket.RemoteEndPoint as IPEndPoint; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsSecure
|
public bool IsSecure
|
||||||
|
@ -513,12 +515,12 @@ namespace SocketHttpListener.Net
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IAcceptSocket s = _socket;
|
Socket s = _socket;
|
||||||
_socket = null;
|
_socket = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (s != null)
|
if (s != null)
|
||||||
s.Shutdown(true);
|
s.Shutdown(SocketShutdown.Both);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Model.Cryptography;
|
using MediaBrowser.Model.Cryptography;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
@ -17,7 +18,6 @@ namespace SocketHttpListener.Net
|
||||||
public sealed class HttpListener : IDisposable
|
public sealed class HttpListener : IDisposable
|
||||||
{
|
{
|
||||||
internal ICryptoProvider CryptoProvider { get; private set; }
|
internal ICryptoProvider CryptoProvider { get; private set; }
|
||||||
internal IStreamFactory StreamFactory { get; private set; }
|
|
||||||
internal ISocketFactory SocketFactory { get; private set; }
|
internal ISocketFactory SocketFactory { get; private set; }
|
||||||
internal IFileSystem FileSystem { get; private set; }
|
internal IFileSystem FileSystem { get; private set; }
|
||||||
internal ITextEncoding TextEncoding { get; private set; }
|
internal ITextEncoding TextEncoding { get; private set; }
|
||||||
|
@ -38,15 +38,14 @@ namespace SocketHttpListener.Net
|
||||||
Dictionary<HttpListenerContext, HttpListenerContext> registry; // Dictionary<HttpListenerContext,HttpListenerContext>
|
Dictionary<HttpListenerContext, HttpListenerContext> registry; // Dictionary<HttpListenerContext,HttpListenerContext>
|
||||||
Dictionary<HttpConnection, HttpConnection> connections;
|
Dictionary<HttpConnection, HttpConnection> connections;
|
||||||
private ILogger _logger;
|
private ILogger _logger;
|
||||||
private ICertificate _certificate;
|
private X509Certificate _certificate;
|
||||||
|
|
||||||
public Action<HttpListenerContext> OnContext { get; set; }
|
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;
|
_logger = logger;
|
||||||
CryptoProvider = cryptoProvider;
|
CryptoProvider = cryptoProvider;
|
||||||
StreamFactory = streamFactory;
|
|
||||||
SocketFactory = socketFactory;
|
SocketFactory = socketFactory;
|
||||||
NetworkManager = networkManager;
|
NetworkManager = networkManager;
|
||||||
TextEncoding = textEncoding;
|
TextEncoding = textEncoding;
|
||||||
|
@ -59,18 +58,18 @@ namespace SocketHttpListener.Net
|
||||||
auth_schemes = AuthenticationSchemes.Anonymous;
|
auth_schemes = AuthenticationSchemes.Anonymous;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpListener(ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
|
public HttpListener(X509Certificate certificate, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
|
||||||
:this(new NullLogger(), certificate, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, 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)
|
public HttpListener(ILogger logger, X509Certificate certificate, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
|
||||||
: this(logger, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo)
|
: this(logger, cryptoProvider, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo)
|
||||||
{
|
{
|
||||||
_certificate = certificate;
|
_certificate = certificate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadCert(ICertificate cert)
|
public void LoadCert(X509Certificate cert)
|
||||||
{
|
{
|
||||||
_certificate = cert;
|
_certificate = cert;
|
||||||
}
|
}
|
||||||
|
@ -150,7 +149,7 @@ namespace SocketHttpListener.Net
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
internal ICertificate Certificate
|
internal X509Certificate Certificate
|
||||||
{
|
{
|
||||||
get { return _certificate; }
|
get { return _certificate; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Specialized;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Model.Net;
|
using MediaBrowser.Model.Net;
|
||||||
|
@ -513,7 +514,14 @@ namespace SocketHttpListener.Net
|
||||||
|
|
||||||
public bool IsLocal
|
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
|
public bool IsSecureConnection
|
||||||
|
@ -557,7 +565,7 @@ namespace SocketHttpListener.Net
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IpEndPointInfo LocalEndPoint
|
public IPEndPoint LocalEndPoint
|
||||||
{
|
{
|
||||||
get { return context.Connection.LocalEndPoint; }
|
get { return context.Connection.LocalEndPoint; }
|
||||||
}
|
}
|
||||||
|
@ -577,7 +585,7 @@ namespace SocketHttpListener.Net
|
||||||
get { return raw_url; }
|
get { return raw_url; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public IpEndPointInfo RemoteEndPoint
|
public IPEndPoint RemoteEndPoint
|
||||||
{
|
{
|
||||||
get { return context.Connection.RemoteEndPoint; }
|
get { return context.Connection.RemoteEndPoint; }
|
||||||
}
|
}
|
||||||
|
@ -651,10 +659,5 @@ namespace SocketHttpListener.Net
|
||||||
return _websocketRequest;
|
return _websocketRequest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ICertificate> GetClientCertificateAsync()
|
|
||||||
{
|
|
||||||
return Task.FromResult<ICertificate>(null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,13 +51,13 @@ namespace SocketHttpListener.Net
|
||||||
private bool _trailer_sent;
|
private bool _trailer_sent;
|
||||||
private Stream _stream;
|
private Stream _stream;
|
||||||
private readonly IMemoryStreamFactory _memoryStreamFactory;
|
private readonly IMemoryStreamFactory _memoryStreamFactory;
|
||||||
private readonly IAcceptSocket _socket;
|
private readonly Socket _socket;
|
||||||
private readonly bool _supportsDirectSocketAccess;
|
private readonly bool _supportsDirectSocketAccess;
|
||||||
private readonly IEnvironmentInfo _environment;
|
private readonly IEnvironmentInfo _environment;
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly ILogger _logger;
|
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;
|
_response = response;
|
||||||
_ignore_errors = ignore_errors;
|
_ignore_errors = ignore_errors;
|
||||||
|
@ -289,64 +289,9 @@ namespace SocketHttpListener.Net
|
||||||
|
|
||||||
public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
|
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);
|
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;
|
const int StreamCopyToBufferSize = 81920;
|
||||||
private async Task TransmitFileManaged(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
|
private async Task TransmitFileManaged(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace SocketHttpListener.Net
|
||||||
ushort port;
|
ushort port;
|
||||||
string path;
|
string path;
|
||||||
bool secure;
|
bool secure;
|
||||||
IpAddressInfo[] addresses;
|
IPAddress[] addresses;
|
||||||
public HttpListener Listener;
|
public HttpListener Listener;
|
||||||
|
|
||||||
public ListenerPrefix(string prefix)
|
public ListenerPrefix(string prefix)
|
||||||
|
@ -25,7 +25,7 @@ namespace SocketHttpListener.Net
|
||||||
return original;
|
return original;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IpAddressInfo[] Addresses
|
public IPAddress[] Addresses
|
||||||
{
|
{
|
||||||
get { return addresses; }
|
get { return addresses; }
|
||||||
set { addresses = value; }
|
set { addresses = value; }
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using MediaBrowser.Model.Net;
|
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.Net
|
namespace SocketHttpListener.Net
|
||||||
{
|
{
|
||||||
public class SocketAcceptor
|
public class SocketAcceptor
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly Socket _originalSocket;
|
private readonly Socket _originalSocket;
|
||||||
private readonly Func<bool> _isClosed;
|
private readonly Func<bool> _isClosed;
|
||||||
private readonly Action<IAcceptSocket> _onAccept;
|
private readonly Action<Socket> _onAccept;
|
||||||
private readonly bool _isDualMode;
|
|
||||||
|
|
||||||
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)
|
if (logger == null)
|
||||||
{
|
{
|
||||||
|
@ -35,7 +33,6 @@ namespace Emby.Server.Implementations.Net
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_originalSocket = originalSocket;
|
_originalSocket = originalSocket;
|
||||||
_isClosed = isClosed;
|
_isClosed = isClosed;
|
||||||
_isDualMode = isDualMode;
|
|
||||||
_onAccept = onAccept;
|
_onAccept = onAccept;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +114,7 @@ namespace Emby.Server.Implementations.Net
|
||||||
if (acceptSocket != null)
|
if (acceptSocket != null)
|
||||||
{
|
{
|
||||||
//ProcessAccept(acceptSocket);
|
//ProcessAccept(acceptSocket);
|
||||||
_onAccept(new NetAcceptSocket(acceptSocket, _logger, _isDualMode));
|
_onAccept(acceptSocket);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accept the next connection request
|
// Accept the next connection request
|
|
@ -254,7 +254,7 @@ namespace SocketHttpListener.Net.WebSockets
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>
|
/// <value>
|
||||||
/// </value>
|
/// </value>
|
||||||
public override IpEndPointInfo ServerEndPoint
|
public override IPEndPoint ServerEndPoint
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
@ -281,7 +281,7 @@ namespace SocketHttpListener.Net.WebSockets
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>
|
/// <value>
|
||||||
/// </value>
|
/// </value>
|
||||||
public override IpEndPointInfo UserEndPoint
|
public override IPEndPoint UserEndPoint
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
|
|
@ -151,7 +151,7 @@ namespace SocketHttpListener.Net.WebSockets
|
||||||
/// <value>
|
/// <value>
|
||||||
/// A <see cref="System.Net.IPEndPoint"/> that represents the server endpoint.
|
/// A <see cref="System.Net.IPEndPoint"/> that represents the server endpoint.
|
||||||
/// </value>
|
/// </value>
|
||||||
public abstract IpEndPointInfo ServerEndPoint { get; }
|
public abstract IPEndPoint ServerEndPoint { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the client information (identity, authentication, and security roles).
|
/// Gets the client information (identity, authentication, and security roles).
|
||||||
|
@ -167,7 +167,7 @@ namespace SocketHttpListener.Net.WebSockets
|
||||||
/// <value>
|
/// <value>
|
||||||
/// A <see cref="System.Net.IPEndPoint"/> that represents the client endpoint.
|
/// A <see cref="System.Net.IPEndPoint"/> that represents the client endpoint.
|
||||||
/// </value>
|
/// </value>
|
||||||
public abstract IpEndPointInfo UserEndPoint { get; }
|
public abstract IPEndPoint UserEndPoint { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="SocketHttpListener.WebSocket"/> instance used for two-way communication
|
/// Gets the <see cref="SocketHttpListener.WebSocket"/> instance used for two-way communication
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace SocketHttpListener.Primitives
|
|
||||||
{
|
|
||||||
public interface ICertificate
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -82,6 +82,7 @@
|
||||||
<Compile Include="Net\HttpStreamAsyncResult.cs" />
|
<Compile Include="Net\HttpStreamAsyncResult.cs" />
|
||||||
<Compile Include="Net\HttpVersion.cs" />
|
<Compile Include="Net\HttpVersion.cs" />
|
||||||
<Compile Include="Net\ListenerPrefix.cs" />
|
<Compile Include="Net\ListenerPrefix.cs" />
|
||||||
|
<Compile Include="Net\SocketAcceptor.cs" />
|
||||||
<Compile Include="Net\UriScheme.cs" />
|
<Compile Include="Net\UriScheme.cs" />
|
||||||
<Compile Include="Net\WebHeaderCollection.cs" />
|
<Compile Include="Net\WebHeaderCollection.cs" />
|
||||||
<Compile Include="Net\WebHeaderEncoding.cs" />
|
<Compile Include="Net\WebHeaderEncoding.cs" />
|
||||||
|
@ -89,11 +90,10 @@
|
||||||
<Compile Include="Net\WebSockets\WebSocketContext.cs" />
|
<Compile Include="Net\WebSockets\WebSocketContext.cs" />
|
||||||
<Compile Include="Opcode.cs" />
|
<Compile Include="Opcode.cs" />
|
||||||
<Compile Include="PayloadData.cs" />
|
<Compile Include="PayloadData.cs" />
|
||||||
<Compile Include="Primitives\ICertificate.cs" />
|
|
||||||
<Compile Include="Primitives\IStreamFactory.cs" />
|
|
||||||
<Compile Include="Primitives\ITextEncoding.cs" />
|
<Compile Include="Primitives\ITextEncoding.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Rsv.cs" />
|
<Compile Include="Rsv.cs" />
|
||||||
|
<Compile Include="SocketStream.cs" />
|
||||||
<Compile Include="WebSocket.cs" />
|
<Compile Include="WebSocket.cs" />
|
||||||
<Compile Include="WebSocketException.cs" />
|
<Compile Include="WebSocketException.cs" />
|
||||||
<Compile Include="WebSocketFrame.cs" />
|
<Compile Include="WebSocketFrame.cs" />
|
||||||
|
|
86
SocketHttpListener/SocketStream.cs
Normal file
86
SocketHttpListener/SocketStream.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user