diff --git a/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnection.cs b/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnection.cs index 8f6b72af564bd253195fa4e3b98848e1dd9d133e..cbdaae61f466a669822d775a391eceb7ae9a6550 100644 --- a/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnection.cs +++ b/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnection.cs @@ -6,6 +6,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; +using System.IO; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Channels; @@ -640,7 +641,8 @@ namespace Microsoft.AspNetCore.SignalR.Client break; } } - else if (result.IsCompleted) + + if (result.IsCompleted) { // Not enough data, and we won't be getting any more data. throw new InvalidOperationException( @@ -717,8 +719,13 @@ namespace Microsoft.AspNetCore.SignalR.Client break; } } - else if (result.IsCompleted) + + if (result.IsCompleted) { + if (!buffer.IsEmpty) + { + throw new InvalidDataException("Connection terminated while reading a message."); + } break; } } diff --git a/src/Microsoft.AspNetCore.SignalR.Core/HubConnectionContext.cs b/src/Microsoft.AspNetCore.SignalR.Core/HubConnectionContext.cs index a446ab3f263e069935e41e8552053ff254519259..5a1049e780422635ea09ecf050421bd4b0a2d9a6 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/HubConnectionContext.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/HubConnectionContext.cs @@ -381,12 +381,9 @@ namespace Microsoft.AspNetCore.SignalR await WriteHandshakeResponseAsync(HandshakeResponseMessage.Empty); return true; } - else - { - _logger.LogInformation("Didn't parse the handshake"); - } } - else if (result.IsCompleted) + + if (result.IsCompleted) { // connection was closed before we ever received a response // can't send a handshake response because there is no longer a connection diff --git a/src/Microsoft.AspNetCore.SignalR.Core/HubConnectionHandler.cs b/src/Microsoft.AspNetCore.SignalR.Core/HubConnectionHandler.cs index abc0f999f5e573e3bd88ee153e1821cbfd925e68..95612f1035914f27ccf9e45ac442035a9e28f2d9 100644 --- a/src/Microsoft.AspNetCore.SignalR.Core/HubConnectionHandler.cs +++ b/src/Microsoft.AspNetCore.SignalR.Core/HubConnectionHandler.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Connections; @@ -199,8 +200,13 @@ namespace Microsoft.AspNetCore.SignalR await _dispatcher.DispatchMessageAsync(connection, message); } } - else if (result.IsCompleted) + + if (result.IsCompleted) { + if (!buffer.IsEmpty) + { + throw new InvalidDataException("Connection terminated while reading a message."); + } break; } } diff --git a/test/Microsoft.AspNetCore.SignalR.Client.Tests/HubConnectionTests.ConnectionLifecycle.cs b/test/Microsoft.AspNetCore.SignalR.Client.Tests/HubConnectionTests.ConnectionLifecycle.cs index ebdfabac441a053aa5e63e10e32c7ea821c9f080..4bb97308af5cb03a9a066e8e17427f778e64e4ab 100644 --- a/test/Microsoft.AspNetCore.SignalR.Client.Tests/HubConnectionTests.ConnectionLifecycle.cs +++ b/test/Microsoft.AspNetCore.SignalR.Client.Tests/HubConnectionTests.ConnectionLifecycle.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Connections; @@ -34,7 +35,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests testConnection.StartAsync, connection => ((TestConnection)connection).DisposeAsync()); builder.Services.AddSingleton<IConnectionFactory>(delegateConnectionFactory); - + return builder.Build(); } @@ -450,6 +451,34 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests } } + [Fact] + public async Task HubConnectionClosesWithErrorIfTerminatedWithPartialMessage() + { + var builder = new HubConnectionBuilder(); + var innerConnection = new TestConnection(); + + var delegateConnectionFactory = new DelegateConnectionFactory( + format => innerConnection.StartAsync(format), + connection => ((TestConnection)connection).DisposeAsync()); + builder.Services.AddSingleton<IConnectionFactory>(delegateConnectionFactory); + + var hubConnection = builder.Build(); + var closedEventTcs = new TaskCompletionSource<Exception>(); + hubConnection.Closed += e => + { + closedEventTcs.SetResult(e); + return Task.CompletedTask; + }; + + await hubConnection.StartAsync().OrTimeout(); + + await innerConnection.Application.Output.WriteAsync(Encoding.UTF8.GetBytes(new[] { '{' })).OrTimeout(); + innerConnection.Application.Output.Complete(); + + var exception = await closedEventTcs.Task.OrTimeout(); + Assert.Equal("Connection terminated while reading a message.", exception.Message); + } + private static async Task ForceLastInvocationToComplete(TestConnection testConnection) { // We need to "complete" the invocation diff --git a/test/Microsoft.AspNetCore.SignalR.Tests/HubConnectionHandlerTests.cs b/test/Microsoft.AspNetCore.SignalR.Tests/HubConnectionHandlerTests.cs index ec8119b19c546df09c55c0753a3f0a3b0e2c694c..e253e7e425b275227e3eb4684731a4a3ae686c0a 100644 --- a/test/Microsoft.AspNetCore.SignalR.Tests/HubConnectionHandlerTests.cs +++ b/test/Microsoft.AspNetCore.SignalR.Tests/HubConnectionHandlerTests.cs @@ -2184,6 +2184,38 @@ namespace Microsoft.AspNetCore.SignalR.Tests } } + [Fact] + public async Task ServerSendsCloseWithErrorWhenConnectionClosedWithPartialMessage() + { + var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(services => + { + services.AddSignalR(options => options.EnableDetailedErrors = true); + }); + var connectionHandler = serviceProvider.GetService<HubConnectionHandler<SimpleHub>>(); + + using (var client = new TestClient()) + { + var connectionHandlerTask = await client.ConnectAsync(connectionHandler).OrTimeout(); + + await client.Connection.Application.Output.WriteAsync(Encoding.UTF8.GetBytes(new[] { '{' })).OrTimeout(); + + // Close connection + client.Connection.Application.Output.Complete(); + + // Ignore message from OnConnectedAsync + await client.ReadAsync().OrTimeout(); + + var closeMessage = Assert.IsType<CloseMessage>(await client.ReadAsync().OrTimeout()); + + Assert.Equal("Connection closed with an error. InvalidDataException: Connection terminated while reading a message.", closeMessage.Error); + + // Shut down + client.Dispose(); + + await connectionHandlerTask.OrTimeout(); + } + } + private class CustomHubActivator<THub> : IHubActivator<THub> where THub : Hub { public int ReleaseCount;