Browse Source

Fix websockets array index out of bounds and some cleanup

Claus Vium 6 years ago
parent
commit
a85488cd20

+ 2 - 76
Emby.Server.Implementations/ApplicationHost.cs

@@ -624,25 +624,7 @@ namespace Emby.Server.Implementations
 
 
             Host = new WebHostBuilder()
             Host = new WebHostBuilder()
                 .UseKestrel()
                 .UseKestrel()
-                .UseContentRoot(Path.Combine(Directory.GetCurrentDirectory(), @"jellyfin-web\src"))
-                //.UseStartup<Startup>()
-//                .ConfigureServices(async services =>
-//                {
-//                    services.AddSingleton<IStartup>(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")
                 .UseUrls("http://localhost:8096")
                 .ConfigureServices(services =>
                 .ConfigureServices(services =>
                 {
                 {
@@ -672,63 +654,7 @@ namespace Emby.Server.Implementations
                 return;
                 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<byte>(), 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<Task> next)
         public async Task ExecuteHttpHandlerAsync(HttpContext context, Func<Task> next)
         {
         {

+ 6 - 1
Emby.Server.Implementations/HttpServer/HttpListenerHost.cs

@@ -21,6 +21,7 @@ using MediaBrowser.Model.Events;
 using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.Services;
+using Microsoft.AspNetCore.Http;
 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
 using ServiceStack.Text.Jsv;
 using ServiceStack.Text.Jsv;
@@ -767,6 +768,10 @@ namespace Emby.Server.Implementations.HttpServer
             return _jsonSerializer.DeserializeFromStreamAsync(stream, type);
             return _jsonSerializer.DeserializeFromStreamAsync(stream, type);
         }
         }
 
 
+        public Task ProcessWebSocketRequest(HttpContext context)
+        {
+            return _websocketlistener.ProcessWebSocketRequest(context);
+        }
         //TODO Add Jellyfin Route Path Normalizer
         //TODO Add Jellyfin Route Path Normalizer
 
 
         private static string NormalizeEmbyRoutePath(string path)
         private static string NormalizeEmbyRoutePath(string path)
@@ -801,7 +806,7 @@ namespace Emby.Server.Implementations.HttpServer
 
 
         private bool _disposed;
         private bool _disposed;
         private readonly object _disposeLock = new object();
         private readonly object _disposeLock = new object();
-        public WebSocketSharpListener _websocketlistener;
+        private readonly WebSocketSharpListener _websocketlistener;
 
 
         protected virtual void Dispose(bool disposing)
         protected virtual void Dispose(bool disposing)
         {
         {

+ 16 - 150
Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs

@@ -1,6 +1,7 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
- using System.Net;
+using System.Linq;
+using System.Net;
 using System.Net.WebSockets;
 using System.Net.WebSockets;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
@@ -38,94 +39,18 @@ using Microsoft.Extensions.Logging;
 
 
         public Action<WebSocketConnectEventArgs> WebSocketConnected { get; set; }
         public Action<WebSocketConnectEventArgs> WebSocketConnected { get; set; }
 
 
-//        public void Start(IEnumerable<string> 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)
         public async Task ProcessWebSocketRequest(HttpContext ctx)
         {
         {
             try
             try
             {
             {
+                LogRequest(_logger, ctx.Request);
                 var endpoint = ctx.Connection.RemoteIpAddress.ToString();
                 var endpoint = ctx.Connection.RemoteIpAddress.ToString();
                 var url = ctx.Request.GetDisplayUrl();
                 var url = ctx.Request.GetDisplayUrl();
 
 
@@ -156,94 +81,35 @@ using Microsoft.Extensions.Logging;
                         Endpoint = endpoint
                         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<byte>();
 
 
-                    while (result.MessageType != WebSocketMessageType.Close)
+                    do
                     {
                     {
                         result = await webSocketContext.ReceiveAsync(buffer, CancellationToken.None);
                         result = await webSocketContext.ReceiveAsync(buffer, CancellationToken.None);
                         socket.OnReceiveBytes(buffer.Array);
                         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<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);
-
-                    //    result = await webSocketContext.ReceiveAsync(new ArraySegment<byte>(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
                 else
                 {
                 {
                     _logger.LogWarning("Web socket connection not allowed");
                     _logger.LogWarning("Web socket connection not allowed");
                     ctx.Response.StatusCode = 401;
                     ctx.Response.StatusCode = 401;
-                    //ctx.Response.Close();
                 }
                 }
             }
             }
             catch (Exception ex)
             catch (Exception ex)
             {
             {
                 _logger.LogError(ex, "AcceptWebSocketAsync error");
                 _logger.LogError(ex, "AcceptWebSocketAsync error");
                 ctx.Response.StatusCode = 500;
                 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<string> urlPrefixes)
         public void Start(IEnumerable<string> urlPrefixes)
         {
         {
             throw new NotImplementedException();
             throw new NotImplementedException();