aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Server.Mono/SocketSharp/WebSocketSharpListener.cs
diff options
context:
space:
mode:
authorstefan <stefan@hegedues.at>2018-09-12 19:26:21 +0200
committerstefan <stefan@hegedues.at>2018-09-12 19:26:21 +0200
commit48facb797ed912e4ea6b04b17d1ff190ac2daac4 (patch)
tree8dae77a31670a888d733484cb17dd4077d5444e8 /MediaBrowser.Server.Mono/SocketSharp/WebSocketSharpListener.cs
parentc32d8656382a0eacb301692e0084377fc433ae9b (diff)
Update to 3.5.2 and .net core 2.1
Diffstat (limited to 'MediaBrowser.Server.Mono/SocketSharp/WebSocketSharpListener.cs')
-rw-r--r--MediaBrowser.Server.Mono/SocketSharp/WebSocketSharpListener.cs262
1 files changed, 262 insertions, 0 deletions
diff --git a/MediaBrowser.Server.Mono/SocketSharp/WebSocketSharpListener.cs b/MediaBrowser.Server.Mono/SocketSharp/WebSocketSharpListener.cs
new file mode 100644
index 000000000..e75a38e38
--- /dev/null
+++ b/MediaBrowser.Server.Mono/SocketSharp/WebSocketSharpListener.cs
@@ -0,0 +1,262 @@
+using MediaBrowser.Controller.Net;
+using MediaBrowser.Model.Logging;
+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;
+using MediaBrowser.Model.Cryptography;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Net;
+using MediaBrowser.Model.Services;
+using MediaBrowser.Model.System;
+using MediaBrowser.Model.Text;
+using Emby.Server.Implementations.Net;
+using Emby.Server.Implementations.HttpServer;
+
+namespace EmbyServer.SocketSharp
+{
+ public class WebSocketSharpListener : IHttpListener
+ {
+ private HttpListener _listener;
+
+ private readonly ILogger _logger;
+ private readonly X509Certificate _certificate;
+ private readonly IStreamHelper _streamHelper;
+ private readonly ITextEncoding _textEncoding;
+ private readonly INetworkManager _networkManager;
+ private readonly ISocketFactory _socketFactory;
+ private readonly ICryptoProvider _cryptoProvider;
+ private readonly IFileSystem _fileSystem;
+ private readonly bool _enableDualMode;
+ private readonly IEnvironmentInfo _environment;
+
+ private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
+ private CancellationToken _disposeCancellationToken;
+
+ public WebSocketSharpListener(ILogger logger, X509Certificate certificate, IStreamHelper streamHelper, ITextEncoding textEncoding, INetworkManager networkManager, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, bool enableDualMode, IFileSystem fileSystem, IEnvironmentInfo environment)
+ {
+ _logger = logger;
+ _certificate = certificate;
+ _streamHelper = streamHelper;
+ _textEncoding = textEncoding;
+ _networkManager = networkManager;
+ _socketFactory = socketFactory;
+ _cryptoProvider = cryptoProvider;
+ _enableDualMode = enableDualMode;
+ _fileSystem = fileSystem;
+ _environment = environment;
+
+ _disposeCancellationToken = _disposeCancellationTokenSource.Token;
+ }
+
+ public Func<Exception, IRequest, bool, bool, Task> ErrorHandler { get; set; }
+ public Func<IHttpRequest, string, string, string, CancellationToken, Task> RequestHandler { get; set; }
+
+ public Action<WebSocketConnectingEventArgs> WebSocketConnecting { get; set; }
+
+ public Action<WebSocketConnectEventArgs> WebSocketConnected { get; set; }
+
+ public void Start(IEnumerable<string> urlPrefixes)
+ {
+ if (_listener == null)
+ _listener = new HttpListener(_logger, _cryptoProvider, _socketFactory, _networkManager, _textEncoding, _streamHelper, _fileSystem, _environment);
+
+ _listener.EnableDualMode = _enableDualMode;
+
+ if (_certificate != null)
+ {
+ _listener.LoadCert(_certificate);
+ }
+
+ foreach (var prefix in urlPrefixes)
+ {
+ _logger.Info("Adding HttpListener prefix " + prefix);
+ _listener.Prefixes.Add(prefix);
+ }
+
+ _listener.OnContext = ProcessContext;
+
+ _listener.Start();
+ }
+
+ private void ProcessContext(HttpListenerContext context)
+ {
+ //InitTask(context, _disposeCancellationToken);
+ Task.Run(() => InitTask(context, _disposeCancellationToken));
+ }
+
+ private void LogRequest(ILogger logger, HttpListenerRequest request)
+ {
+ var url = request.Url.ToString();
+
+ logger.Info("{0} {1}. UserAgent: {2}", request.IsWebSocketRequest ? "WS" : "HTTP " + request.HttpMethod, url, request.UserAgent ?? string.Empty);
+ }
+
+ private Task InitTask(HttpListenerContext context, CancellationToken cancellationToken)
+ {
+ IHttpRequest httpReq = null;
+ var request = context.Request;
+
+ try
+ {
+ if (request.IsWebSocketRequest)
+ {
+ LogRequest(_logger, request);
+
+ return ProcessWebSocketRequest(context);
+ }
+
+ httpReq = GetRequest(context);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error processing request", ex);
+
+ httpReq = httpReq ?? GetRequest(context);
+ return ErrorHandler(ex, httpReq, true, true);
+ }
+
+ var uri = request.Url;
+
+ return RequestHandler(httpReq, uri.OriginalString, uri.Host, uri.LocalPath, cancellationToken);
+ }
+
+ private async Task ProcessWebSocketRequest(HttpListenerContext ctx)
+ {
+ try
+ {
+ var endpoint = ctx.Request.RemoteEndPoint.ToString();
+ var url = ctx.Request.RawUrl;
+
+ var queryString = ctx.Request.QueryString;
+
+ var connectingArgs = new WebSocketConnectingEventArgs
+ {
+ Url = url,
+ QueryString = queryString,
+ Endpoint = endpoint
+ };
+
+ if (WebSocketConnecting != null)
+ {
+ WebSocketConnecting(connectingArgs);
+ }
+
+ if (connectingArgs.AllowConnection)
+ {
+ _logger.Debug("Web socket connection allowed");
+
+ var webSocketContext = await ctx.AcceptWebSocketAsync(null).ConfigureAwait(false);
+
+ if (WebSocketConnected != null)
+ {
+ var socket = new SharpWebSocket(webSocketContext.WebSocket, _logger);
+
+ WebSocketConnected(new WebSocketConnectEventArgs
+ {
+ Url = url,
+ QueryString = queryString,
+ WebSocket = socket,
+ Endpoint = endpoint
+ });
+
+ await ReceiveWebSocket(ctx, socket).ConfigureAwait(false);
+ }
+ }
+ else
+ {
+ _logger.Warn("Web socket connection not allowed");
+ ctx.Response.StatusCode = 401;
+ ctx.Response.Close();
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("AcceptWebSocketAsync error", ex);
+ ctx.Response.StatusCode = 500;
+ ctx.Response.Close();
+ }
+ }
+
+ private async Task ReceiveWebSocket(HttpListenerContext ctx, SharpWebSocket socket)
+ {
+ try
+ {
+ await socket.StartReceive().ConfigureAwait(false);
+ }
+ finally
+ {
+ TryClose(ctx, 200);
+ }
+ }
+
+ private void TryClose(HttpListenerContext ctx, int statusCode)
+ {
+ try
+ {
+ ctx.Response.StatusCode = 200;
+ ctx.Response.Close();
+ }
+ catch (ObjectDisposedException)
+ {
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error closing web socket response", ex);
+ }
+ }
+
+ private IHttpRequest GetRequest(HttpListenerContext httpContext)
+ {
+ var urlSegments = httpContext.Request.Url.Segments;
+
+ var operationName = urlSegments[urlSegments.Length - 1];
+
+ var req = new WebSocketSharpRequest(httpContext, operationName, _logger);
+
+ return req;
+ }
+
+ public Task Stop()
+ {
+ _disposeCancellationTokenSource.Cancel();
+
+ if (_listener != null)
+ {
+ _listener.Close();
+ }
+
+ return Task.CompletedTask;
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ private bool _disposed;
+ private readonly object _disposeLock = new object();
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_disposed) return;
+
+ lock (_disposeLock)
+ {
+ if (_disposed) return;
+
+ if (disposing)
+ {
+ Stop();
+ }
+
+ //release unmanaged resources here...
+ _disposed = true;
+ }
+ }
+ }
+
+} \ No newline at end of file