diff --git a/eng/Versions.props b/eng/Versions.props
index e86eb1601c..aa382cd021 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -221,7 +221,7 @@
4.2.1
4.2.1
3.8.0
- 0.1.22-pre2
+ 0.1.22-pre3
3.0.0-preview3.4
3.0.0-preview3.4
3.0.0-preview3.4
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Program.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Program.cs
index 94905231a0..d1f9df7226 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Program.cs
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Program.cs
@@ -15,6 +15,8 @@ namespace GrpcService_CSharp
CreateHostBuilder(args).Build().Run();
}
+ // Additional configuration is required to successfully run gRPC on macOS.
+ // For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
diff --git a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/Angular-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/Angular-CSharp/.template.config/template.json
index 93dd531436..f919655bd8 100644
--- a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/Angular-CSharp/.template.config/template.json
+++ b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/Angular-CSharp/.template.config/template.json
@@ -6,6 +6,7 @@
"SPA"
],
"groupIdentity": "Microsoft.DotNet.Web.Spa.ProjectTemplates.Angular",
+ "precedence": "5000",
"identity": "Microsoft.DotNet.Web.Spa.ProjectTemplates.Angular.CSharp.3.0",
"name": "ASP.NET Core with Angular",
"preferNameDirectory": true,
diff --git a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/React-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/React-CSharp/.template.config/template.json
index 7eff01916f..3c4b69d0b9 100644
--- a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/React-CSharp/.template.config/template.json
+++ b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/React-CSharp/.template.config/template.json
@@ -6,6 +6,7 @@
"SPA"
],
"groupIdentity": "Microsoft.DotNet.Web.Spa.ProjectTemplates.React",
+ "precedence": "5000",
"identity": "Microsoft.DotNet.Web.Spa.ProjectTemplates.React.CSharp.3.0",
"name": "ASP.NET Core with React.js",
"preferNameDirectory": true,
@@ -189,7 +190,6 @@
"binding": "HostIdentifier"
}
},
-
"tags": {
"language": "C#",
"type": "project"
diff --git a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/.template.config/template.json
index 660c888df4..264061a004 100644
--- a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/.template.config/template.json
+++ b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/.template.config/template.json
@@ -6,6 +6,7 @@
"SPA"
],
"groupIdentity": "Microsoft.DotNet.Web.Spa.ProjectTemplates.ReactRedux",
+ "precedence": "5000",
"identity": "Microsoft.DotNet.Web.Spa.ProjectTemplates.ReactRedux.CSharp.3.0",
"name": "ASP.NET Core with React.js and Redux",
"preferNameDirectory": true,
diff --git a/src/SignalR/server/Core/ref/Microsoft.AspNetCore.SignalR.Core.netcoreapp3.0.cs b/src/SignalR/server/Core/ref/Microsoft.AspNetCore.SignalR.Core.netcoreapp3.0.cs
index 6e2f3f1f71..5309dae32c 100644
--- a/src/SignalR/server/Core/ref/Microsoft.AspNetCore.SignalR.Core.netcoreapp3.0.cs
+++ b/src/SignalR/server/Core/ref/Microsoft.AspNetCore.SignalR.Core.netcoreapp3.0.cs
@@ -144,6 +144,7 @@ namespace Microsoft.AspNetCore.SignalR
public HubConnectionContextOptions() { }
public System.TimeSpan ClientTimeoutInterval { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public System.TimeSpan KeepAliveInterval { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
+ public long? MaximumReceiveMessageSize { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public int StreamBufferCapacity { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
}
public partial class HubConnectionHandler : Microsoft.AspNetCore.Connections.ConnectionHandler where THub : Microsoft.AspNetCore.SignalR.Hub
diff --git a/src/SignalR/server/Core/src/HubConnectionContext.cs b/src/SignalR/server/Core/src/HubConnectionContext.cs
index ba3a8a0201..cfc0137b36 100644
--- a/src/SignalR/server/Core/src/HubConnectionContext.cs
+++ b/src/SignalR/server/Core/src/HubConnectionContext.cs
@@ -43,6 +43,7 @@ namespace Microsoft.AspNetCore.SignalR
private bool _clientTimeoutActive;
private bool _connectionAborted;
private int _streamBufferCapacity;
+ private long? _maxMessageSize;
///
/// Initializes a new instance of the class.
@@ -55,6 +56,7 @@ namespace Microsoft.AspNetCore.SignalR
_keepAliveInterval = contextOptions.KeepAliveInterval.Ticks;
_clientTimeoutInterval = contextOptions.ClientTimeoutInterval.Ticks;
_streamBufferCapacity = contextOptions.StreamBufferCapacity;
+ _maxMessageSize = contextOptions.MaximumReceiveMessageSize;
_connectionContext = connectionContext;
_logger = loggerFactory.CreateLogger();
@@ -406,10 +408,20 @@ namespace Microsoft.AspNetCore.SignalR
if (!buffer.IsEmpty)
{
- if (HandshakeProtocol.TryParseRequestMessage(ref buffer, out var handshakeRequestMessage))
+ var segment = buffer;
+ var overLength = false;
+
+ if (_maxMessageSize != null && buffer.Length > _maxMessageSize.Value)
+ {
+ // We give the parser a sliding window of the default message size
+ segment = segment.Slice(segment.Start, _maxMessageSize.Value);
+ overLength = true;
+ }
+
+ if (HandshakeProtocol.TryParseRequestMessage(ref segment, out var handshakeRequestMessage))
{
// We parsed the handshake
- consumed = buffer.Start;
+ consumed = segment.Start;
examined = consumed;
Protocol = protocolResolver.GetProtocol(handshakeRequestMessage.Protocol, supportedProtocols);
@@ -461,6 +473,12 @@ namespace Microsoft.AspNetCore.SignalR
await WriteHandshakeResponseAsync(HandshakeResponseMessage.Empty);
return true;
}
+ else if (overLength)
+ {
+ Log.HandshakeSizeLimitExceeded(_logger, _maxMessageSize.Value);
+ await WriteHandshakeResponseAsync(new HandshakeResponseMessage("Handshake was canceled."));
+ return false;
+ }
}
if (result.IsCompleted)
@@ -619,6 +637,9 @@ namespace Microsoft.AspNetCore.SignalR
private static readonly Action _clientTimeout =
LoggerMessage.Define(LogLevel.Debug, new EventId(9, "ClientTimeout"), "Client timeout ({ClientTimeout}ms) elapsed without receiving a message from the client. Closing connection.");
+ private static readonly Action _handshakeSizeLimitExceeded =
+ LoggerMessage.Define(LogLevel.Debug, new EventId(10, "HandshakeSizeLimitExceeded"), "The maximum message size of {MaxMessageSize}B was exceeded while parsing the Handshake. The message size can be configured in AddHubOptions.");
+
public static void HandshakeComplete(ILogger logger, string hubProtocol)
{
_handshakeComplete(logger, hubProtocol, null);
@@ -663,6 +684,11 @@ namespace Microsoft.AspNetCore.SignalR
{
_clientTimeout(logger, (int)timeout.TotalMilliseconds, null);
}
+
+ public static void HandshakeSizeLimitExceeded(ILogger logger, long maxMessageSize)
+ {
+ _handshakeSizeLimitExceeded(logger, maxMessageSize, null);
+ }
}
}
}
diff --git a/src/SignalR/server/Core/src/HubConnectionContextOptions.cs b/src/SignalR/server/Core/src/HubConnectionContextOptions.cs
index a38096cbef..c95c58afe6 100644
--- a/src/SignalR/server/Core/src/HubConnectionContextOptions.cs
+++ b/src/SignalR/server/Core/src/HubConnectionContextOptions.cs
@@ -24,5 +24,10 @@ namespace Microsoft.AspNetCore.SignalR
/// Gets or sets the max buffer size for client upload streams.
///
public int StreamBufferCapacity { get; set; }
+
+ ///
+ /// Gets or sets the maximum message size the client can send.
+ ///
+ public long? MaximumReceiveMessageSize { get; set; }
}
}
diff --git a/src/SignalR/server/Core/src/HubConnectionHandler.cs b/src/SignalR/server/Core/src/HubConnectionHandler.cs
index de6a3dd3c0..270eb44c0c 100644
--- a/src/SignalR/server/Core/src/HubConnectionHandler.cs
+++ b/src/SignalR/server/Core/src/HubConnectionHandler.cs
@@ -89,6 +89,7 @@ namespace Microsoft.AspNetCore.SignalR
KeepAliveInterval = _hubOptions.KeepAliveInterval ?? _globalHubOptions.KeepAliveInterval ?? HubOptionsSetup.DefaultKeepAliveInterval,
ClientTimeoutInterval = _hubOptions.ClientTimeoutInterval ?? _globalHubOptions.ClientTimeoutInterval ?? HubOptionsSetup.DefaultClientTimeoutInterval,
StreamBufferCapacity = _hubOptions.StreamBufferCapacity ?? _globalHubOptions.StreamBufferCapacity ?? HubOptionsSetup.DefaultStreamBufferCapacity,
+ MaximumReceiveMessageSize = _maximumMessageSize,
};
Log.ConnectedStarting(_logger);
diff --git a/src/SignalR/server/SignalR/test/HubConnectionHandlerTests.cs b/src/SignalR/server/SignalR/test/HubConnectionHandlerTests.cs
index d4188e3918..f2eb574c9d 100644
--- a/src/SignalR/server/SignalR/test/HubConnectionHandlerTests.cs
+++ b/src/SignalR/server/SignalR/test/HubConnectionHandlerTests.cs
@@ -292,6 +292,40 @@ namespace Microsoft.AspNetCore.SignalR.Tests
}
}
+ [Fact]
+ public async Task ConnectionClosedWhenHandshakeLargerThanMaxMessageSize()
+ {
+ using (StartVerifiableLog())
+ {
+ var connectionHandler = HubConnectionHandlerTestUtils.GetHubConnectionHandler(typeof(HubT), loggerFactory: LoggerFactory,
+ builder =>
+ {
+ builder.AddSignalR(o =>
+ {
+ o.MaximumReceiveMessageSize = 1;
+ });
+ });
+
+ using (var client = new TestClient())
+ {
+ client.SupportedFormats = TransferFormat.Text;
+
+ var connectionHandlerTask = await client.ConnectAsync(connectionHandler,
+ sendHandshakeRequestMessage: true,
+ expectedHandshakeResponseMessage: false);
+
+ var message = await client.ReadAsync(isHandshake: true).OrTimeout();
+
+ Assert.Equal("Handshake was canceled.", ((HandshakeResponseMessage)message).Error);
+
+ // Connection closes
+ await connectionHandlerTask.OrTimeout();
+
+ client.Dispose();
+ }
+ }
+ }
+
[Fact]
public async Task SendingHandshakeRequestInChunksWorks()
{