-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Add option to restrict the maximum hub message size #8135
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -72,7 +72,7 @@ public static IServiceProvider CreateServiceProvider(Action<ServiceCollection> a | |
return services.BuildServiceProvider(); | ||
} | ||
|
||
public static Connections.ConnectionHandler GetHubConnectionHandler(Type hubType, Action<ServiceCollection> addServices = null, ILoggerFactory loggerFactory = null) | ||
public static Connections.ConnectionHandler GetHubConnectionHandler(Type hubType, ILoggerFactory loggerFactory = null, Action<ServiceCollection> addServices = null) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lambdas should be last. |
||
{ | ||
var serviceProvider = CreateServiceProvider(addServices, loggerFactory); | ||
return (Connections.ConnectionHandler)serviceProvider.GetService(GetConnectionHandlerType(hubType)); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
using System.Buffers; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Security.Claims; | ||
using System.Text; | ||
|
@@ -452,6 +453,191 @@ public async Task HandshakeSuccessSendsResponseWithoutError() | |
} | ||
} | ||
|
||
[Fact] | ||
public async Task HubMessageOverTheMaxMessageSizeThrows() | ||
{ | ||
var payload = Encoding.UTF8.GetBytes("{\"type\":1, \"invocationId\":\"1\", \"target\": \"Echo\", \"arguments\":[\"hello\"]}\u001e"); | ||
var maximumMessageSize = payload.Length - 10; | ||
InvalidDataException exception = null; | ||
|
||
bool ExpectedErrors(WriteContext writeContext) | ||
{ | ||
if (writeContext.LoggerName == "Microsoft.AspNetCore.SignalR.HubConnectionHandler" && (writeContext.Exception is InvalidDataException ide)) | ||
{ | ||
exception = ide; | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
using (StartVerifiableLog(ExpectedErrors)) | ||
{ | ||
var connectionHandler = HubConnectionHandlerTestUtils.GetHubConnectionHandler(typeof(HubT), LoggerFactory, | ||
services => services.AddSignalR().AddHubOptions<HubT>(o => o.MaximumReceiveMessageSize = maximumMessageSize)); | ||
|
||
using (var client = new TestClient()) | ||
{ | ||
var connectionHandlerTask = await client.ConnectAsync(connectionHandler); | ||
|
||
await client.Connection.Application.Output.WriteAsync(payload); | ||
|
||
client.Dispose(); | ||
|
||
await connectionHandlerTask.OrTimeout(); | ||
} | ||
} | ||
|
||
Assert.NotNull(exception); | ||
Assert.Equal(exception.Message, $"The maximum message size of {maximumMessageSize}B was exceeded. The message size can be configured in AddHubOptions."); | ||
} | ||
|
||
[Fact] | ||
public async Task ChunkedHubMessageOverTheMaxMessageSizeThrows() | ||
{ | ||
var payload = Encoding.UTF8.GetBytes("{\"type\":1, \"invocationId\":\"1\", \"target\": \"Echo\", \"arguments\":[\"hello\"]}\u001e"); | ||
var maximumMessageSize = payload.Length - 10; | ||
InvalidDataException exception = null; | ||
|
||
bool ExpectedErrors(WriteContext writeContext) | ||
{ | ||
if (writeContext.LoggerName == "Microsoft.AspNetCore.SignalR.HubConnectionHandler" && (writeContext.Exception is InvalidDataException ide)) | ||
{ | ||
exception = ide; | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
using (StartVerifiableLog(ExpectedErrors)) | ||
{ | ||
var connectionHandler = HubConnectionHandlerTestUtils.GetHubConnectionHandler(typeof(HubT), LoggerFactory, | ||
services => services.AddSignalR().AddHubOptions<HubT>(o => o.MaximumReceiveMessageSize = maximumMessageSize)); | ||
|
||
using (var client = new TestClient()) | ||
{ | ||
var connectionHandlerTask = await client.ConnectAsync(connectionHandler); | ||
|
||
await client.Connection.Application.Output.WriteAsync(payload.AsMemory(0, payload.Length / 2)); | ||
await client.Connection.Application.Output.WriteAsync(payload.AsMemory(payload.Length / 2)); | ||
|
||
client.Dispose(); | ||
|
||
await connectionHandlerTask.OrTimeout(); | ||
} | ||
} | ||
|
||
Assert.NotNull(exception); | ||
Assert.Equal(exception.Message, $"The maximum message size of {maximumMessageSize}B was exceeded. The message size can be configured in AddHubOptions."); | ||
} | ||
|
||
[Fact] | ||
public async Task ManyHubMessagesOneOverTheMaxMessageSizeThrows() | ||
{ | ||
var payload1 = Encoding.UTF8.GetBytes("{\"type\":1, \"invocationId\":\"1\", \"target\": \"Echo\", \"arguments\":[\"one\"]}\u001e"); | ||
var payload2 = Encoding.UTF8.GetBytes("{\"type\":1, \"invocationId\":\"2\", \"target\": \"Echo\", \"arguments\":[\"two\"]}\u001e"); | ||
var payload3 = Encoding.UTF8.GetBytes("{\"type\":1, \"invocationId\":\"3\", \"target\": \"Echo\", \"arguments\":[\"three\"]}\u001e"); | ||
|
||
// Between the first and the second payload so we'll end up slicing with some remaining in the slice for | ||
// the next message | ||
var maximumMessageSize = payload1.Length + 1; | ||
InvalidDataException exception = null; | ||
|
||
bool ExpectedErrors(WriteContext writeContext) | ||
{ | ||
if (writeContext.LoggerName == "Microsoft.AspNetCore.SignalR.HubConnectionHandler" && (writeContext.Exception is InvalidDataException ide)) | ||
{ | ||
exception = ide; | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
using (StartVerifiableLog(ExpectedErrors)) | ||
{ | ||
var connectionHandler = HubConnectionHandlerTestUtils.GetHubConnectionHandler(typeof(HubT), LoggerFactory, | ||
services => services.AddSignalR().AddHubOptions<HubT>(o => o.MaximumReceiveMessageSize = maximumMessageSize)); | ||
|
||
using (var client = new TestClient()) | ||
{ | ||
var connectionHandlerTask = await client.ConnectAsync(connectionHandler); | ||
|
||
client.Connection.Application.Output.Write(payload1); | ||
client.Connection.Application.Output.Write(payload2); | ||
client.Connection.Application.Output.Write(payload3); | ||
await client.Connection.Application.Output.FlushAsync(); | ||
|
||
// 2 invocations should be processed | ||
var completionMessage = await client.ReadAsync().OrTimeout() as CompletionMessage; | ||
Assert.NotNull(completionMessage); | ||
Assert.Equal("1", completionMessage.InvocationId); | ||
Assert.Equal("one", completionMessage.Result); | ||
|
||
completionMessage = await client.ReadAsync().OrTimeout() as CompletionMessage; | ||
Assert.NotNull(completionMessage); | ||
Assert.Equal("2", completionMessage.InvocationId); | ||
Assert.Equal("two", completionMessage.Result); | ||
|
||
// We never receive the 3rd message since it was over the maximum message size | ||
CloseMessage closeMessage = await client.ReadAsync().OrTimeout() as CloseMessage; | ||
Assert.NotNull(closeMessage); | ||
|
||
client.Dispose(); | ||
|
||
await connectionHandlerTask.OrTimeout(); | ||
} | ||
} | ||
|
||
Assert.NotNull(exception); | ||
Assert.Equal(exception.Message, $"The maximum message size of {maximumMessageSize}B was exceeded. The message size can be configured in AddHubOptions."); | ||
} | ||
|
||
[Fact] | ||
public async Task ManyHubMessagesUnderTheMessageSizeButConfiguredWithMax() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good test 👍 |
||
{ | ||
var payload1 = Encoding.UTF8.GetBytes("{\"type\":1, \"invocationId\":\"1\", \"target\": \"Echo\", \"arguments\":[\"one\"]}\u001e"); | ||
var payload2 = Encoding.UTF8.GetBytes("{\"type\":1, \"invocationId\":\"2\", \"target\": \"Echo\", \"arguments\":[\"two\"]}\u001e"); | ||
var payload3 = Encoding.UTF8.GetBytes("{\"type\":1, \"invocationId\":\"3\", \"target\": \"Echo\", \"arguments\":[\"three\"]}\u001e"); | ||
|
||
// Bigger than all 3 messages | ||
var maximumMessageSize = payload3.Length + 10; | ||
|
||
using (StartVerifiableLog()) | ||
{ | ||
var connectionHandler = HubConnectionHandlerTestUtils.GetHubConnectionHandler(typeof(HubT), LoggerFactory, | ||
services => services.AddSignalR().AddHubOptions<HubT>(o => o.MaximumReceiveMessageSize = maximumMessageSize)); | ||
|
||
using (var client = new TestClient()) | ||
{ | ||
var connectionHandlerTask = await client.ConnectAsync(connectionHandler); | ||
|
||
client.Connection.Application.Output.Write(payload1); | ||
client.Connection.Application.Output.Write(payload2); | ||
client.Connection.Application.Output.Write(payload3); | ||
await client.Connection.Application.Output.FlushAsync(); | ||
|
||
// 2 invocations should be processed | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: 3 |
||
var completionMessage = await client.ReadAsync().OrTimeout() as CompletionMessage; | ||
Assert.NotNull(completionMessage); | ||
Assert.Equal("1", completionMessage.InvocationId); | ||
Assert.Equal("one", completionMessage.Result); | ||
|
||
completionMessage = await client.ReadAsync().OrTimeout() as CompletionMessage; | ||
Assert.NotNull(completionMessage); | ||
Assert.Equal("2", completionMessage.InvocationId); | ||
Assert.Equal("two", completionMessage.Result); | ||
|
||
completionMessage = await client.ReadAsync().OrTimeout() as CompletionMessage; | ||
Assert.NotNull(completionMessage); | ||
Assert.Equal("3", completionMessage.InvocationId); | ||
Assert.Equal("three", completionMessage.Result); | ||
|
||
client.Dispose(); | ||
|
||
await connectionHandlerTask.OrTimeout(); | ||
} | ||
} | ||
} | ||
|
||
[Fact] | ||
public async Task HandshakeFailureFromIncompatibleProtocolVersionSendsResponseWithError() | ||
{ | ||
|
@@ -2789,7 +2975,7 @@ public async Task UploadManyStreams() | |
|
||
foreach (string id in ids) | ||
{ | ||
await client.BeginUploadStreamAsync("invocation_"+id, nameof(MethodHub.StreamingConcat), new[] { id }, Array.Empty<object>()); | ||
await client.BeginUploadStreamAsync("invocation_" + id, nameof(MethodHub.StreamingConcat), new[] { id }, Array.Empty<object>()); | ||
} | ||
|
||
var words = new[] { "zygapophyses", "qwerty", "abcd" }; | ||
|
@@ -2868,7 +3054,7 @@ public async Task UploadStreamItemInvalidTypeAutoCasts() | |
} | ||
} | ||
} | ||
|
||
[Fact] | ||
public async Task ServerReportsProtocolMinorVersion() | ||
{ | ||
|
@@ -2881,7 +3067,7 @@ public async Task ServerReportsProtocolMinorVersion() | |
testProtocol.Setup(m => m.TransferFormat).Returns(TransferFormat.Binary); | ||
|
||
var connectionHandler = HubConnectionHandlerTestUtils.GetHubConnectionHandler(typeof(HubT), | ||
(services) => services.AddSingleton<IHubProtocol>(testProtocol.Object), LoggerFactory); | ||
LoggerFactory, (services) => services.AddSingleton<IHubProtocol>(testProtocol.Object)); | ||
|
||
using (var client = new TestClient(protocol: testProtocol.Object)) | ||
{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Null means no maximum message size" or is that implicit with nullable types