Fix nullref exception and added logging

This commit is contained in:
Bond_009 2019-12-26 20:57:46 +01:00
parent 976459d3e8
commit 5ca68f9623
6 changed files with 41 additions and 65 deletions

View File

@ -518,30 +518,29 @@ namespace Emby.Server.Implementations.HttpServer
return; return;
} }
var url = context.Request.GetDisplayUrl();
_logger.LogInformation("WS {Url}. UserAgent: {UserAgent}", url, context.Request.Headers[HeaderNames.UserAgent].ToString());
try try
{ {
var webSocket = await context.WebSockets.AcceptWebSocketAsync(null).ConfigureAwait(false); _logger.LogInformation("WS Request from {IP}", context.Connection.RemoteIpAddress);
WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false);
var connection = new WebSocketConnection( var connection = new WebSocketConnection(
_loggerFactory.CreateLogger<WebSocketConnection>(), _loggerFactory.CreateLogger<WebSocketConnection>(),
webSocket, webSocket,
context.Connection.RemoteIpAddress) context.Connection.RemoteIpAddress,
context.Request.Query)
{ {
Url = url,
QueryString = context.Request.Query,
OnReceive = ProcessWebSocketMessageReceived OnReceive = ProcessWebSocketMessageReceived
}; };
WebSocketConnected?.Invoke(this, new GenericEventArgs<IWebSocketConnection>(connection)); WebSocketConnected?.Invoke(this, new GenericEventArgs<IWebSocketConnection>(connection));
await connection.ProcessAsync().ConfigureAwait(false); await connection.ProcessAsync().ConfigureAwait(false);
_logger.LogInformation("WS closed from {IP}", context.Connection.RemoteIpAddress);
} }
catch (WebSocketException ex) catch (Exception ex) // Otherwise ASP.Net will ignore the exception
{ {
_logger.LogError(ex, "ProcessWebSocketRequest error"); _logger.LogError(ex, "WebSocketRequestHandler error");
if (!context.Response.HasStarted) if (!context.Response.HasStarted)
{ {
context.Response.StatusCode = 500; context.Response.StatusCode = 500;

View File

@ -1,4 +1,6 @@
using System; #nullable enable
using System;
using System.Buffers; using System.Buffers;
using System.IO.Pipelines; using System.IO.Pipelines;
using System.Net; using System.Net;
@ -39,47 +41,38 @@ namespace Emby.Server.Implementations.HttpServer
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="WebSocketConnection" /> class. /// Initializes a new instance of the <see cref="WebSocketConnection" /> class.
/// </summary> /// </summary>
/// <param name="logger">The logger.</param>
/// <param name="socket">The socket.</param> /// <param name="socket">The socket.</param>
/// <param name="remoteEndPoint">The remote end point.</param> /// <param name="remoteEndPoint">The remote end point.</param>
/// <param name="logger">The logger.</param> /// <param name="query">The query.</param>
/// <exception cref="ArgumentNullException">socket</exception> public WebSocketConnection(
public WebSocketConnection(ILogger<WebSocketConnection> logger, WebSocket socket, IPAddress remoteEndPoint) ILogger<WebSocketConnection> logger,
WebSocket socket,
IPAddress? remoteEndPoint,
IQueryCollection query)
{ {
if (socket == null) _logger = logger;
{
throw new ArgumentNullException(nameof(socket));
}
if (remoteEndPoint != null)
{
throw new ArgumentNullException(nameof(remoteEndPoint));
}
if (logger == null)
{
throw new ArgumentNullException(nameof(logger));
}
_socket = socket; _socket = socket;
RemoteEndPoint = remoteEndPoint; RemoteEndPoint = remoteEndPoint;
_logger = logger; QueryString = query;
_jsonOptions = JsonDefaults.GetOptions(); _jsonOptions = JsonDefaults.GetOptions();
LastActivityDate = DateTime.Now;
} }
/// <inheritdoc /> /// <inheritdoc />
public event EventHandler<EventArgs> Closed; public event EventHandler<EventArgs>? Closed;
/// <summary> /// <summary>
/// Gets or sets the remote end point. /// Gets or sets the remote end point.
/// </summary> /// </summary>
public IPAddress RemoteEndPoint { get; private set; } public IPAddress? RemoteEndPoint { get; }
/// <summary> /// <summary>
/// Gets or sets the receive action. /// Gets or sets the receive action.
/// </summary> /// </summary>
/// <value>The receive action.</value> /// <value>The receive action.</value>
public Func<WebSocketMessageInfo, Task> OnReceive { get; set; } public Func<WebSocketMessageInfo, Task>? OnReceive { get; set; }
/// <summary> /// <summary>
/// Gets the last activity date. /// Gets the last activity date.
@ -87,17 +80,11 @@ namespace Emby.Server.Implementations.HttpServer
/// <value>The last activity date.</value> /// <value>The last activity date.</value>
public DateTime LastActivityDate { get; private set; } public DateTime LastActivityDate { get; private set; }
/// <summary>
/// Gets or sets the URL.
/// </summary>
/// <value>The URL.</value>
public string Url { get; set; }
/// <summary> /// <summary>
/// Gets or sets the query string. /// Gets or sets the query string.
/// </summary> /// </summary>
/// <value>The query string.</value> /// <value>The query string.</value>
public IQueryCollection QueryString { get; set; } public IQueryCollection QueryString { get; }
/// <summary> /// <summary>
/// Gets the state. /// Gets the state.
@ -115,11 +102,6 @@ namespace Emby.Server.Implementations.HttpServer
/// <exception cref="ArgumentNullException">message</exception> /// <exception cref="ArgumentNullException">message</exception>
public Task SendAsync<T>(WebSocketMessage<T> message, CancellationToken cancellationToken) public Task SendAsync<T>(WebSocketMessage<T> message, CancellationToken cancellationToken)
{ {
if (message == null)
{
throw new ArgumentNullException(nameof(message));
}
var json = JsonSerializer.SerializeToUtf8Bytes(message, _jsonOptions); var json = JsonSerializer.SerializeToUtf8Bytes(message, _jsonOptions);
return _socket.SendAsync(json, WebSocketMessageType.Text, true, cancellationToken); return _socket.SendAsync(json, WebSocketMessageType.Text, true, cancellationToken);
} }
@ -140,7 +122,7 @@ namespace Emby.Server.Implementations.HttpServer
int bytesRead = receiveresult.Count; int bytesRead = receiveresult.Count;
if (bytesRead == 0) if (bytesRead == 0)
{ {
continue; break;
} }
// Tell the PipeWriter how much was read from the Socket // Tell the PipeWriter how much was read from the Socket
@ -154,6 +136,8 @@ namespace Emby.Server.Implementations.HttpServer
break; break;
} }
LastActivityDate = DateTime.UtcNow;
if (receiveresult.EndOfMessage) if (receiveresult.EndOfMessage)
{ {
await ProcessInternal(pipe.Reader).ConfigureAwait(false); await ProcessInternal(pipe.Reader).ConfigureAwait(false);
@ -162,10 +146,7 @@ namespace Emby.Server.Implementations.HttpServer
if (_socket.State == WebSocketState.Open) if (_socket.State == WebSocketState.Open)
{ {
await _socket.CloseAsync( _logger.LogWarning("Stopped reading from websocket before it was closed");
WebSocketCloseStatus.NormalClosure,
string.Empty, // REVIEW: human readable explanation as to why the connection is closed.
cancellationToken).ConfigureAwait(false);
} }
Closed?.Invoke(this, EventArgs.Empty); Closed?.Invoke(this, EventArgs.Empty);
@ -175,8 +156,6 @@ namespace Emby.Server.Implementations.HttpServer
private async Task ProcessInternal(PipeReader reader) private async Task ProcessInternal(PipeReader reader)
{ {
LastActivityDate = DateTime.UtcNow;
if (OnReceive == null) if (OnReceive == null)
{ {
return; return;

View File

@ -1726,6 +1726,7 @@ namespace Emby.Server.Implementations.Session
string.Equals(i.Client, client)); string.Equals(i.Client, client));
} }
/// <inheritdoc />
public SessionInfo GetSessionByAuthenticationToken(AuthenticationInfo info, string deviceId, string remoteEndpoint, string appVersion) public SessionInfo GetSessionByAuthenticationToken(AuthenticationInfo info, string deviceId, string remoteEndpoint, string appVersion)
{ {
if (info == null) if (info == null)
@ -1733,7 +1734,7 @@ namespace Emby.Server.Implementations.Session
throw new ArgumentNullException(nameof(info)); throw new ArgumentNullException(nameof(info));
} }
var user = info.UserId.Equals(Guid.Empty) var user = info.UserId == Guid.Empty
? null ? null
: _userManager.GetUserById(info.UserId); : _userManager.GetUserById(info.UserId);

View File

@ -56,7 +56,7 @@ namespace Emby.Server.Implementations.Session
} }
else else
{ {
_logger.LogWarning("Unable to determine session based on url: {0}", e.Argument.Url); _logger.LogWarning("Unable to determine session based on query string: {0}", e.Argument.QueryString);
} }
} }

View File

@ -53,11 +53,12 @@ namespace Emby.Server.Implementations.Session
private void OnConnectionClosed(object sender, EventArgs e) private void OnConnectionClosed(object sender, EventArgs e)
{ {
_logger.LogDebug("Removing websocket from session {Session}", _session.Id);
var connection = (IWebSocketConnection)sender; var connection = (IWebSocketConnection)sender;
_logger.LogDebug("Removing websocket from session {Session}", _session.Id);
_sockets.Remove(connection); _sockets.Remove(connection);
_sessionManager.CloseIfNeeded(_session); connection.Closed -= OnConnectionClosed;
connection.Dispose(); connection.Dispose();
_sessionManager.CloseIfNeeded(_session);
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -1,3 +1,5 @@
#nullable enable
using System; using System;
using System.Net; using System.Net;
using System.Net.WebSockets; using System.Net.WebSockets;
@ -13,7 +15,7 @@ namespace MediaBrowser.Controller.Net
/// <summary> /// <summary>
/// Occurs when [closed]. /// Occurs when [closed].
/// </summary> /// </summary>
event EventHandler<EventArgs> Closed; event EventHandler<EventArgs>? Closed;
/// <summary> /// <summary>
/// Gets the last activity date. /// Gets the last activity date.
@ -21,23 +23,17 @@ namespace MediaBrowser.Controller.Net
/// <value>The last activity date.</value> /// <value>The last activity date.</value>
DateTime LastActivityDate { get; } DateTime LastActivityDate { get; }
/// <summary>
/// Gets or sets the URL.
/// </summary>
/// <value>The URL.</value>
string Url { get; set; }
/// <summary> /// <summary>
/// Gets or sets the query string. /// Gets or sets the query string.
/// </summary> /// </summary>
/// <value>The query string.</value> /// <value>The query string.</value>
IQueryCollection QueryString { get; set; } IQueryCollection QueryString { get; }
/// <summary> /// <summary>
/// Gets or sets the receive action. /// Gets or sets the receive action.
/// </summary> /// </summary>
/// <value>The receive action.</value> /// <value>The receive action.</value>
Func<WebSocketMessageInfo, Task> OnReceive { get; set; } Func<WebSocketMessageInfo, Task>? OnReceive { get; set; }
/// <summary> /// <summary>
/// Gets the state. /// Gets the state.
@ -49,7 +45,7 @@ namespace MediaBrowser.Controller.Net
/// Gets the remote end point. /// Gets the remote end point.
/// </summary> /// </summary>
/// <value>The remote end point.</value> /// <value>The remote end point.</value>
IPAddress RemoteEndPoint { get; } IPAddress? RemoteEndPoint { get; }
/// <summary> /// <summary>
/// Sends a message asynchronously. /// Sends a message asynchronously.