From 852460b99155e015ed5f1d7ad2fab0281bfdfbec Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Mon, 25 Feb 2019 23:34:32 +0100 Subject: kestrel init --- .../SocketSharp/WebSocketSharpListener.cs | 261 +++++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs (limited to 'Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs') diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs new file mode 100644 index 000000000..ab7ddeca2 --- /dev/null +++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs @@ -0,0 +1,261 @@ +using System; +using System.Collections.Generic; + using System.Net; +using System.Threading; +using System.Threading.Tasks; +using Emby.Server.Implementations.HttpServer; +using Emby.Server.Implementations.Net; +using MediaBrowser.Controller.Net; +using MediaBrowser.Model.Services; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; + + namespace Emby.Server.Implementations.SocketSharp +{ + public class WebSocketSharpListener : IHttpListener + { + private HttpListener _listener; + + private readonly ILogger _logger; + + private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource(); + private CancellationToken _disposeCancellationToken; + + public WebSocketSharpListener( + ILogger logger) + { + _logger = logger; + + _disposeCancellationToken = _disposeCancellationTokenSource.Token; + } + + public Func ErrorHandler { get; set; } + public Func RequestHandler { get; set; } + + public Action WebSocketConnecting { get; set; } + + public Action WebSocketConnected { get; set; } + +// public void Start(IEnumerable urlPrefixes) +// { +// // TODO +// //if (_listener == null) +// //{ +// // _listener = new HttpListener(_logger, _cryptoProvider, _socketFactory, _streamHelper, _fileSystem, _environment); +// //} +// +// //_listener.EnableDualMode = _enableDualMode; +// +// //if (_certificate != null) +// //{ +// // _listener.LoadCert(_certificate); +// //} +// +// //_logger.LogInformation("Adding HttpListener prefixes {Prefixes}", urlPrefixes); +// //_listener.Prefixes.AddRange(urlPrefixes); +// +// //_listener.OnContext = async c => await InitTask(c, _disposeCancellationToken).ConfigureAwait(false); +// +// //_listener.Start(); +// +// if (_listener == null) +// { +// _listener = new HttpListener(); +// } +// +// _logger.LogInformation("Adding HttpListener prefixes {Prefixes}", urlPrefixes); +// +// //foreach (var urlPrefix in urlPrefixes) +// //{ +// // _listener.Prefixes.Add(urlPrefix); +// //} +// _listener.Prefixes.Add("http://localhost:8096/"); +// +// _listener.Start(); +// +// // TODO how to do this in netcore? +// _listener.BeginGetContext(async c => await InitTask(c, _disposeCancellationToken).ConfigureAwait(false), +// null); +// } + + private static void LogRequest(ILogger logger, HttpListenerRequest request) + { + var url = request.Url.ToString(); + + logger.LogInformation( + "{0} {1}. UserAgent: {2}", + request.IsWebSocketRequest ? "WS" : "HTTP " + request.HttpMethod, + url, + request.UserAgent ?? string.Empty); + } +// +// private Task InitTask(IAsyncResult asyncResult, CancellationToken cancellationToken) +// { +// var context = _listener.EndGetContext(asyncResult); +// _listener.BeginGetContext(async c => await InitTask(c, _disposeCancellationToken).ConfigureAwait(false), null); +// IHttpRequest httpReq = null; +// var request = context.Request; +// +// try +// { +// if (request.IsWebSocketRequest) +// { +// LogRequest(_logger, request); +// +// return ProcessWebSocketRequest(context); +// } +// +// httpReq = GetRequest(context); +// } +// catch (Exception ex) +// { +// _logger.LogError(ex, "Error processing request"); +// +// 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 = new QueryParamCollection(ctx.Request.QueryString); + + var connectingArgs = new WebSocketConnectingEventArgs + { + Url = url, + QueryString = queryString, + Endpoint = endpoint + }; + + WebSocketConnecting?.Invoke(connectingArgs); + + if (connectingArgs.AllowConnection) + { + _logger.LogDebug("Web socket connection allowed"); + + var webSocketContext = await ctx.AcceptWebSocketAsync(null).ConfigureAwait(false); + + if (WebSocketConnected != null) + { + SharpWebSocket socket = null; //new SharpWebSocket(webSocketContext.WebSocket, _logger); + await socket.ConnectAsServerAsync().ConfigureAwait(false); + + WebSocketConnected(new WebSocketConnectEventArgs + { + Url = url, + QueryString = queryString, + WebSocket = socket, + Endpoint = endpoint + }); + + await ReceiveWebSocketAsync(ctx, socket).ConfigureAwait(false); + } + } + else + { + _logger.LogWarning("Web socket connection not allowed"); + ctx.Response.StatusCode = 401; + ctx.Response.Close(); + } + } + catch (Exception ex) + { + _logger.LogError(ex, "AcceptWebSocketAsync error"); + ctx.Response.StatusCode = 500; + ctx.Response.Close(); + } + } + + private async Task ReceiveWebSocketAsync(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 = statusCode; + ctx.Response.Close(); + } + catch (ObjectDisposedException) + { + // TODO: Investigate and properly fix. + } + catch (Exception ex) + { + _logger.LogError(ex, "Error closing web socket response"); + } + } + + private IHttpRequest GetRequest(HttpRequest httpContext) + { + var urlSegments = httpContext.Path; + + var operationName = urlSegments; + + var req = new WebSocketSharpRequest(httpContext, httpContext.HttpContext.Response, operationName, _logger); + + return req; + } + + public void Start(IEnumerable urlPrefixes) + { + throw new NotImplementedException(); + } + + public Task Stop() + { + _disposeCancellationTokenSource.Cancel(); + _listener?.Close(); + + return Task.CompletedTask; + } + + /// + /// Releases the unmanaged resources and disposes of the managed resources used. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private bool _disposed; + + /// + /// Releases the unmanaged resources and disposes of the managed resources used. + /// + /// Whether or not the managed resources should be disposed + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + if (disposing) + { + Stop().GetAwaiter().GetResult(); + } + + _disposed = true; + } + } +} -- cgit v1.2.3 From f3e7bc0573e69df236ac8c565a354520dd094775 Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Tue, 26 Feb 2019 08:09:42 +0100 Subject: Replace some todos with http extensions and prepare some socket work --- Emby.Server.Implementations/ApplicationHost.cs | 122 +++++++++++---------- .../HttpServer/HttpListenerHost.cs | 7 ++ .../SocketSharp/WebSocketSharpListener.cs | 46 ++++---- .../SocketSharp/WebSocketSharpRequest.cs | 13 ++- 4 files changed, 102 insertions(+), 86 deletions(-) (limited to 'Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 56089320e..18e752e53 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -110,10 +110,12 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using ServiceStack; using HttpResponse = MediaBrowser.Model.Net.HttpResponse; using X509Certificate = System.Security.Cryptography.X509Certificates.X509Certificate; @@ -642,7 +644,12 @@ namespace Emby.Server.Implementations // await RunStartupTasks().ConfigureAwait(false); // }) .UseUrls("http://localhost:8096") - .ConfigureServices(s => s.AddRouting()) + .ConfigureServices(services => + { + services.AddRouting(); + services.AddHttpContextAccessor(); + services.TryAddSingleton(); + }) .Configure( app => { app.UseWebSockets(new WebSocketOptions { @@ -668,62 +675,63 @@ namespace Emby.Server.Implementations var ctx = request.HttpContext; if (ctx.WebSockets.IsWebSocketRequest) { - try - { - var endpoint = ctx.Request.Path.ToString(); - var url = ctx.Request.Path.ToString(); - - var queryString = new QueryParamCollection(request.Query); - - var connectingArgs = new WebSocketConnectingEventArgs - { - Url = url, - QueryString = queryString, - Endpoint = endpoint - }; - - if (connectingArgs.AllowConnection) - { - Logger.LogDebug("Web socket connection allowed"); - - var webSocketContext = ctx.WebSockets.AcceptWebSocketAsync(null).Result; - - //SharpWebSocket socket = new SharpWebSocket(webSocketContext, Logger); - //socket.ConnectAsServerAsync().ConfigureAwait(false); - -// var connection = new WebSocketConnection(webSocketContext, e.Endpoint, _jsonSerializer, _logger) -// { -// OnReceive = ProcessWebSocketMessageReceived, -// Url = e.Url, -// QueryString = e.QueryString ?? new QueryParamCollection() -// }; -// -// connection.Closed += Connection_Closed; -// -// lock (_webSocketConnections) -// { -// _webSocketConnections.Add(connection); -// } -// -// WebSocketConnected(new WebSocketConnectEventArgs -// { -// Url = url, -// QueryString = queryString, -// WebSocket = socket, -// Endpoint = endpoint -// }); - await webSocketContext.ReceiveAsync(new ArraySegment(), CancellationToken.None).ConfigureAwait(false); - } - else - { - Logger.LogWarning("Web socket connection not allowed"); - ctx.Response.StatusCode = 401; - } - } - catch (Exception ex) - { - ctx.Response.StatusCode = 500; - } + await ((HttpListenerHost)HttpServer)._websocketlistener.ProcessWebSocketRequest(ctx).ConfigureAwait(false); +// try +// { +// var endpoint = ctx.Request.Path.ToString(); +// var url = ctx.Request.Path.ToString(); + + // var queryString = new QueryParamCollection(request.Query); + + // var connectingArgs = new WebSocketConnectingEventArgs + // { + // Url = url, + // QueryString = queryString, + // Endpoint = endpoint + // }; + + // if (connectingArgs.AllowConnection) + // { + // Logger.LogDebug("Web socket connection allowed"); + + // var webSocketContext = ctx.WebSockets.AcceptWebSocketAsync(null).Result; + + // //SharpWebSocket socket = new SharpWebSocket(webSocketContext, Logger); + // //socket.ConnectAsServerAsync().ConfigureAwait(false); + + //// var connection = new WebSocketConnection(webSocketContext, e.Endpoint, _jsonSerializer, _logger) + //// { + //// OnReceive = ProcessWebSocketMessageReceived, + //// Url = e.Url, + //// QueryString = e.QueryString ?? new QueryParamCollection() + //// }; + //// + //// connection.Closed += Connection_Closed; + //// + //// lock (_webSocketConnections) + //// { + //// _webSocketConnections.Add(connection); + //// } + //// + //// WebSocketConnected(new WebSocketConnectEventArgs + //// { + //// Url = url, + //// QueryString = queryString, + //// WebSocket = socket, + //// Endpoint = endpoint + //// }); + // await webSocketContext.ReceiveAsync(new ArraySegment(), CancellationToken.None).ConfigureAwait(false); + // } + // else + // { + // Logger.LogWarning("Web socket connection not allowed"); + // ctx.Response.StatusCode = 401; + // } + // } + // catch (Exception ex) + // { + // ctx.Response.StatusCode = 500; + // } } var req = new WebSocketSharpRequest(request, response, request.Path, Logger); diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index 1bd084259..cfe0bbe97 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -11,6 +11,7 @@ using System.Threading; using System.Threading.Tasks; using Emby.Server.Implementations.Net; using Emby.Server.Implementations.Services; +using Emby.Server.Implementations.SocketSharp; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller; @@ -73,6 +74,10 @@ namespace Emby.Server.Implementations.HttpServer Instance = this; ResponseFilters = Array.Empty>(); + _websocketlistener = new WebSocketSharpListener(_logger) + { + WebSocketConnected = OnWebSocketConnected + }; } public string GlobalResponse { get; set; } @@ -796,6 +801,8 @@ namespace Emby.Server.Implementations.HttpServer private bool _disposed; private readonly object _disposeLock = new object(); + public WebSocketSharpListener _websocketlistener; + protected virtual void Dispose(bool disposing) { if (_disposed) return; diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs index ab7ddeca2..824c9a822 100644 --- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs +++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Net; using System.Threading; @@ -8,6 +8,7 @@ using Emby.Server.Implementations.Net; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.SocketSharp @@ -120,14 +121,14 @@ using Microsoft.Extensions.Logging; // return RequestHandler(httpReq, uri.OriginalString, uri.Host, uri.LocalPath, cancellationToken); // } - private async Task ProcessWebSocketRequest(HttpListenerContext ctx) + public async Task ProcessWebSocketRequest(HttpContext ctx) { try { - var endpoint = ctx.Request.RemoteEndPoint.ToString(); - var url = ctx.Request.RawUrl; + var endpoint = ctx.Connection.RemoteIpAddress.ToString(); + var url = ctx.Request.GetDisplayUrl(); - var queryString = new QueryParamCollection(ctx.Request.QueryString); + var queryString = new QueryParamCollection(ctx.Request.Query); var connectingArgs = new WebSocketConnectingEventArgs { @@ -142,40 +143,40 @@ using Microsoft.Extensions.Logging; { _logger.LogDebug("Web socket connection allowed"); - var webSocketContext = await ctx.AcceptWebSocketAsync(null).ConfigureAwait(false); + var webSocketContext = await ctx.WebSockets.AcceptWebSocketAsync(null).ConfigureAwait(false); if (WebSocketConnected != null) { - SharpWebSocket socket = null; //new SharpWebSocket(webSocketContext.WebSocket, _logger); - await socket.ConnectAsServerAsync().ConfigureAwait(false); - - WebSocketConnected(new WebSocketConnectEventArgs - { - Url = url, - QueryString = queryString, - WebSocket = socket, - Endpoint = endpoint - }); - - await ReceiveWebSocketAsync(ctx, socket).ConfigureAwait(false); + //SharpWebSocket socket = new SharpWebSocket(webSocketContext, _logger); + //await socket.ConnectAsServerAsync().ConfigureAwait(false); + + //WebSocketConnected(new WebSocketConnectEventArgs + //{ + // Url = url, + // QueryString = queryString, + // WebSocket = socket, + // Endpoint = endpoint + //}); + + //await ReceiveWebSocketAsync(ctx, socket).ConfigureAwait(false); } } else { _logger.LogWarning("Web socket connection not allowed"); ctx.Response.StatusCode = 401; - ctx.Response.Close(); + //ctx.Response.Close(); } } catch (Exception ex) { _logger.LogError(ex, "AcceptWebSocketAsync error"); ctx.Response.StatusCode = 500; - ctx.Response.Close(); + //ctx.Response.Close(); } } - private async Task ReceiveWebSocketAsync(HttpListenerContext ctx, SharpWebSocket socket) + private async Task ReceiveWebSocketAsync(HttpContext ctx, SharpWebSocket socket) { try { @@ -187,12 +188,11 @@ using Microsoft.Extensions.Logging; } } - private void TryClose(HttpListenerContext ctx, int statusCode) + private void TryClose(HttpContext ctx, int statusCode) { try { ctx.Response.StatusCode = statusCode; - ctx.Response.Close(); } catch (ObjectDisposedException) { diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs index facc54446..9c5b2b083 100644 --- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs +++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs @@ -7,6 +7,7 @@ using System.Text; using Emby.Server.Implementations.HttpServer; using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Primitives; using Microsoft.Net.Http.Headers; @@ -44,11 +45,11 @@ namespace Emby.Server.Implementations.SocketSharp public object Dto { get; set; } - public string RawUrl => request.Path.ToUriComponent(); + public string RawUrl => request.Path.ToString(); - public string AbsoluteUri => request.Path.ToUriComponent().TrimEnd('/'); + public string AbsoluteUri => request.GetDisplayUrl().TrimEnd('/'); - public string UserHostAddress => ""; + public string UserHostAddress => request.HttpContext.Connection.RemoteIpAddress.ToString(); public string XForwardedFor => StringValues.IsNullOrEmpty(request.Headers["X-Forwarded-For"]) ? null : request.Headers["X-Forwarded-For"].ToString(); @@ -66,7 +67,7 @@ namespace Emby.Server.Implementations.SocketSharp remoteIp ?? (remoteIp = CheckBadChars(XForwardedFor) ?? NormalizeIp(CheckBadChars(XRealIp) ?? - (string.IsNullOrEmpty(request.Host.Host) ? null : NormalizeIp(request.Host.Host)))); + (string.IsNullOrEmpty(request.HttpContext.Connection.RemoteIpAddress.ToString()) ? null : NormalizeIp(request.HttpContext.Connection.RemoteIpAddress.ToString())))); private static readonly char[] HttpTrimCharacters = new char[] { (char)0x09, (char)0xA, (char)0xB, (char)0xC, (char)0xD, (char)0x20 }; @@ -199,7 +200,7 @@ namespace Emby.Server.Implementations.SocketSharp const string serverDefaultContentType = "application/json"; - var acceptContentTypes = httpReq.Headers.GetCommaSeparatedValues(HeaderNames.Accept); // TODO; + var acceptContentTypes = httpReq.Headers.GetCommaSeparatedValues(HeaderNames.Accept); string defaultContentType = null; if (HasAnyOfContentTypes(httpReq, FormUrlEncoded, MultiPartFormData)) { @@ -448,7 +449,7 @@ namespace Emby.Server.Implementations.SocketSharp private QueryParamCollection queryString; public QueryParamCollection QueryString => queryString ?? (queryString = new QueryParamCollection(request.Query)); - public bool IsLocal => true; // TODO + public bool IsLocal => string.Equals(request.HttpContext.Connection.LocalIpAddress.ToString(), request.HttpContext.Connection.RemoteIpAddress.ToString()); private string httpMethod; public string HttpMethod => -- cgit v1.2.3 From d6c6f3c10cff68b11df884be502c58a17da0d332 Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Tue, 26 Feb 2019 15:13:06 +0100 Subject: Still broken --- Emby.Server.Implementations/ApplicationHost.cs | 2 +- .../Net/WebSocketConnectEventArgs.cs | 1 + .../SocketSharp/SharpWebSocket.cs | 31 ++++++-------- .../SocketSharp/WebSocketSharpListener.cs | 48 +++++++++++++++------- .../SocketSharp/WebSocketSharpListener.cs | 4 +- 5 files changed, 51 insertions(+), 35 deletions(-) (limited to 'Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index da9550b85..65b6681c8 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -740,7 +740,7 @@ namespace Emby.Server.Implementations var request = context.Request; var response = context.Response; - var localPath = context.Request.Path.ToString().TrimStart('/'); + var localPath = context.Request.Path.ToString(); var req = new WebSocketSharpRequest(request, response, request.Path, Logger); await ((HttpListenerHost)HttpServer).RequestHandler(req, request.GetDisplayUrl(), request.Host.ToString(), localPath, CancellationToken.None).ConfigureAwait(false); diff --git a/Emby.Server.Implementations/Net/WebSocketConnectEventArgs.cs b/Emby.Server.Implementations/Net/WebSocketConnectEventArgs.cs index 3ab8e854a..666f1f601 100644 --- a/Emby.Server.Implementations/Net/WebSocketConnectEventArgs.cs +++ b/Emby.Server.Implementations/Net/WebSocketConnectEventArgs.cs @@ -1,4 +1,5 @@ using System; +using System.Net.WebSockets; using MediaBrowser.Model.Services; namespace Emby.Server.Implementations.Net diff --git a/Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs b/Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs index 854d33f3a..89004ba7f 100644 --- a/Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs +++ b/Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs @@ -1,5 +1,6 @@ using System; using System.Net.WebSockets; +using System.Text; using System.Threading; using System.Threading.Tasks; using Emby.Server.Implementations.Net; @@ -20,25 +21,18 @@ namespace Emby.Server.Implementations.SocketSharp /// Gets or sets the web socket. /// /// The web socket. - private SocketHttpListener.WebSocket WebSocket { get; set; } + private WebSocket WebSocket { get; set; } private TaskCompletionSource _taskCompletionSource = new TaskCompletionSource(); private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); private bool _disposed = false; - public SharpWebSocket(SocketHttpListener.WebSocket socket, ILogger logger) + public SharpWebSocket(WebSocket socket, ILogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); WebSocket = socket ?? throw new ArgumentNullException(nameof(socket)); - - socket.OnMessage += OnSocketMessage; - socket.OnClose += OnSocketClose; - socket.OnError += OnSocketError; } - public Task ConnectAsServerAsync() - => WebSocket.ConnectAsServer(); - public Task StartReceive() { return _taskCompletionSource.Task; @@ -58,7 +52,7 @@ namespace Emby.Server.Implementations.SocketSharp Closed?.Invoke(this, EventArgs.Empty); } - private void OnSocketMessage(object sender, SocketHttpListener.MessageEventArgs e) + private void OnSocketMessage(SocketHttpListener.MessageEventArgs e) { if (OnReceiveBytes != null) { @@ -66,11 +60,15 @@ namespace Emby.Server.Implementations.SocketSharp } } + public Task ConnectAsServerAsync() + { + return Task.CompletedTask; + } /// /// Gets or sets the state. /// /// The state. - public WebSocketState State => WebSocket.ReadyState; + public WebSocketState State => WebSocket.State; /// /// Sends the async. @@ -81,7 +79,7 @@ namespace Emby.Server.Implementations.SocketSharp /// Task. public Task SendAsync(byte[] bytes, bool endOfMessage, CancellationToken cancellationToken) { - return WebSocket.SendAsync(bytes); + return WebSocket.SendAsync(new ArraySegment(bytes), WebSocketMessageType.Binary, endOfMessage, cancellationToken); } /// @@ -93,7 +91,7 @@ namespace Emby.Server.Implementations.SocketSharp /// Task. public Task SendAsync(string text, bool endOfMessage, CancellationToken cancellationToken) { - return WebSocket.SendAsync(text); + return WebSocket.SendAsync(new ArraySegment(Encoding.UTF8.GetBytes(text)), WebSocketMessageType.Text, endOfMessage, cancellationToken); } /// @@ -118,13 +116,10 @@ namespace Emby.Server.Implementations.SocketSharp if (dispose) { - WebSocket.OnMessage -= OnSocketMessage; - WebSocket.OnClose -= OnSocketClose; - WebSocket.OnError -= OnSocketError; - _cancellationTokenSource.Cancel(); - WebSocket.CloseAsync().GetAwaiter().GetResult(); + // TODO + WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "bye", CancellationToken.None).GetAwaiter().GetResult(); } _disposed = true; diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs index 824c9a822..b64fc0683 100644 --- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs +++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Net; +using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; using Emby.Server.Implementations.HttpServer; @@ -144,22 +145,41 @@ using Microsoft.Extensions.Logging; _logger.LogDebug("Web socket connection allowed"); var webSocketContext = await ctx.WebSockets.AcceptWebSocketAsync(null).ConfigureAwait(false); + var socket = new SharpWebSocket(webSocketContext, _logger); + await socket.ConnectAsServerAsync().ConfigureAwait(false); - if (WebSocketConnected != null) + WebSocketConnected(new WebSocketConnectEventArgs { - //SharpWebSocket socket = new SharpWebSocket(webSocketContext, _logger); - //await socket.ConnectAsServerAsync().ConfigureAwait(false); - - //WebSocketConnected(new WebSocketConnectEventArgs - //{ - // Url = url, - // QueryString = queryString, - // WebSocket = socket, - // Endpoint = endpoint - //}); - - //await ReceiveWebSocketAsync(ctx, socket).ConfigureAwait(false); - } + Url = url, + QueryString = queryString, + WebSocket = socket, + Endpoint = endpoint + }); + + //await ReceiveWebSocketAsync(ctx, socket).ConfigureAwait(false); + var buffer = WebSocket.CreateClientBuffer(1024 * 4, 1024 * 4); + WebSocketReceiveResult result = await webSocketContext.ReceiveAsync(buffer, CancellationToken.None); + socket.OnReceiveBytes(buffer.Array); + //while (!result.CloseStatus.HasValue) + //{ + // await webSocketContext.SendAsync(new ArraySegment(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None); + + // result = await webSocketContext.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); + //} + //WebSocketConnected?.Invoke(new WebSocketConnectEventArgs + //{ + // Url = url, + // QueryString = queryString, + // WebSocket = webSocketContext, + // Endpoint = endpoint + //}); + await webSocketContext.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); + //SharpWebSocket socket = new SharpWebSocket(webSocketContext, _logger); + //await socket.ConnectAsServerAsync().ConfigureAwait(false); + + + + //await ReceiveWebSocketAsync(ctx, socket).ConfigureAwait(false); } else { diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs index c458fdb78..4dc4103cb 100644 --- a/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs +++ b/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Net; using System.Threading; @@ -152,7 +152,7 @@ using Microsoft.Extensions.Logging; { Url = url, QueryString = queryString, - WebSocket = socket, + WebSocket = null, // socket, Endpoint = endpoint }); -- cgit v1.2.3 From 5a7cca9d1bdc5280626a6654cdbd8c0d45016af5 Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Tue, 26 Feb 2019 19:48:18 +0100 Subject: Fix websockets and RawUrl --- Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs | 2 +- .../SocketSharp/WebSocketSharpListener.cs | 13 +++++++++++-- .../SocketSharp/WebSocketSharpRequest.cs | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) (limited to 'Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs') diff --git a/Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs b/Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs index 89004ba7f..eab903db8 100644 --- a/Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs +++ b/Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs @@ -119,7 +119,7 @@ namespace Emby.Server.Implementations.SocketSharp _cancellationTokenSource.Cancel(); // TODO - WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "bye", CancellationToken.None).GetAwaiter().GetResult(); + // WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "bye", CancellationToken.None).GetAwaiter().GetResult(); } _disposed = true; diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs index b64fc0683..05f159b4e 100644 --- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs +++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs @@ -160,6 +160,15 @@ using Microsoft.Extensions.Logging; var buffer = WebSocket.CreateClientBuffer(1024 * 4, 1024 * 4); WebSocketReceiveResult result = await webSocketContext.ReceiveAsync(buffer, CancellationToken.None); socket.OnReceiveBytes(buffer.Array); + + while (result.MessageType != WebSocketMessageType.Close) + { + result = await webSocketContext.ReceiveAsync(buffer, CancellationToken.None); + socket.OnReceiveBytes(buffer.Array); + } + await webSocketContext.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); + socket.Dispose(); + //while (!result.CloseStatus.HasValue) //{ // await webSocketContext.SendAsync(new ArraySegment(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None); @@ -173,11 +182,11 @@ using Microsoft.Extensions.Logging; // WebSocket = webSocketContext, // Endpoint = endpoint //}); - await webSocketContext.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); + //await webSocketContext.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); //SharpWebSocket socket = new SharpWebSocket(webSocketContext, _logger); //await socket.ConnectAsServerAsync().ConfigureAwait(false); - + //await ReceiveWebSocketAsync(ctx, socket).ConfigureAwait(false); } diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs index 9c5b2b083..b07c4bfeb 100644 --- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs +++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs @@ -45,7 +45,7 @@ namespace Emby.Server.Implementations.SocketSharp public object Dto { get; set; } - public string RawUrl => request.Path.ToString(); + public string RawUrl => request.GetEncodedPathAndQuery(); public string AbsoluteUri => request.GetDisplayUrl().TrimEnd('/'); -- cgit v1.2.3 From a85488cd205532662c59ada5032dc81c0315543b Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Tue, 26 Feb 2019 20:13:48 +0100 Subject: Fix websockets array index out of bounds and some cleanup --- Emby.Server.Implementations/ApplicationHost.cs | 78 +--------- .../HttpServer/HttpListenerHost.cs | 7 +- .../SocketSharp/WebSocketSharpListener.cs | 166 ++------------------- 3 files changed, 24 insertions(+), 227 deletions(-) (limited to 'Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 65b6681c8..e9d8d8de7 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -624,25 +624,7 @@ namespace Emby.Server.Implementations Host = new WebHostBuilder() .UseKestrel() - .UseContentRoot(Path.Combine(Directory.GetCurrentDirectory(), @"jellyfin-web\src")) - //.UseStartup() -// .ConfigureServices(async services => -// { -// services.AddSingleton(startUp); -// RegisterResources(services); -// FindParts(); -// try -// { -// ImageProcessor.ImageEncoder = -// new NullImageEncoder(); //SkiaEncoder(_loggerFactory, appPaths, fileSystem, localizationManager); -// } -// catch (Exception ex) -// { -// Logger.LogInformation(ex, "Skia not available. Will fallback to NullIMageEncoder. {0}"); -// ImageProcessor.ImageEncoder = new NullImageEncoder(); -// } -// await RunStartupTasks().ConfigureAwait(false); -// }) + .UseContentRoot(Path.Combine(Directory.GetCurrentDirectory(), "jellyfin-web", "src")) .UseUrls("http://localhost:8096") .ConfigureServices(services => { @@ -672,63 +654,7 @@ namespace Emby.Server.Implementations return; } - await ((HttpListenerHost)HttpServer)._websocketlistener.ProcessWebSocketRequest(context).ConfigureAwait(false); - // try - // { - // var endpoint = ctx.Request.Path.ToString(); - // var url = ctx.Request.Path.ToString(); - - // var queryString = new QueryParamCollection(request.Query); - - // var connectingArgs = new WebSocketConnectingEventArgs - // { - // Url = url, - // QueryString = queryString, - // Endpoint = endpoint - // }; - - // if (connectingArgs.AllowConnection) - // { - // Logger.LogDebug("Web socket connection allowed"); - - // var webSocketContext = ctx.WebSockets.AcceptWebSocketAsync(null).Result; - - // //SharpWebSocket socket = new SharpWebSocket(webSocketContext, Logger); - // //socket.ConnectAsServerAsync().ConfigureAwait(false); - - //// var connection = new WebSocketConnection(webSocketContext, e.Endpoint, _jsonSerializer, _logger) - //// { - //// OnReceive = ProcessWebSocketMessageReceived, - //// Url = e.Url, - //// QueryString = e.QueryString ?? new QueryParamCollection() - //// }; - //// - //// connection.Closed += Connection_Closed; - //// - //// lock (_webSocketConnections) - //// { - //// _webSocketConnections.Add(connection); - //// } - //// - //// WebSocketConnected(new WebSocketConnectEventArgs - //// { - //// Url = url, - //// QueryString = queryString, - //// WebSocket = socket, - //// Endpoint = endpoint - //// }); - // await webSocketContext.ReceiveAsync(new ArraySegment(), CancellationToken.None).ConfigureAwait(false); - // } - // else - // { - // Logger.LogWarning("Web socket connection not allowed"); - // ctx.Response.StatusCode = 401; - // } - // } - // catch (Exception ex) - // { - // ctx.Response.StatusCode = 500; - // } + await ((HttpListenerHost)HttpServer).ProcessWebSocketRequest(context).ConfigureAwait(false); } public async Task ExecuteHttpHandlerAsync(HttpContext context, Func next) { diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index cfe0bbe97..a3eaa2fb5 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -21,6 +21,7 @@ using MediaBrowser.Model.Events; using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using ServiceStack.Text.Jsv; @@ -767,6 +768,10 @@ namespace Emby.Server.Implementations.HttpServer return _jsonSerializer.DeserializeFromStreamAsync(stream, type); } + public Task ProcessWebSocketRequest(HttpContext context) + { + return _websocketlistener.ProcessWebSocketRequest(context); + } //TODO Add Jellyfin Route Path Normalizer private static string NormalizeEmbyRoutePath(string path) @@ -801,7 +806,7 @@ namespace Emby.Server.Implementations.HttpServer private bool _disposed; private readonly object _disposeLock = new object(); - public WebSocketSharpListener _websocketlistener; + private readonly WebSocketSharpListener _websocketlistener; protected virtual void Dispose(bool disposing) { diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs index 05f159b4e..6e5190efd 100644 --- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs +++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; - using System.Net; +using System.Linq; +using System.Net; using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; @@ -38,94 +39,18 @@ using Microsoft.Extensions.Logging; public Action WebSocketConnected { get; set; } -// public void Start(IEnumerable urlPrefixes) -// { -// // TODO -// //if (_listener == null) -// //{ -// // _listener = new HttpListener(_logger, _cryptoProvider, _socketFactory, _streamHelper, _fileSystem, _environment); -// //} -// -// //_listener.EnableDualMode = _enableDualMode; -// -// //if (_certificate != null) -// //{ -// // _listener.LoadCert(_certificate); -// //} -// -// //_logger.LogInformation("Adding HttpListener prefixes {Prefixes}", urlPrefixes); -// //_listener.Prefixes.AddRange(urlPrefixes); -// -// //_listener.OnContext = async c => await InitTask(c, _disposeCancellationToken).ConfigureAwait(false); -// -// //_listener.Start(); -// -// if (_listener == null) -// { -// _listener = new HttpListener(); -// } -// -// _logger.LogInformation("Adding HttpListener prefixes {Prefixes}", urlPrefixes); -// -// //foreach (var urlPrefix in urlPrefixes) -// //{ -// // _listener.Prefixes.Add(urlPrefix); -// //} -// _listener.Prefixes.Add("http://localhost:8096/"); -// -// _listener.Start(); -// -// // TODO how to do this in netcore? -// _listener.BeginGetContext(async c => await InitTask(c, _disposeCancellationToken).ConfigureAwait(false), -// null); -// } - - private static void LogRequest(ILogger logger, HttpListenerRequest request) + private static void LogRequest(ILogger logger, HttpRequest request) { - var url = request.Url.ToString(); + var url = request.GetDisplayUrl(); - logger.LogInformation( - "{0} {1}. UserAgent: {2}", - request.IsWebSocketRequest ? "WS" : "HTTP " + request.HttpMethod, - url, - request.UserAgent ?? string.Empty); + logger.LogInformation("{0} {1}. UserAgent: {2}", "WS", url, request.Headers["User-Agent"].ToString()); } -// -// private Task InitTask(IAsyncResult asyncResult, CancellationToken cancellationToken) -// { -// var context = _listener.EndGetContext(asyncResult); -// _listener.BeginGetContext(async c => await InitTask(c, _disposeCancellationToken).ConfigureAwait(false), null); -// IHttpRequest httpReq = null; -// var request = context.Request; -// -// try -// { -// if (request.IsWebSocketRequest) -// { -// LogRequest(_logger, request); -// -// return ProcessWebSocketRequest(context); -// } -// -// httpReq = GetRequest(context); -// } -// catch (Exception ex) -// { -// _logger.LogError(ex, "Error processing request"); -// -// httpReq = httpReq ?? GetRequest(context); -// return ErrorHandler(ex, httpReq, true, true); -// } -// -// var uri = request.Url; -// -// return RequestHandler(httpReq, uri.OriginalString, uri.Host, uri.LocalPath, cancellationToken); -// } public async Task ProcessWebSocketRequest(HttpContext ctx) { try { + LogRequest(_logger, ctx.Request); var endpoint = ctx.Connection.RemoteIpAddress.ToString(); var url = ctx.Request.GetDisplayUrl(); @@ -156,94 +81,35 @@ using Microsoft.Extensions.Logging; Endpoint = endpoint }); - //await ReceiveWebSocketAsync(ctx, socket).ConfigureAwait(false); - var buffer = WebSocket.CreateClientBuffer(1024 * 4, 1024 * 4); - WebSocketReceiveResult result = await webSocketContext.ReceiveAsync(buffer, CancellationToken.None); - socket.OnReceiveBytes(buffer.Array); + var buffer = WebSocket.CreateClientBuffer(4096, 4096); + WebSocketReceiveResult result; + var message = new List(); - while (result.MessageType != WebSocketMessageType.Close) + do { result = await webSocketContext.ReceiveAsync(buffer, CancellationToken.None); socket.OnReceiveBytes(buffer.Array); - } - await webSocketContext.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); - socket.Dispose(); - - //while (!result.CloseStatus.HasValue) - //{ - // await webSocketContext.SendAsync(new ArraySegment(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None); - - // result = await webSocketContext.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); - //} - //WebSocketConnected?.Invoke(new WebSocketConnectEventArgs - //{ - // Url = url, - // QueryString = queryString, - // WebSocket = webSocketContext, - // Endpoint = endpoint - //}); - //await webSocketContext.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); - //SharpWebSocket socket = new SharpWebSocket(webSocketContext, _logger); - //await socket.ConnectAsServerAsync().ConfigureAwait(false); + message.AddRange(buffer.Array.Take(result.Count)); + } while (!result.EndOfMessage && result.MessageType != WebSocketMessageType.Close); - - - //await ReceiveWebSocketAsync(ctx, socket).ConfigureAwait(false); + socket.OnReceiveBytes(message.ToArray()); + await webSocketContext.CloseAsync(result.CloseStatus ?? WebSocketCloseStatus.NormalClosure, + result.CloseStatusDescription, CancellationToken.None); + socket.Dispose(); } else { _logger.LogWarning("Web socket connection not allowed"); ctx.Response.StatusCode = 401; - //ctx.Response.Close(); } } catch (Exception ex) { _logger.LogError(ex, "AcceptWebSocketAsync error"); ctx.Response.StatusCode = 500; - //ctx.Response.Close(); - } - } - - private async Task ReceiveWebSocketAsync(HttpContext ctx, SharpWebSocket socket) - { - try - { - await socket.StartReceive().ConfigureAwait(false); - } - finally - { - TryClose(ctx, 200); - } - } - - private void TryClose(HttpContext ctx, int statusCode) - { - try - { - ctx.Response.StatusCode = statusCode; - } - catch (ObjectDisposedException) - { - // TODO: Investigate and properly fix. - } - catch (Exception ex) - { - _logger.LogError(ex, "Error closing web socket response"); } } - private IHttpRequest GetRequest(HttpRequest httpContext) - { - var urlSegments = httpContext.Path; - - var operationName = urlSegments; - - var req = new WebSocketSharpRequest(httpContext, httpContext.HttpContext.Response, operationName, _logger); - - return req; - } - public void Start(IEnumerable urlPrefixes) { throw new NotImplementedException(); -- cgit v1.2.3 From 148db8b81ac4bb52262e071e6920b1449c8611fe Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Tue, 26 Feb 2019 21:51:02 +0100 Subject: Remove unused SharpSocket stuff --- .../SocketSharp/SharpWebSocket.cs | 44 +++------------------- .../SocketSharp/WebSocketSharpListener.cs | 1 - 2 files changed, 5 insertions(+), 40 deletions(-) (limited to 'Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs') diff --git a/Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs b/Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs index eab903db8..66c5cc334 100644 --- a/Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs +++ b/Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs @@ -21,7 +21,7 @@ namespace Emby.Server.Implementations.SocketSharp /// Gets or sets the web socket. /// /// The web socket. - private WebSocket WebSocket { get; set; } + private readonly WebSocket _webSocket; private TaskCompletionSource _taskCompletionSource = new TaskCompletionSource(); private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); @@ -30,45 +30,14 @@ namespace Emby.Server.Implementations.SocketSharp public SharpWebSocket(WebSocket socket, ILogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - WebSocket = socket ?? throw new ArgumentNullException(nameof(socket)); + _webSocket = socket ?? throw new ArgumentNullException(nameof(socket)); } - public Task StartReceive() - { - return _taskCompletionSource.Task; - } - - private void OnSocketError(object sender, SocketHttpListener.ErrorEventArgs e) - { - _logger.LogError("Error in SharpWebSocket: {Message}", e.Message ?? string.Empty); - - // Closed?.Invoke(this, EventArgs.Empty); - } - - private void OnSocketClose(object sender, SocketHttpListener.CloseEventArgs e) - { - _taskCompletionSource.TrySetResult(true); - - Closed?.Invoke(this, EventArgs.Empty); - } - - private void OnSocketMessage(SocketHttpListener.MessageEventArgs e) - { - if (OnReceiveBytes != null) - { - OnReceiveBytes(e.RawData); - } - } - - public Task ConnectAsServerAsync() - { - return Task.CompletedTask; - } /// /// Gets or sets the state. /// /// The state. - public WebSocketState State => WebSocket.State; + public WebSocketState State => _webSocket.State; /// /// Sends the async. @@ -79,7 +48,7 @@ namespace Emby.Server.Implementations.SocketSharp /// Task. public Task SendAsync(byte[] bytes, bool endOfMessage, CancellationToken cancellationToken) { - return WebSocket.SendAsync(new ArraySegment(bytes), WebSocketMessageType.Binary, endOfMessage, cancellationToken); + return _webSocket.SendAsync(new ArraySegment(bytes), WebSocketMessageType.Binary, endOfMessage, cancellationToken); } /// @@ -91,7 +60,7 @@ namespace Emby.Server.Implementations.SocketSharp /// Task. public Task SendAsync(string text, bool endOfMessage, CancellationToken cancellationToken) { - return WebSocket.SendAsync(new ArraySegment(Encoding.UTF8.GetBytes(text)), WebSocketMessageType.Text, endOfMessage, cancellationToken); + return _webSocket.SendAsync(new ArraySegment(Encoding.UTF8.GetBytes(text)), WebSocketMessageType.Text, endOfMessage, cancellationToken); } /// @@ -117,9 +86,6 @@ namespace Emby.Server.Implementations.SocketSharp if (dispose) { _cancellationTokenSource.Cancel(); - - // TODO - // WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "bye", CancellationToken.None).GetAwaiter().GetResult(); } _disposed = true; diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs index 6e5190efd..7a6144fb2 100644 --- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs +++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs @@ -71,7 +71,6 @@ using Microsoft.Extensions.Logging; var webSocketContext = await ctx.WebSockets.AcceptWebSocketAsync(null).ConfigureAwait(false); var socket = new SharpWebSocket(webSocketContext, _logger); - await socket.ConnectAsServerAsync().ConfigureAwait(false); WebSocketConnected(new WebSocketConnectEventArgs { -- cgit v1.2.3 From 848cfc32cc89327e16ff6ea281dc1d9b96cc4f7a Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Tue, 26 Feb 2019 22:57:59 +0100 Subject: More cleanup --- Emby.Server.Implementations/HttpServer/HttpListenerHost.cs | 1 - .../SocketSharp/WebSocketSharpListener.cs | 13 ++----------- 2 files changed, 2 insertions(+), 12 deletions(-) (limited to 'Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs') diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index 6b69fa0f4..5b1cb433a 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -803,7 +803,6 @@ namespace Emby.Server.Implementations.HttpServer private bool _disposed; private readonly object _disposeLock = new object(); - private readonly WebSocketSharpListener _websocketlistener; protected virtual void Dispose(bool disposing) { diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs index 7a6144fb2..77469244b 100644 --- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs +++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs @@ -17,8 +17,6 @@ using Microsoft.Extensions.Logging; { public class WebSocketSharpListener : IHttpListener { - private HttpListener _listener; - private readonly ILogger _logger; private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource(); @@ -86,14 +84,14 @@ using Microsoft.Extensions.Logging; do { - result = await webSocketContext.ReceiveAsync(buffer, CancellationToken.None); + result = await webSocketContext.ReceiveAsync(buffer, _disposeCancellationToken); socket.OnReceiveBytes(buffer.Array); message.AddRange(buffer.Array.Take(result.Count)); } while (!result.EndOfMessage && result.MessageType != WebSocketMessageType.Close); socket.OnReceiveBytes(message.ToArray()); await webSocketContext.CloseAsync(result.CloseStatus ?? WebSocketCloseStatus.NormalClosure, - result.CloseStatusDescription, CancellationToken.None); + result.CloseStatusDescription, _disposeCancellationToken); socket.Dispose(); } else @@ -109,16 +107,9 @@ using Microsoft.Extensions.Logging; } } - public void Start(IEnumerable urlPrefixes) - { - throw new NotImplementedException(); - } - public Task Stop() { _disposeCancellationTokenSource.Cancel(); - _listener?.Close(); - return Task.CompletedTask; } -- cgit v1.2.3 From 27e7e792b3d95912787c613f849548809d48f6b1 Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Wed, 27 Feb 2019 14:23:39 +0100 Subject: Replace some usage of QueryParamCollection --- Emby.Dlna/Api/DlnaServerService.cs | 10 +-- Emby.Dlna/ConnectionManager/ConnectionManager.cs | 3 +- Emby.Dlna/ContentDirectory/ContentDirectory.cs | 2 +- Emby.Dlna/ControlRequest.cs | 5 +- Emby.Dlna/DlnaManager.cs | 17 +++-- Emby.Dlna/IUpnpService.cs | 5 +- .../MediaReceiverRegistrar.cs | 3 +- .../HttpServer/HttpListenerHost.cs | 7 +- .../HttpServer/HttpResultFactory.cs | 19 +++-- .../HttpServer/WebSocketConnection.cs | 3 +- .../Net/WebSocketConnectEventArgs.cs | 3 +- .../Services/ServiceHandler.cs | 2 +- .../Session/SessionWebSocketListener.cs | 3 +- .../SocketSharp/RequestMono.cs | 2 - .../SocketSharp/WebSocketSharpListener.cs | 6 +- .../SocketSharp/WebSocketSharpRequest.cs | 12 ++-- .../SocketSharp/WebSocketSharpResponse.cs | 83 +--------------------- MediaBrowser.Api/Playback/BaseStreamingService.cs | 6 +- MediaBrowser.Controller/Dlna/IDlnaManager.cs | 5 +- .../Net/IWebSocketConnection.cs | 3 +- .../Net/WebSocketConnectEventArgs.cs | 6 +- MediaBrowser.Model/Services/IHttpRequest.cs | 5 -- MediaBrowser.Model/Services/IHttpResponse.cs | 12 ---- MediaBrowser.Model/Services/IRequest.cs | 21 ++---- .../Services/QueryParamCollection.cs | 20 ------ 25 files changed, 66 insertions(+), 197 deletions(-) (limited to 'Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs') diff --git a/Emby.Dlna/Api/DlnaServerService.cs b/Emby.Dlna/Api/DlnaServerService.cs index 68bf80163..8bf3797f8 100644 --- a/Emby.Dlna/Api/DlnaServerService.cs +++ b/Emby.Dlna/Api/DlnaServerService.cs @@ -136,7 +136,7 @@ namespace Emby.Dlna.Api { var url = Request.AbsoluteUri; var serverAddress = url.Substring(0, url.IndexOf("/dlna/", StringComparison.OrdinalIgnoreCase)); - var xml = _dlnaManager.GetServerDescriptionXml(Request.Headers.ToDictionary(), request.UuId, serverAddress); + var xml = _dlnaManager.GetServerDescriptionXml(Request.Headers, request.UuId, serverAddress); var cacheLength = TimeSpan.FromDays(1); var cacheKey = Request.RawUrl.GetMD5(); @@ -147,21 +147,21 @@ namespace Emby.Dlna.Api public object Get(GetContentDirectory request) { - var xml = ContentDirectory.GetServiceXml(Request.Headers.ToDictionary()); + var xml = ContentDirectory.GetServiceXml(); return _resultFactory.GetResult(Request, xml, XMLContentType); } public object Get(GetMediaReceiverRegistrar request) { - var xml = MediaReceiverRegistrar.GetServiceXml(Request.Headers.ToDictionary()); + var xml = MediaReceiverRegistrar.GetServiceXml(); return _resultFactory.GetResult(Request, xml, XMLContentType); } public object Get(GetConnnectionManager request) { - var xml = ConnectionManager.GetServiceXml(Request.Headers.ToDictionary()); + var xml = ConnectionManager.GetServiceXml(); return _resultFactory.GetResult(Request, xml, XMLContentType); } @@ -193,7 +193,7 @@ namespace Emby.Dlna.Api return service.ProcessControlRequest(new ControlRequest { - Headers = Request.Headers.ToDictionary(), + Headers = Request.Headers, InputXml = requestStream, TargetServerUuId = id, RequestedUrl = Request.AbsoluteUri diff --git a/Emby.Dlna/ConnectionManager/ConnectionManager.cs b/Emby.Dlna/ConnectionManager/ConnectionManager.cs index cc427f2a1..e138b91d6 100644 --- a/Emby.Dlna/ConnectionManager/ConnectionManager.cs +++ b/Emby.Dlna/ConnectionManager/ConnectionManager.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using Emby.Dlna.Service; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; @@ -24,7 +23,7 @@ namespace Emby.Dlna.ConnectionManager XmlReaderSettingsFactory = xmlReaderSettingsFactory; } - public string GetServiceXml(IDictionary headers) + public string GetServiceXml() { return new ConnectionManagerXmlBuilder().GetXml(); } diff --git a/Emby.Dlna/ContentDirectory/ContentDirectory.cs b/Emby.Dlna/ContentDirectory/ContentDirectory.cs index b0fec90e6..867e6112f 100644 --- a/Emby.Dlna/ContentDirectory/ContentDirectory.cs +++ b/Emby.Dlna/ContentDirectory/ContentDirectory.cs @@ -65,7 +65,7 @@ namespace Emby.Dlna.ContentDirectory } } - public string GetServiceXml(IDictionary headers) + public string GetServiceXml() { return new ContentDirectoryXmlBuilder().GetXml(); } diff --git a/Emby.Dlna/ControlRequest.cs b/Emby.Dlna/ControlRequest.cs index afd9a0b87..907d437f8 100644 --- a/Emby.Dlna/ControlRequest.cs +++ b/Emby.Dlna/ControlRequest.cs @@ -1,11 +1,12 @@ using System.Collections.Generic; using System.IO; +using Microsoft.AspNetCore.Http; namespace Emby.Dlna { public class ControlRequest { - public IDictionary Headers { get; set; } + public IHeaderDictionary Headers { get; set; } public Stream InputXml { get; set; } @@ -15,7 +16,7 @@ namespace Emby.Dlna public ControlRequest() { - Headers = new Dictionary(); + Headers = new HeaderDictionary(); } } } diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index f53d27451..770a90152 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -17,7 +17,9 @@ using MediaBrowser.Model.Drawing; using MediaBrowser.Model.IO; using MediaBrowser.Model.Reflection; using MediaBrowser.Model.Serialization; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Primitives; namespace Emby.Dlna { @@ -205,16 +207,13 @@ namespace Emby.Dlna } } - public DeviceProfile GetProfile(IDictionary headers) + public DeviceProfile GetProfile(IHeaderDictionary headers) { if (headers == null) { throw new ArgumentNullException(nameof(headers)); } - // Convert to case insensitive - headers = new Dictionary(headers, StringComparer.OrdinalIgnoreCase); - var profile = GetProfiles().FirstOrDefault(i => i.Identification != null && IsMatch(headers, i.Identification)); if (profile != null) @@ -230,12 +229,12 @@ namespace Emby.Dlna return profile; } - private bool IsMatch(IDictionary headers, DeviceIdentification profileInfo) + private bool IsMatch(IHeaderDictionary headers, DeviceIdentification profileInfo) { return profileInfo.Headers.Any(i => IsMatch(headers, i)); } - private bool IsMatch(IDictionary headers, HttpHeaderInfo header) + private bool IsMatch(IHeaderDictionary headers, HttpHeaderInfo header) { // Handle invalid user setup if (string.IsNullOrEmpty(header.Name)) @@ -243,14 +242,14 @@ namespace Emby.Dlna return false; } - if (headers.TryGetValue(header.Name, out string value)) + if (headers.TryGetValue(header.Name, out StringValues value)) { switch (header.Match) { case HeaderMatchType.Equals: return string.Equals(value, header.Value, StringComparison.OrdinalIgnoreCase); case HeaderMatchType.Substring: - var isMatch = value.IndexOf(header.Value, StringComparison.OrdinalIgnoreCase) != -1; + var isMatch = value.ToString().IndexOf(header.Value, StringComparison.OrdinalIgnoreCase) != -1; //_logger.LogDebug("IsMatch-Substring value: {0} testValue: {1} isMatch: {2}", value, header.Value, isMatch); return isMatch; case HeaderMatchType.Regex: @@ -493,7 +492,7 @@ namespace Emby.Dlna internal string Path { get; set; } } - public string GetServerDescriptionXml(IDictionary headers, string serverUuId, string serverAddress) + public string GetServerDescriptionXml(IHeaderDictionary headers, string serverUuId, string serverAddress) { var profile = GetProfile(headers) ?? GetDefaultProfile(); diff --git a/Emby.Dlna/IUpnpService.cs b/Emby.Dlna/IUpnpService.cs index ab8aa4619..ae90e95c7 100644 --- a/Emby.Dlna/IUpnpService.cs +++ b/Emby.Dlna/IUpnpService.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace Emby.Dlna { public interface IUpnpService @@ -7,9 +5,8 @@ namespace Emby.Dlna /// /// Gets the content directory XML. /// - /// The headers. /// System.String. - string GetServiceXml(IDictionary headers); + string GetServiceXml(); /// /// Processes the control request. diff --git a/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs b/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs index 2b84528ea..9c6022b6c 100644 --- a/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs +++ b/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs @@ -3,6 +3,7 @@ using Emby.Dlna.Service; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Xml; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; namespace Emby.Dlna.MediaReceiverRegistrar @@ -19,7 +20,7 @@ namespace Emby.Dlna.MediaReceiverRegistrar XmlReaderSettingsFactory = xmlReaderSettingsFactory; } - public string GetServiceXml(IDictionary headers) + public string GetServiceXml() { return new MediaReceiverRegistrarXmlBuilder().GetXml(); } diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index 2abc6c2f4..70753e563 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -22,6 +22,7 @@ using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Internal; using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; @@ -154,7 +155,7 @@ namespace Emby.Server.Implementations.HttpServer { OnReceive = ProcessWebSocketMessageReceived, Url = e.Url, - QueryString = e.QueryString ?? new QueryParamCollection() + QueryString = e.QueryString ?? new QueryCollection() }; connection.Closed += Connection_Closed; @@ -606,8 +607,8 @@ namespace Emby.Server.Implementations.HttpServer } finally { - httpRes.Close(); - + // TODO + httpRes.IsClosed = true; stopWatch.Stop(); var elapsed = stopWatch.Elapsed; if (elapsed.TotalMilliseconds > 500) diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index 09cdbc3c2..52c8221f6 100644 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -16,6 +16,8 @@ using MediaBrowser.Model.IO; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; using IRequest = MediaBrowser.Model.Services.IRequest; using MimeTypes = MediaBrowser.Model.Net.MimeTypes; @@ -246,9 +248,9 @@ namespace Emby.Server.Implementations.HttpServer private static string GetCompressionType(IRequest request) { - var acceptEncoding = request.Headers["Accept-Encoding"]; + var acceptEncoding = request.Headers["Accept-Encoding"].ToString(); - if (acceptEncoding != null) + if (string.IsNullOrEmpty(acceptEncoding)) { //if (_brotliCompressor != null && acceptEncoding.IndexOf("br", StringComparison.OrdinalIgnoreCase) != -1) // return "br"; @@ -424,12 +426,12 @@ namespace Emby.Server.Implementations.HttpServer /// private object GetCachedResult(IRequest requestContext, IDictionary responseHeaders, StaticResultOptions options) { - bool noCache = (requestContext.Headers.Get("Cache-Control") ?? string.Empty).IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1; + bool noCache = (requestContext.Headers[HeaderNames.CacheControl].ToString()).IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1; AddCachingHeaders(responseHeaders, options.CacheDuration, noCache, options.DateLastModified); if (!noCache) { - DateTime.TryParse(requestContext.Headers.Get("If-Modified-Since"), out var ifModifiedSinceHeader); + DateTime.TryParse(requestContext.Headers[HeaderNames.IfModifiedSince], out var ifModifiedSinceHeader); if (IsNotModified(ifModifiedSinceHeader, options.CacheDuration, options.DateLastModified)) { @@ -530,7 +532,7 @@ namespace Emby.Server.Implementations.HttpServer options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary(StringComparer.OrdinalIgnoreCase); var contentType = options.ContentType; - if (!string.IsNullOrEmpty(requestContext.Headers.Get("If-Modified-Since"))) + if (!StringValues.IsNullOrEmpty(requestContext.Headers[HeaderNames.IfModifiedSince])) { // See if the result is already cached in the browser var result = GetCachedResult(requestContext, options.ResponseHeaders, options); @@ -548,7 +550,7 @@ namespace Emby.Server.Implementations.HttpServer AddCachingHeaders(responseHeaders, options.CacheDuration, false, options.DateLastModified); AddAgeHeader(responseHeaders, options.DateLastModified); - var rangeHeader = requestContext.Headers.Get("Range"); + var rangeHeader = requestContext.Headers["Range"]; if (!isHeadRequest && !string.IsNullOrEmpty(options.Path)) { @@ -609,11 +611,6 @@ namespace Emby.Server.Implementations.HttpServer } } - /// - /// The us culture - /// - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - /// /// Adds the caching responseHeaders. /// diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index e9d0bac74..2bf460bd1 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -8,6 +8,7 @@ using MediaBrowser.Controller.Net; using MediaBrowser.Model.Net; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using UtfUnknown; @@ -67,7 +68,7 @@ namespace Emby.Server.Implementations.HttpServer /// Gets or sets the query string. /// /// The query string. - public QueryParamCollection QueryString { get; set; } + public IQueryCollection QueryString { get; set; } /// /// Initializes a new instance of the class. diff --git a/Emby.Server.Implementations/Net/WebSocketConnectEventArgs.cs b/Emby.Server.Implementations/Net/WebSocketConnectEventArgs.cs index 666f1f601..e3047d392 100644 --- a/Emby.Server.Implementations/Net/WebSocketConnectEventArgs.cs +++ b/Emby.Server.Implementations/Net/WebSocketConnectEventArgs.cs @@ -1,6 +1,7 @@ using System; using System.Net.WebSockets; using MediaBrowser.Model.Services; +using Microsoft.AspNetCore.Http; namespace Emby.Server.Implementations.Net { @@ -15,7 +16,7 @@ namespace Emby.Server.Implementations.Net /// Gets or sets the query string. /// /// The query string. - public QueryParamCollection QueryString { get; set; } + public IQueryCollection QueryString { get; set; } /// /// Gets or sets the web socket. /// diff --git a/Emby.Server.Implementations/Services/ServiceHandler.cs b/Emby.Server.Implementations/Services/ServiceHandler.cs index 7e836e22c..3c8adfc98 100644 --- a/Emby.Server.Implementations/Services/ServiceHandler.cs +++ b/Emby.Server.Implementations/Services/ServiceHandler.cs @@ -154,7 +154,7 @@ namespace Emby.Server.Implementations.Services { if (name == null) continue; //thank you ASP.NET - var values = request.QueryString.GetValues(name); + var values = request.QueryString[name]; if (values.Count == 1) { map[name] = values[0]; diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs index 24903f5e8..a551433ed 100644 --- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs @@ -5,6 +5,7 @@ using MediaBrowser.Controller.Session; using MediaBrowser.Model.Events; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Session @@ -62,7 +63,7 @@ namespace Emby.Server.Implementations.Session } } - private SessionInfo GetSession(QueryParamCollection queryString, string remoteEndpoint) + private SessionInfo GetSession(IQueryCollection queryString, string remoteEndpoint) { if (queryString == null) { diff --git a/Emby.Server.Implementations/SocketSharp/RequestMono.cs b/Emby.Server.Implementations/SocketSharp/RequestMono.cs index 113f76b10..f73adc5ff 100644 --- a/Emby.Server.Implementations/SocketSharp/RequestMono.cs +++ b/Emby.Server.Implementations/SocketSharp/RequestMono.cs @@ -118,8 +118,6 @@ namespace Emby.Server.Implementations.SocketSharp public string Authorization => StringValues.IsNullOrEmpty(request.Headers["Authorization"]) ? null : request.Headers["Authorization"].ToString(); - protected bool validate_cookies { get; set; } - protected bool validate_query_string { get; set; } protected bool validate_form { get; set; } protected bool checked_form { get; set; } diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs index 77469244b..9f046c3fd 100644 --- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs +++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs @@ -52,12 +52,10 @@ using Microsoft.Extensions.Logging; var endpoint = ctx.Connection.RemoteIpAddress.ToString(); var url = ctx.Request.GetDisplayUrl(); - var queryString = new QueryParamCollection(ctx.Request.Query); - var connectingArgs = new WebSocketConnectingEventArgs { Url = url, - QueryString = queryString, + QueryString = ctx.Request.Query, Endpoint = endpoint }; @@ -73,7 +71,7 @@ using Microsoft.Extensions.Logging; WebSocketConnected(new WebSocketConnectEventArgs { Url = url, - QueryString = queryString, + QueryString = ctx.Request.Query, WebSocket = socket, Endpoint = endpoint }); diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs index bddccf68b..24fd36062 100644 --- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs +++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs @@ -13,7 +13,6 @@ using Microsoft.Extensions.Primitives; using Microsoft.Net.Http.Headers; using IHttpFile = MediaBrowser.Model.Services.IHttpFile; using IHttpRequest = MediaBrowser.Model.Services.IHttpRequest; -using IHttpResponse = MediaBrowser.Model.Services.IHttpResponse; using IResponse = MediaBrowser.Model.Services.IResponse; namespace Emby.Server.Implementations.SocketSharp @@ -21,7 +20,7 @@ namespace Emby.Server.Implementations.SocketSharp public partial class WebSocketSharpRequest : IHttpRequest { private readonly HttpRequest request; - private readonly IHttpResponse response; + private readonly IResponse response; public WebSocketSharpRequest(HttpRequest httpContext, HttpResponse response, string operationName, ILogger logger) { @@ -34,11 +33,9 @@ namespace Emby.Server.Implementations.SocketSharp public HttpRequest HttpRequest => request; - public object OriginalRequest => request; - public IResponse Response => response; - public IHttpResponse HttpResponse => response; + public IResponse HttpResponse => response; public string OperationName { get; set; } @@ -396,10 +393,9 @@ namespace Emby.Server.Implementations.SocketSharp public string UserAgent => request.Headers[HeaderNames.UserAgent]; - public QueryParamCollection Headers => new QueryParamCollection(request.Headers); + public IHeaderDictionary Headers => request.Headers; - private QueryParamCollection queryString; - public QueryParamCollection QueryString => queryString ?? (queryString = new QueryParamCollection(request.Query)); + public IQueryCollection QueryString => request.Query; public bool IsLocal => string.Equals(request.HttpContext.Connection.LocalIpAddress.ToString(), request.HttpContext.Connection.RemoteIpAddress.ToString()); diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpResponse.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpResponse.cs index f9ecb52a5..c4fbaddd3 100644 --- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpResponse.cs +++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpResponse.cs @@ -1,23 +1,18 @@ using System; using System.Collections.Generic; using System.IO; -using System.Net; -using System.Net.Sockets; using System.Runtime.InteropServices; -using System.Text; using System.Threading; using System.Threading.Tasks; -using Emby.Server.Implementations; using MediaBrowser.Model.IO; using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; -using IHttpResponse = MediaBrowser.Model.Services.IHttpResponse; using IRequest = MediaBrowser.Model.Services.IRequest; namespace Emby.Server.Implementations.SocketSharp { - public class WebSocketSharpResponse : IHttpResponse + public class WebSocketSharpResponse : IResponse { private readonly ILogger _logger; @@ -51,42 +46,7 @@ namespace Emby.Server.Implementations.SocketSharp set => _response.ContentType = value; } - public QueryParamCollection Headers => new QueryParamCollection(_response.Headers); - - private static string AsHeaderValue(Cookie cookie) - { - DateTime defaultExpires = DateTime.MinValue; - - var path = cookie.Expires == defaultExpires - ? "/" - : cookie.Path ?? "/"; - - var sb = new StringBuilder(); - - sb.Append($"{cookie.Name}={cookie.Value};path={path}"); - - if (cookie.Expires != defaultExpires) - { - sb.Append($";expires={cookie.Expires:R}"); - } - - if (!string.IsNullOrEmpty(cookie.Domain)) - { - sb.Append($";domain={cookie.Domain}"); - } - - if (cookie.Secure) - { - sb.Append(";Secure"); - } - - if (cookie.HttpOnly) - { - sb.Append(";HttpOnly"); - } - - return sb.ToString(); - } + public IHeaderDictionary Headers => _response.Headers; public void AddHeader(string name, string value) { @@ -111,51 +71,14 @@ namespace Emby.Server.Implementations.SocketSharp public Stream OutputStream => _response.Body; - public void Close() - { - if (!this.IsClosed) - { - this.IsClosed = true; - - try - { - var response = this._response; - - var outputStream = response.Body; - - // This is needed with compression - outputStream.Flush(); - outputStream.Dispose(); - } - catch (SocketException) - { - } - catch (Exception ex) - { - _logger.LogError(ex, "Error in HttpListenerResponseWrapper"); - } - } - } - public bool IsClosed { get; - private set; - } - - public void SetCookie(Cookie cookie) - { - var cookieStr = AsHeaderValue(cookie); - _response.Headers.Add("Set-Cookie", cookieStr); + set; } public bool SendChunked { get; set; } - public bool KeepAlive { get; set; } - - public void ClearCookies() - { - } const int StreamCopyToBufferSize = 81920; public async Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, IFileSystem fileSystem, IStreamHelper streamHelper, CancellationToken cancellationToken) { diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index a6be071b8..ae259a4f5 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -609,12 +609,12 @@ namespace MediaBrowser.Api.Playback { foreach (var param in Request.QueryString) { - if (char.IsLower(param.Name[0])) + if (char.IsLower(param.Key[0])) { // This was probably not parsed initially and should be a StreamOptions // TODO: This should be incorporated either in the lower framework for parsing requests // or the generated URL should correctly serialize it - request.StreamOptions[param.Name] = param.Value; + request.StreamOptions[param.Key] = param.Value; } } } @@ -867,7 +867,7 @@ namespace MediaBrowser.Api.Playback private void ApplyDeviceProfileSettings(StreamState state) { - var headers = Request.Headers.ToDictionary(); + var headers = Request.Headers; if (!string.IsNullOrWhiteSpace(state.Request.DeviceProfileId)) { diff --git a/MediaBrowser.Controller/Dlna/IDlnaManager.cs b/MediaBrowser.Controller/Dlna/IDlnaManager.cs index a6ee7c505..41a7686a3 100644 --- a/MediaBrowser.Controller/Dlna/IDlnaManager.cs +++ b/MediaBrowser.Controller/Dlna/IDlnaManager.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using MediaBrowser.Controller.Drawing; using MediaBrowser.Model.Dlna; +using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.Dlna { @@ -17,7 +18,7 @@ namespace MediaBrowser.Controller.Dlna /// /// The headers. /// DeviceProfile. - DeviceProfile GetProfile(IDictionary headers); + DeviceProfile GetProfile(IHeaderDictionary headers); /// /// Gets the default profile. @@ -64,7 +65,7 @@ namespace MediaBrowser.Controller.Dlna /// The server uu identifier. /// The server address. /// System.String. - string GetServerDescriptionXml(IDictionary headers, string serverUuId, string serverAddress); + string GetServerDescriptionXml(IHeaderDictionary headers, string serverUuId, string serverAddress); /// /// Gets the icon. diff --git a/MediaBrowser.Controller/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs index a09b2f7a2..566897b31 100644 --- a/MediaBrowser.Controller/Net/IWebSocketConnection.cs +++ b/MediaBrowser.Controller/Net/IWebSocketConnection.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.Net; using MediaBrowser.Model.Services; +using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.Net { @@ -35,7 +36,7 @@ namespace MediaBrowser.Controller.Net /// Gets or sets the query string. /// /// The query string. - QueryParamCollection QueryString { get; set; } + IQueryCollection QueryString { get; set; } /// /// Gets or sets the receive action. diff --git a/MediaBrowser.Controller/Net/WebSocketConnectEventArgs.cs b/MediaBrowser.Controller/Net/WebSocketConnectEventArgs.cs index f26b764bb..107e67421 100644 --- a/MediaBrowser.Controller/Net/WebSocketConnectEventArgs.cs +++ b/MediaBrowser.Controller/Net/WebSocketConnectEventArgs.cs @@ -1,5 +1,7 @@ using System; using MediaBrowser.Model.Services; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Internal; namespace MediaBrowser.Controller.Net { @@ -22,7 +24,7 @@ namespace MediaBrowser.Controller.Net /// Gets or sets the query string. /// /// The query string. - public QueryParamCollection QueryString { get; set; } + public IQueryCollection QueryString { get; set; } /// /// Gets or sets a value indicating whether [allow connection]. /// @@ -31,7 +33,7 @@ namespace MediaBrowser.Controller.Net public WebSocketConnectingEventArgs() { - QueryString = new QueryParamCollection(); + QueryString = new QueryCollection(); AllowConnection = true; } } diff --git a/MediaBrowser.Model/Services/IHttpRequest.cs b/MediaBrowser.Model/Services/IHttpRequest.cs index 579f80c96..50c6076f3 100644 --- a/MediaBrowser.Model/Services/IHttpRequest.cs +++ b/MediaBrowser.Model/Services/IHttpRequest.cs @@ -2,11 +2,6 @@ namespace MediaBrowser.Model.Services { public interface IHttpRequest : IRequest { - /// - /// The HttpResponse - /// - IHttpResponse HttpResponse { get; } - /// /// The HTTP Verb /// diff --git a/MediaBrowser.Model/Services/IHttpResponse.cs b/MediaBrowser.Model/Services/IHttpResponse.cs index a8b79f394..b99d12525 100644 --- a/MediaBrowser.Model/Services/IHttpResponse.cs +++ b/MediaBrowser.Model/Services/IHttpResponse.cs @@ -4,17 +4,5 @@ namespace MediaBrowser.Model.Services { public interface IHttpResponse : IResponse { - //ICookies Cookies { get; } - - /// - /// Adds a new Set-Cookie instruction to Response - /// - /// - void SetCookie(Cookie cookie); - - /// - /// Removes all pending Set-Cookie instructions - /// - void ClearCookies(); } } diff --git a/MediaBrowser.Model/Services/IRequest.cs b/MediaBrowser.Model/Services/IRequest.cs index 0fd4ea37b..edb5a2509 100644 --- a/MediaBrowser.Model/Services/IRequest.cs +++ b/MediaBrowser.Model/Services/IRequest.cs @@ -1,20 +1,15 @@ using System; using System.Collections.Generic; using System.IO; -using System.Net; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.IO; +using Microsoft.AspNetCore.Http; namespace MediaBrowser.Model.Services { public interface IRequest { - /// - /// The underlying ASP.NET or HttpListener HttpRequest - /// - object OriginalRequest { get; } - IResponse Response { get; } /// @@ -51,9 +46,9 @@ namespace MediaBrowser.Model.Services /// Dictionary Items { get; } - QueryParamCollection Headers { get; } + IHeaderDictionary Headers { get; } - QueryParamCollection QueryString { get; } + IQueryCollection QueryString { get; } Task GetFormData(); @@ -122,21 +117,15 @@ namespace MediaBrowser.Model.Services Stream OutputStream { get; } - /// - /// Signal that this response has been handled and no more processing should be done. - /// When used in a request or response filter, no more filters or processing is done on this request. - /// - void Close(); - /// /// Gets a value indicating whether this instance is closed. /// - bool IsClosed { get; } + bool IsClosed { get; set; } //Add Metadata to Response Dictionary Items { get; } - QueryParamCollection Headers { get; } + IHeaderDictionary Headers { get; } Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, IFileSystem fileSystem, IStreamHelper streamHelper, CancellationToken cancellationToken); diff --git a/MediaBrowser.Model/Services/QueryParamCollection.cs b/MediaBrowser.Model/Services/QueryParamCollection.cs index 9f23b2420..4631a3b63 100644 --- a/MediaBrowser.Model/Services/QueryParamCollection.cs +++ b/MediaBrowser.Model/Services/QueryParamCollection.cs @@ -1,10 +1,7 @@ using System; using System.Collections.Generic; -using System.Collections.Specialized; using System.Linq; -using System.Net; using MediaBrowser.Model.Dto; -using Microsoft.AspNetCore.Http; namespace MediaBrowser.Model.Services { @@ -13,23 +10,6 @@ namespace MediaBrowser.Model.Services { public QueryParamCollection() { - - } - - public QueryParamCollection(IHeaderDictionary headers) - { - foreach (var pair in headers) - { - Add(pair.Key, pair.Value); - } - } - - public QueryParamCollection(IQueryCollection queryCollection) - { - foreach (var pair in queryCollection) - { - Add(pair.Key, pair.Value); - } } private static StringComparison GetStringComparison() -- cgit v1.2.3 From e47d12198556abfbfb57d2c1a9e45f6f7230bf63 Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Wed, 27 Feb 2019 21:40:47 +0100 Subject: Fix websockets --- Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs | 5 +++++ .../SocketSharp/WebSocketSharpListener.cs | 13 +++++++++---- .../Net/BasePeriodicWebSocketListener.cs | 13 ++----------- 3 files changed, 16 insertions(+), 15 deletions(-) (limited to 'Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs') diff --git a/Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs b/Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs index dcbfb8048..eebbe8b78 100644 --- a/Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs +++ b/Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs @@ -85,6 +85,11 @@ namespace Emby.Server.Implementations.SocketSharp if (dispose) { _cancellationTokenSource.Cancel(); + if (_webSocket.State == WebSocketState.Open) + { + _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closed by client", + CancellationToken.None); + } } _disposed = true; diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs index 9f046c3fd..c5abad5d3 100644 --- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs +++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs @@ -76,18 +76,23 @@ using Microsoft.Extensions.Logging; Endpoint = endpoint }); - var buffer = WebSocket.CreateClientBuffer(4096, 4096); WebSocketReceiveResult result; var message = new List(); do { + var buffer = WebSocket.CreateServerBuffer(4096); result = await webSocketContext.ReceiveAsync(buffer, _disposeCancellationToken); - socket.OnReceiveBytes(buffer.Array); message.AddRange(buffer.Array.Take(result.Count)); - } while (!result.EndOfMessage && result.MessageType != WebSocketMessageType.Close); - socket.OnReceiveBytes(message.ToArray()); + if (result.EndOfMessage) + { + socket.OnReceiveBytes(message.ToArray()); + message.Clear(); + } + } while (socket.State == WebSocketState.Open && result.MessageType != WebSocketMessageType.Close); + + await webSocketContext.CloseAsync(result.CloseStatus ?? WebSocketCloseStatus.NormalClosure, result.CloseStatusDescription, _disposeCancellationToken); socket.Dispose(); diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs index 4242a00e2..d2d0fbbc6 100644 --- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs @@ -80,12 +80,7 @@ namespace MediaBrowser.Controller.Net protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); - protected virtual bool SendOnTimer => false; - - protected virtual void ParseMessageParams(string[] values) - { - - } + protected bool SendOnTimer => false; /// /// Starts sending messages over a web socket @@ -98,11 +93,6 @@ namespace MediaBrowser.Controller.Net var dueTimeMs = long.Parse(vals[0], UsCulture); var periodMs = long.Parse(vals[1], UsCulture); - if (vals.Length > 2) - { - ParseMessageParams(vals.Skip(2).ToArray()); - } - var cancellationTokenSource = new CancellationTokenSource(); Logger.LogDebug("{1} Begin transmitting over websocket to {0}", message.Connection.RemoteEndPoint, GetType().Name); @@ -250,6 +240,7 @@ namespace MediaBrowser.Controller.Net { Logger.LogDebug("{1} stop transmitting over websocket to {0}", connection.Item1.RemoteEndPoint, GetType().Name); + connection.Item1.Dispose(); var timer = connection.Item3; if (timer != null) -- cgit v1.2.3 From dab8e150520f5a76d875a926530632783e17006f Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Wed, 27 Feb 2019 21:48:28 +0100 Subject: Check websocket state before closing --- Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs') diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs index c5abad5d3..9422673f5 100644 --- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs +++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs @@ -93,8 +93,12 @@ using Microsoft.Extensions.Logging; } while (socket.State == WebSocketState.Open && result.MessageType != WebSocketMessageType.Close); - await webSocketContext.CloseAsync(result.CloseStatus ?? WebSocketCloseStatus.NormalClosure, - result.CloseStatusDescription, _disposeCancellationToken); + if (webSocketContext.State == WebSocketState.Open) + { + await webSocketContext.CloseAsync(result.CloseStatus ?? WebSocketCloseStatus.NormalClosure, + result.CloseStatusDescription, _disposeCancellationToken); + } + socket.Dispose(); } else -- cgit v1.2.3 From fb1de5a9213f7da98ed15a6975201d6bca3537d4 Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Wed, 27 Feb 2019 23:22:55 +0100 Subject: Remove more cruft and add the beginnings of a socket middleware --- Emby.Server.Implementations/ApplicationHost.cs | 2 + .../HttpServer/WebSocketConnection.cs | 36 +----------- .../Middleware/WebSocketMiddleware.cs | 36 ++++++++++++ Emby.Server.Implementations/Net/IWebSocket.cs | 5 -- .../SocketSharp/WebSocketSharpListener.cs | 65 ++++++++-------------- .../WebSocket/WebSocketManager.cs | 7 +++ .../WebSockets/WebSocketManager.cs | 22 ++++++++ .../MediaBrowser.Controller.csproj | 8 ++- 8 files changed, 97 insertions(+), 84 deletions(-) create mode 100644 Emby.Server.Implementations/Middleware/WebSocketMiddleware.cs create mode 100644 Emby.Server.Implementations/WebSocket/WebSocketManager.cs create mode 100644 Emby.Server.Implementations/WebSockets/WebSocketManager.cs (limited to 'Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 0b4a2fd30..e558b4354 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -35,6 +35,7 @@ using Emby.Server.Implementations.IO; using Emby.Server.Implementations.Library; using Emby.Server.Implementations.LiveTv; using Emby.Server.Implementations.Localization; +using Emby.Server.Implementations.Middleware; using Emby.Server.Implementations.Net; using Emby.Server.Implementations.Playlists; using Emby.Server.Implementations.Reflection; @@ -641,6 +642,7 @@ namespace Emby.Server.Implementations app.UseWebSockets(); app.UseResponseCompression(); + // TODO app.UseMiddleware(); app.Use(ExecuteWebsocketHandlerAsync); app.Use(ExecuteHttpHandlerAsync); }) diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index 2bf460bd1..54a16040f 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -102,12 +102,6 @@ namespace Emby.Server.Implementations.HttpServer _socket = socket; _socket.OnReceiveBytes = OnReceiveInternal; - var memorySocket = socket as IMemoryWebSocket; - if (memorySocket != null) - { - memorySocket.OnReceiveMemoryBytes = OnReceiveInternal; - } - RemoteEndPoint = remoteEndPoint; _logger = logger; @@ -143,34 +137,6 @@ namespace Emby.Server.Implementations.HttpServer } } - /// - /// Called when [receive]. - /// - /// The memory block. - /// The length of the memory block. - private void OnReceiveInternal(Memory memory, int length) - { - LastActivityDate = DateTime.UtcNow; - - if (OnReceive == null) - { - return; - } - - var bytes = memory.Slice(0, length).ToArray(); - - var charset = CharsetDetector.DetectFromBytes(bytes).Detected?.EncodingName; - - if (string.Equals(charset, "utf-8", StringComparison.OrdinalIgnoreCase)) - { - OnReceiveInternal(Encoding.UTF8.GetString(bytes, 0, bytes.Length)); - } - else - { - OnReceiveInternal(Encoding.ASCII.GetString(bytes, 0, bytes.Length)); - } - } - private void OnReceiveInternal(string message) { LastActivityDate = DateTime.UtcNow; @@ -194,7 +160,7 @@ namespace Emby.Server.Implementations.HttpServer var info = new WebSocketMessageInfo { MessageType = stub.MessageType, - Data = stub.Data == null ? null : stub.Data.ToString(), + Data = stub.Data?.ToString(), Connection = this }; diff --git a/Emby.Server.Implementations/Middleware/WebSocketMiddleware.cs b/Emby.Server.Implementations/Middleware/WebSocketMiddleware.cs new file mode 100644 index 000000000..a1d0e77d6 --- /dev/null +++ b/Emby.Server.Implementations/Middleware/WebSocketMiddleware.cs @@ -0,0 +1,36 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using WebSocketManager = Emby.Server.Implementations.WebSockets.WebSocketManager; + +namespace Emby.Server.Implementations.Middleware +{ + public class WebSocketMiddleware + { + private readonly RequestDelegate _next; + private readonly ILogger _logger; + private readonly WebSocketManager _webSocketManager; + + public WebSocketMiddleware(RequestDelegate next, ILogger logger, WebSocketManager webSocketManager) + { + _next = next; + _logger = logger; + _webSocketManager = webSocketManager; + } + + public async Task Invoke(HttpContext httpContext) + { + _logger.LogInformation("Handling request: " + httpContext.Request.Path); + + if (httpContext.WebSockets.IsWebSocketRequest) + { + var webSocketContext = await httpContext.WebSockets.AcceptWebSocketAsync(null).ConfigureAwait(false); + _webSocketManager.AddSocket(webSocketContext); + } + else + { + await _next.Invoke(httpContext); + } + } + } +} diff --git a/Emby.Server.Implementations/Net/IWebSocket.cs b/Emby.Server.Implementations/Net/IWebSocket.cs index 4671de07c..4d160aa66 100644 --- a/Emby.Server.Implementations/Net/IWebSocket.cs +++ b/Emby.Server.Implementations/Net/IWebSocket.cs @@ -45,9 +45,4 @@ namespace Emby.Server.Implementations.Net /// Task. Task SendAsync(string text, bool endOfMessage, CancellationToken cancellationToken); } - - public interface IMemoryWebSocket - { - Action, int> OnReceiveMemoryBytes { get; set; } - } } diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs index 9422673f5..5ddd31647 100644 --- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs +++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs @@ -33,8 +33,6 @@ using Microsoft.Extensions.Logging; public Func ErrorHandler { get; set; } public Func RequestHandler { get; set; } - public Action WebSocketConnecting { get; set; } - public Action WebSocketConnected { get; set; } private static void LogRequest(ILogger logger, HttpRequest request) @@ -52,60 +50,41 @@ using Microsoft.Extensions.Logging; var endpoint = ctx.Connection.RemoteIpAddress.ToString(); var url = ctx.Request.GetDisplayUrl(); - var connectingArgs = new WebSocketConnectingEventArgs + var webSocketContext = await ctx.WebSockets.AcceptWebSocketAsync(null).ConfigureAwait(false); + var socket = new SharpWebSocket(webSocketContext, _logger); + + WebSocketConnected(new WebSocketConnectEventArgs { Url = url, QueryString = ctx.Request.Query, + WebSocket = socket, Endpoint = endpoint - }; + }); - WebSocketConnecting?.Invoke(connectingArgs); + WebSocketReceiveResult result; + var message = new List(); - if (connectingArgs.AllowConnection) + do { - _logger.LogDebug("Web socket connection allowed"); + var buffer = WebSocket.CreateServerBuffer(4096); + result = await webSocketContext.ReceiveAsync(buffer, _disposeCancellationToken); + message.AddRange(buffer.Array.Take(result.Count)); - var webSocketContext = await ctx.WebSockets.AcceptWebSocketAsync(null).ConfigureAwait(false); - var socket = new SharpWebSocket(webSocketContext, _logger); - - WebSocketConnected(new WebSocketConnectEventArgs + if (result.EndOfMessage) { - Url = url, - QueryString = ctx.Request.Query, - WebSocket = socket, - Endpoint = endpoint - }); - - WebSocketReceiveResult result; - var message = new List(); - - do - { - var buffer = WebSocket.CreateServerBuffer(4096); - result = await webSocketContext.ReceiveAsync(buffer, _disposeCancellationToken); - message.AddRange(buffer.Array.Take(result.Count)); - - if (result.EndOfMessage) - { - socket.OnReceiveBytes(message.ToArray()); - message.Clear(); - } - } while (socket.State == WebSocketState.Open && result.MessageType != WebSocketMessageType.Close); - - - if (webSocketContext.State == WebSocketState.Open) - { - await webSocketContext.CloseAsync(result.CloseStatus ?? WebSocketCloseStatus.NormalClosure, - result.CloseStatusDescription, _disposeCancellationToken); + socket.OnReceiveBytes(message.ToArray()); + message.Clear(); } + } while (socket.State == WebSocketState.Open && result.MessageType != WebSocketMessageType.Close); - socket.Dispose(); - } - else + + if (webSocketContext.State == WebSocketState.Open) { - _logger.LogWarning("Web socket connection not allowed"); - ctx.Response.StatusCode = 401; + await webSocketContext.CloseAsync(result.CloseStatus ?? WebSocketCloseStatus.NormalClosure, + result.CloseStatusDescription, _disposeCancellationToken); } + + socket.Dispose(); } catch (Exception ex) { diff --git a/Emby.Server.Implementations/WebSocket/WebSocketManager.cs b/Emby.Server.Implementations/WebSocket/WebSocketManager.cs new file mode 100644 index 000000000..7472820cf --- /dev/null +++ b/Emby.Server.Implementations/WebSocket/WebSocketManager.cs @@ -0,0 +1,7 @@ +namespace Emby.Server.Implementations.WebSocket +{ + public class WebSocketManager + { + + } +} diff --git a/Emby.Server.Implementations/WebSockets/WebSocketManager.cs b/Emby.Server.Implementations/WebSockets/WebSocketManager.cs new file mode 100644 index 000000000..7e74a4527 --- /dev/null +++ b/Emby.Server.Implementations/WebSockets/WebSocketManager.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Concurrent; +using System.Net.WebSockets; + +namespace Emby.Server.Implementations.WebSockets +{ + public class WebSocketManager + { + private readonly ConcurrentDictionary _activeWebSockets; + + public WebSocketManager() + { + _activeWebSockets = new ConcurrentDictionary(); + } + + public void AddSocket(WebSocket webSocket) + { + var guid = Guid.NewGuid(); + _activeWebSockets.TryAdd(guid, webSocket); + } + } +} diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 01893f1b5..81e255d52 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -1,4 +1,4 @@ - + Jellyfin Contributors @@ -16,6 +16,12 @@ + + + ..\..\..\..\..\usr\local\share\dotnet\sdk\NuGetFallbackFolder\microsoft.aspnetcore.http.extensions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Extensions.dll + + + netstandard2.0 false -- cgit v1.2.3 From 6cc1bd544add65fdf7758c04655586c206675193 Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Mon, 4 Mar 2019 19:31:26 +0100 Subject: Fix a logging statement --- Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs') diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs index 5ddd31647..2df826957 100644 --- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs +++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs @@ -12,8 +12,9 @@ using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.Extensions.Logging; +using Microsoft.Net.Http.Headers; - namespace Emby.Server.Implementations.SocketSharp +namespace Emby.Server.Implementations.SocketSharp { public class WebSocketSharpListener : IHttpListener { @@ -39,7 +40,7 @@ using Microsoft.Extensions.Logging; { var url = request.GetDisplayUrl(); - logger.LogInformation("{0} {1}. UserAgent: {2}", "WS", url, request.Headers["User-Agent"].ToString()); + logger.LogInformation("WS {Url}. UserAgent: {UserAgent}", url, request.Headers[HeaderNames.UserAgent].ToString()); } public async Task ProcessWebSocketRequest(HttpContext ctx) -- cgit v1.2.3