diff options
13 files changed, 247 insertions, 21 deletions
diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs index 315b48b83..37142af19 100644 --- a/MediaBrowser.Controller/Net/IHttpServer.cs +++ b/MediaBrowser.Controller/Net/IHttpServer.cs @@ -45,6 +45,11 @@ namespace MediaBrowser.Controller.Net event EventHandler<WebSocketConnectEventArgs> WebSocketConnected; /// <summary> + /// Occurs when [web socket connecting]. + /// </summary> + event EventHandler<WebSocketConnectingEventArgs> WebSocketConnecting; + + /// <summary> /// Inits this instance. /// </summary> void Init(IEnumerable<IRestfulService> services); diff --git a/MediaBrowser.Controller/Net/IServerManager.cs b/MediaBrowser.Controller/Net/IServerManager.cs index d90a0f8ed..5191a62e3 100644 --- a/MediaBrowser.Controller/Net/IServerManager.cs +++ b/MediaBrowser.Controller/Net/IServerManager.cs @@ -1,4 +1,4 @@ -using MediaBrowser.Common.Net; +using MediaBrowser.Model.Events; using System; using System.Collections.Generic; using System.Threading; @@ -58,5 +58,10 @@ namespace MediaBrowser.Controller.Net /// </summary> /// <value>The web socket connections.</value> IEnumerable<IWebSocketConnection> WebSocketConnections { get; } + + /// <summary> + /// Occurs when [web socket connected]. + /// </summary> + event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected; } }
\ No newline at end of file diff --git a/MediaBrowser.Controller/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs index 37fd6708d..e21df3c39 100644 --- a/MediaBrowser.Controller/Net/IWebSocketConnection.cs +++ b/MediaBrowser.Controller/Net/IWebSocketConnection.cs @@ -1,5 +1,6 @@ using MediaBrowser.Model.Net; using System; +using System.Collections.Specialized; using System.Threading; using System.Threading.Tasks; @@ -11,7 +12,7 @@ namespace MediaBrowser.Controller.Net /// Occurs when [closed]. /// </summary> event EventHandler<EventArgs> Closed; - + /// <summary> /// Gets the id. /// </summary> @@ -25,6 +26,17 @@ namespace MediaBrowser.Controller.Net DateTime LastActivityDate { get; } /// <summary> + /// Gets or sets the URL. + /// </summary> + /// <value>The URL.</value> + string Url { get; set; } + /// <summary> + /// Gets or sets the query string. + /// </summary> + /// <value>The query string.</value> + NameValueCollection QueryString { get; set; } + + /// <summary> /// Gets or sets the receive action. /// </summary> /// <value>The receive action.</value> diff --git a/MediaBrowser.Controller/Net/WebSocketConnectEventArgs.cs b/MediaBrowser.Controller/Net/WebSocketConnectEventArgs.cs index 394fcd92f..ffeaf286e 100644 --- a/MediaBrowser.Controller/Net/WebSocketConnectEventArgs.cs +++ b/MediaBrowser.Controller/Net/WebSocketConnectEventArgs.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Specialized; namespace MediaBrowser.Controller.Net { @@ -8,6 +9,16 @@ namespace MediaBrowser.Controller.Net public class WebSocketConnectEventArgs : EventArgs { /// <summary> + /// Gets or sets the URL. + /// </summary> + /// <value>The URL.</value> + public string Url { get; set; } + /// <summary> + /// Gets or sets the query string. + /// </summary> + /// <value>The query string.</value> + public NameValueCollection QueryString { get; set; } + /// <summary> /// Gets or sets the web socket. /// </summary> /// <value>The web socket.</value> @@ -18,4 +29,35 @@ namespace MediaBrowser.Controller.Net /// <value>The endpoint.</value> public string Endpoint { get; set; } } + + public class WebSocketConnectingEventArgs : EventArgs + { + /// <summary> + /// Gets or sets the URL. + /// </summary> + /// <value>The URL.</value> + public string Url { get; set; } + /// <summary> + /// Gets or sets the endpoint. + /// </summary> + /// <value>The endpoint.</value> + public string Endpoint { get; set; } + /// <summary> + /// Gets or sets the query string. + /// </summary> + /// <value>The query string.</value> + public NameValueCollection QueryString { get; set; } + /// <summary> + /// Gets or sets a value indicating whether [allow connection]. + /// </summary> + /// <value><c>true</c> if [allow connection]; otherwise, <c>false</c>.</value> + public bool AllowConnection { get; set; } + + public WebSocketConnectingEventArgs() + { + QueryString = new NameValueCollection(); + AllowConnection = true; + } + } + } diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index 4082f5600..b51b590cf 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -279,6 +279,13 @@ namespace MediaBrowser.Controller.Session SessionInfo GetSession(string deviceId, string client, string version); /// <summary> + /// Gets the session by authentication token. + /// </summary> + /// <param name="token">The token.</param> + /// <returns>SessionInfo.</returns> + SessionInfo GetSessionByAuthenticationToken(string token); + + /// <summary> /// Logouts the specified access token. /// </summary> /// <param name="accessToken">The access token.</param> diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs index 4727e6035..f91054206 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -35,6 +35,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer private readonly ContainerAdapter _containerAdapter; public event EventHandler<WebSocketConnectEventArgs> WebSocketConnected; + public event EventHandler<WebSocketConnectingEventArgs> WebSocketConnecting; private readonly List<string> _localEndpoints = new List<string>(); @@ -196,7 +197,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer _listener = GetListener(); - _listener.WebSocketHandler = WebSocketHandler; + _listener.WebSocketConnected = OnWebSocketConnected; + _listener.WebSocketConnecting = OnWebSocketConnecting; _listener.ErrorHandler = ErrorHandler; _listener.RequestHandler = RequestHandler; @@ -208,7 +210,15 @@ namespace MediaBrowser.Server.Implementations.HttpServer return new WebSocketSharpListener(_logger, OnRequestReceived, CertificatePath); } - private void WebSocketHandler(WebSocketConnectEventArgs args) + private void OnWebSocketConnecting(WebSocketConnectingEventArgs args) + { + if (WebSocketConnecting != null) + { + WebSocketConnecting(this, args); + } + } + + private void OnWebSocketConnected(WebSocketConnectEventArgs args) { if (WebSocketConnected != null) { diff --git a/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs b/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs index e77600e93..dc315601f 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs @@ -24,9 +24,15 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// Gets or sets the web socket handler. /// </summary> /// <value>The web socket handler.</value> - Action<WebSocketConnectEventArgs> WebSocketHandler { get; set; } + Action<WebSocketConnectEventArgs> WebSocketConnected { get; set; } /// <summary> + /// Gets or sets the web socket connecting. + /// </summary> + /// <value>The web socket connecting.</value> + Action<WebSocketConnectingEventArgs> WebSocketConnecting { get; set; } + + /// <summary> /// Starts this instance. /// </summary> /// <param name="urlPrefixes">The URL prefixes.</param> diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/SessionContext.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/SessionContext.cs index 9d1ddb7fc..954db3a9d 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/Security/SessionContext.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/Security/SessionContext.cs @@ -23,6 +23,10 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security { var authorization = _authContext.GetAuthorizationInfo(requestContext); + if (!string.IsNullOrWhiteSpace(authorization.Token)) + { + return _sessionManager.GetSessionByAuthenticationToken(authorization.Token); + } return _sessionManager.GetSession(authorization.DeviceId, authorization.Client, authorization.Version); } diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs index 0c5c9e9bf..a223cf68d 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Net; +using System.Collections.Specialized; +using MediaBrowser.Controller.Net; using MediaBrowser.Model.Logging; using MediaBrowser.Server.Implementations.Logging; using ServiceStack; @@ -18,9 +19,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp private readonly ILogger _logger; private readonly Action<string> _endpointListener; - private readonly string _certificatePath ; + private readonly string _certificatePath; - public WebSocketSharpListener(ILogger logger, Action<string> endpointListener, + public WebSocketSharpListener(ILogger logger, Action<string> endpointListener, string certificatePath) { _logger = logger; @@ -32,7 +33,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp public Func<IHttpRequest, Uri, Task> RequestHandler { get; set; } - public Action<WebSocketConnectEventArgs> WebSocketHandler { get; set; } + public Action<WebSocketConnectingEventArgs> WebSocketConnecting { get; set; } + + public Action<WebSocketConnectEventArgs> WebSocketConnected { get; set; } public void Start(IEnumerable<string> urlPrefixes) { @@ -115,15 +118,43 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp { try { - var webSocketContext = ctx.AcceptWebSocket(null); + var endpoint = ctx.Request.RemoteEndPoint.ToString(); + var url = ctx.Request.RawUrl; + var queryString = new NameValueCollection(ctx.Request.QueryString); + + var connectingArgs = new WebSocketConnectingEventArgs + { + Url = url, + QueryString = queryString, + Endpoint = endpoint + }; + + if (WebSocketConnecting != null) + { + WebSocketConnecting(connectingArgs); + } - if (WebSocketHandler != null) + if (connectingArgs.AllowConnection) { - WebSocketHandler(new WebSocketConnectEventArgs + _logger.Debug("Web socket connection allowed"); + + var webSocketContext = ctx.AcceptWebSocket(null); + + if (WebSocketConnected != null) { - WebSocket = new SharpWebSocket(webSocketContext.WebSocket, _logger), - Endpoint = ctx.Request.RemoteEndPoint.ToString() - }); + WebSocketConnected(new WebSocketConnectEventArgs + { + Url = url, + QueryString = queryString, + WebSocket = new SharpWebSocket(webSocketContext.WebSocket, _logger), + Endpoint = endpoint + }); + } + } + else + { + _logger.Warn("Web socket connection not allowed"); + ctx.Response.Close(); } } catch (Exception ex) diff --git a/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs b/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs index dcfb9c449..6428d10a9 100644 --- a/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs +++ b/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs @@ -1,11 +1,14 @@ -using MediaBrowser.Controller; +using MediaBrowser.Common.Events; +using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Net; +using MediaBrowser.Model.Events; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Net; using MediaBrowser.Model.Serialization; using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.Linq; using System.Net.Sockets; using System.Threading; @@ -44,6 +47,8 @@ namespace MediaBrowser.Server.Implementations.ServerManager get { return _webSocketConnections; } } + public event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected; + /// <summary> /// The _logger /// </summary> @@ -140,10 +145,17 @@ namespace MediaBrowser.Server.Implementations.ServerManager { var connection = new WebSocketConnection(e.WebSocket, e.Endpoint, _jsonSerializer, _logger) { - OnReceive = ProcessWebSocketMessageReceived + OnReceive = ProcessWebSocketMessageReceived, + Url = e.Url, + QueryString = new NameValueCollection(e.QueryString) }; _webSocketConnections.Add(connection); + + if (WebSocketConnected != null) + { + EventHelper.FireEventIfNotNull(WebSocketConnected, this, new GenericEventArgs<IWebSocketConnection> (connection), _logger); + } } /// <summary> diff --git a/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs b/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs index 08e4c2ec2..738e82bd0 100644 --- a/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs +++ b/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs @@ -1,10 +1,10 @@ -using System.Text; -using MediaBrowser.Common.Events; +using MediaBrowser.Common.Events; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Net; using MediaBrowser.Model.Serialization; using System; +using System.Collections.Specialized; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -67,6 +67,17 @@ namespace MediaBrowser.Server.Implementations.ServerManager public Guid Id { get; private set; } /// <summary> + /// Gets or sets the URL. + /// </summary> + /// <value>The URL.</value> + public string Url { get; set; } + /// <summary> + /// Gets or sets the query string. + /// </summary> + /// <value>The query string.</value> + public NameValueCollection QueryString { get; set; } + + /// <summary> /// Initializes a new instance of the <see cref="WebSocketConnection" /> class. /// </summary> /// <param name="socket">The socket.</param> diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index 8eef8536a..a09f585fd 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -1640,6 +1640,26 @@ namespace MediaBrowser.Server.Implementations.Session string.Equals(i.Client, client)); } + public SessionInfo GetSessionByAuthenticationToken(string token) + { + var result = _authRepo.Get(new AuthenticationInfoQuery + { + AccessToken = token + }); + + if (result.Items.Length == 0) + { + return null; + } + + var info = result.Items[0]; + + // TODO: Make Token part of SessionInfo and get result that way + // This can't be done until all apps are updated to new authentication. + return Sessions.FirstOrDefault(i => string.Equals(i.DeviceId, info.DeviceId) && + string.Equals(i.Client, info.AppName)); + } + public Task SendMessageToUserSessions<T>(string userId, string name, T data, CancellationToken cancellationToken) { diff --git a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs index d1bb4b837..b581f9144 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs @@ -1,9 +1,12 @@ using MediaBrowser.Controller.Net; +using MediaBrowser.Controller.Security; using MediaBrowser.Controller.Session; +using MediaBrowser.Model.Events; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Session; using System; +using System.Collections.Specialized; using System.Globalization; using System.Linq; using System.Threading.Tasks; @@ -13,7 +16,7 @@ namespace MediaBrowser.Server.Implementations.Session /// <summary> /// Class SessionWebSocketListener /// </summary> - public class SessionWebSocketListener : IWebSocketListener + public class SessionWebSocketListener : IWebSocketListener, IDisposable { /// <summary> /// The _true task result @@ -35,17 +38,75 @@ namespace MediaBrowser.Server.Implementations.Session /// </summary> private readonly IJsonSerializer _json; + private readonly IHttpServer _httpServer; + private readonly IServerManager _serverManager; + + /// <summary> /// Initializes a new instance of the <see cref="SessionWebSocketListener" /> class. /// </summary> /// <param name="sessionManager">The session manager.</param> /// <param name="logManager">The log manager.</param> /// <param name="json">The json.</param> - public SessionWebSocketListener(ISessionManager sessionManager, ILogManager logManager, IJsonSerializer json) + /// <param name="httpServer">The HTTP server.</param> + /// <param name="serverManager">The server manager.</param> + public SessionWebSocketListener(ISessionManager sessionManager, ILogManager logManager, IJsonSerializer json, IHttpServer httpServer, IServerManager serverManager) { _sessionManager = sessionManager; _logger = logManager.GetLogger(GetType().Name); _json = json; + _httpServer = httpServer; + _serverManager = serverManager; + httpServer.WebSocketConnecting += _httpServer_WebSocketConnecting; + serverManager.WebSocketConnected += _serverManager_WebSocketConnected; + } + + void _serverManager_WebSocketConnected(object sender, GenericEventArgs<IWebSocketConnection> e) + { + var session = GetSession(e.Argument.QueryString); + + if (session != null) + { + var controller = session.SessionController as WebSocketController; + + if (controller == null) + { + controller = new WebSocketController(session, _logger, _sessionManager); + } + + controller.AddWebSocket(e.Argument); + + session.SessionController = controller; + } + else + { + _logger.Warn("Unable to determine session based on url: {0}", e.Argument.Url); + } + } + + void _httpServer_WebSocketConnecting(object sender, WebSocketConnectingEventArgs e) + { + if (e.QueryString.AllKeys.Contains("api_key", StringComparer.OrdinalIgnoreCase)) + { + var session = GetSession(e.QueryString); + + if (session == null) + { + e.AllowConnection = false; + } + } + } + + private SessionInfo GetSession(NameValueCollection queryString) + { + var token = queryString["api_key"]; + return _sessionManager.GetSessionByAuthenticationToken(token); + } + + public void Dispose() + { + _httpServer.WebSocketConnecting -= _httpServer_WebSocketConnecting; + _serverManager.WebSocketConnected -= _serverManager_WebSocketConnected; } /// <summary> |
