diff --git a/src/Servers/Kestrel/Core/src/Http2Limits.cs b/src/Servers/Kestrel/Core/src/Http2Limits.cs
index 6833ec871ea9..1f5877e812d7 100644
--- a/src/Servers/Kestrel/Core/src/Http2Limits.cs
+++ b/src/Servers/Kestrel/Core/src/Http2Limits.cs
@@ -16,15 +16,15 @@ public class Http2Limits
private int _headerTableSize = (int)Http2PeerSettings.DefaultHeaderTableSize;
private int _maxFrameSize = (int)Http2PeerSettings.DefaultMaxFrameSize;
private int _maxRequestHeaderFieldSize = (int)Http2PeerSettings.DefaultMaxFrameSize;
- private int _initialConnectionWindowSize = 1024 * 128; // Larger than the default 64kb, and larger than any one single stream.
- private int _initialStreamWindowSize = 1024 * 96; // Larger than the default 64kb
+ private int _initialConnectionWindowSize = 1024 * 1024; // Equal to SocketTransportOptions.MaxReadBufferSize and larger than any one single stream.
+ private int _initialStreamWindowSize = 768 * 1024; // Larger than the default 64kb and able to use most (3/4ths) of the connection window by itself.
private TimeSpan _keepAlivePingDelay = TimeSpan.MaxValue;
private TimeSpan _keepAlivePingTimeout = TimeSpan.FromSeconds(20);
///
/// Limits the number of concurrent request streams per HTTP/2 connection. Excess streams will be refused.
///
- /// Value must be greater than 0, defaults to 100.
+ /// Value must be greater than 0, defaults to 100 streams.
///
///
public int MaxStreamsPerConnection
@@ -44,7 +44,7 @@ public int MaxStreamsPerConnection
///
/// Limits the size of the header compression tables, in octets, the HPACK encoder and decoder on the server can use.
///
- /// Value must be greater than or equal to 0, defaults to 4096.
+ /// Value must be greater than or equal to 0, defaults to 4096 octets (4 KiB).
///
///
public int HeaderTableSize
@@ -64,7 +64,7 @@ public int HeaderTableSize
///
/// Indicates the size of the largest frame payload that is allowed to be received, in octets. The size must be between 2^14 and 2^24-1.
///
- /// Value must be between 2^14 and 2^24, defaults to 2^14 (16,384).
+ /// Value must be between 2^14 and 2^24, defaults to 2^14 octets (16 KiB).
///
///
public int MaxFrameSize
@@ -82,9 +82,9 @@ public int MaxFrameSize
}
///
- /// Indicates the size of the maximum allowed size of a request header field sequence. This limit applies to both name and value sequences in their compressed and uncompressed representations.
+ /// Indicates the size of the maximum allowed size of a request header field sequence, in octets. This limit applies to both name and value sequences in their compressed and uncompressed representations.
///
- /// Value must be greater than 0, defaults to 2^14 (16,384).
+ /// Value must be greater than 0, defaults to 2^14 octets (16 KiB).
///
///
public int MaxRequestHeaderFieldSize
@@ -102,10 +102,10 @@ public int MaxRequestHeaderFieldSize
}
///
- /// Indicates how much request body data the server is willing to receive and buffer at a time aggregated across all
+ /// Indicates how much request body data, in bytes, the server is willing to receive and buffer at a time aggregated across all
/// requests (streams) per connection. Note requests are also limited by
///
- /// Value must be greater than or equal to 65,535 and less than 2^31, defaults to 128 kb.
+ /// Value must be greater than or equal to 64 KiB and less than 2 GiB, defaults to 1 MiB.
///
///
public int InitialConnectionWindowSize
@@ -124,10 +124,11 @@ public int InitialConnectionWindowSize
}
///
- /// Indicates how much request body data the server is willing to receive and buffer at a time per stream.
- /// Note connections are also limited by
+ /// Indicates how much request body data, in bytes, the server is willing to receive and buffer at a time per stream.
+ /// Note connections are also limited by . There must be space in both the stream
+ /// window and connection window for a client to upload request body data.
///
- /// Value must be greater than or equal to 65,535 and less than 2^31, defaults to 96 kb.
+ /// Value must be greater than or equal to 64 KiB and less than 2 GiB, defaults to 768 KiB.
///
///
public int InitialStreamWindowSize
diff --git a/src/Servers/Kestrel/Transport.Sockets/src/SocketTransportOptions.cs b/src/Servers/Kestrel/Transport.Sockets/src/SocketTransportOptions.cs
index 3483cf03fbd7..a43c1ab7a646 100644
--- a/src/Servers/Kestrel/Transport.Sockets/src/SocketTransportOptions.cs
+++ b/src/Servers/Kestrel/Transport.Sockets/src/SocketTransportOptions.cs
@@ -41,18 +41,32 @@ public class SocketTransportOptions
/// The maximum length of the pending connection queue.
///
///
- /// Defaults to 512.
+ /// Defaults to 512 pending connections.
///
public int Backlog { get; set; } = 512;
///
/// Gets or sets the maximum unconsumed incoming bytes the transport will buffer.
+ ///
+ /// A value of or 0 disables backpressure entirely allowing unlimited buffering.
+ /// Unlimited server buffering is a security risk given untrusted clients.
+ ///
///
+ ///
+ /// Defaults to 1 MiB.
+ ///
public long? MaxReadBufferSize { get; set; } = 1024 * 1024;
///
/// Gets or sets the maximum outgoing bytes the transport will buffer before applying write backpressure.
+ ///
+ /// A value of or 0 disables backpressure entirely allowing unlimited buffering.
+ /// Unlimited server buffering is a security risk given untrusted clients.
+ ///
///
+ ///
+ /// Defaults to 64 KiB.
+ ///
public long? MaxWriteBufferSize { get; set; } = 64 * 1024;
///
@@ -65,6 +79,9 @@ public class SocketTransportOptions
/// This setting can make performance worse if there is expensive work that will end up holding onto the IO thread for longer than needed.
/// Test to make sure this setting helps performance.
///
+ ///
+ /// Defaults to false.
+ ///
public bool UnsafePreferInlineScheduling { get; set; }
///
@@ -77,6 +94,9 @@ public class SocketTransportOptions
/// calls as part of its implementation, so implementors
/// using this method do not need to call it again.
///
+ ///
+ /// Defaults to .
+ ///
public Func CreateBoundListenSocket { get; set; } = CreateDefaultBoundListenSocket;
///
diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs
index 0cacdb447eb7..e2d71746cb82 100644
--- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs
+++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs
@@ -1345,6 +1345,10 @@ await ExpectAsync(Http2FrameType.HEADERS,
[Fact]
public async Task DATA_BufferRequestBodyLargerThanStreamSizeSmallerThanConnectionPipe_Works()
{
+ // This test was not written to allow for arbitrary initial stream sizes. It was tuned to the old defaults.
+ _serviceContext.ServerOptions.Limits.Http2.InitialConnectionWindowSize = 128 * 1024;
+ _serviceContext.ServerOptions.Limits.Http2.InitialStreamWindowSize = 96 * 1024;
+
var initialStreamWindowSize = _serviceContext.ServerOptions.Limits.Http2.InitialStreamWindowSize;
var framesInStreamWindow = initialStreamWindowSize / Http2PeerSettings.DefaultMaxFrameSize;
var initialConnectionWindowSize = _serviceContext.ServerOptions.Limits.Http2.InitialConnectionWindowSize;
@@ -3374,7 +3378,7 @@ public async Task SETTINGS_KestrelDefaults_Sent()
setting = settings[1];
Assert.Equal(Http2SettingsParameter.SETTINGS_INITIAL_WINDOW_SIZE, setting.Parameter);
- Assert.Equal(96 * 1024u, setting.Value);
+ Assert.Equal(768 * 1024u, setting.Value);
setting = settings[2];
Assert.Equal(Http2SettingsParameter.SETTINGS_MAX_HEADER_LIST_SIZE, setting.Parameter);
@@ -3389,7 +3393,7 @@ public async Task SETTINGS_KestrelDefaults_Sent()
withFlags: (byte)Http2SettingsFrameFlags.NONE,
withStreamId: 0);
- Assert.Equal(1024 * 128 - (int)Http2PeerSettings.DefaultInitialWindowSize, update.WindowUpdateSizeIncrement);
+ Assert.Equal(1024 * 1024 - (int)Http2PeerSettings.DefaultInitialWindowSize, update.WindowUpdateSizeIncrement);
await ExpectAsync(Http2FrameType.SETTINGS,
withLength: 0,
@@ -3448,7 +3452,7 @@ public async Task SETTINGS_Custom_Sent()
withFlags: (byte)Http2SettingsFrameFlags.NONE,
withStreamId: 0);
- Assert.Equal(1024 * 128u - Http2PeerSettings.DefaultInitialWindowSize, (uint)update.WindowUpdateSizeIncrement);
+ Assert.Equal(1024 * 1024u - Http2PeerSettings.DefaultInitialWindowSize, (uint)update.WindowUpdateSizeIncrement);
await ExpectAsync(Http2FrameType.SETTINGS,
withLength: 0,
diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http3/Http3TimeoutTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http3/Http3TimeoutTests.cs
index 45a0dd5f1901..fb741c527cb3 100644
--- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http3/Http3TimeoutTests.cs
+++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http3/Http3TimeoutTests.cs
@@ -5,6 +5,7 @@
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http3;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Logging;
diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/HttpProtocolSelectionTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/HttpProtocolSelectionTests.cs
index 753a1cc0e206..16a890852584 100644
--- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/HttpProtocolSelectionTests.cs
+++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/HttpProtocolSelectionTests.cs
@@ -43,12 +43,12 @@ public Task Server_Http2Only_Cleartext_Success()
0x00, 0x00, 0x18, // Payload Length (6 * settings count)
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // SETTINGS frame (type 0x04)
0x00, 0x03, 0x00, 0x00, 0x00, 0x64, // Connection limit (100)
- 0x00, 0x04, 0x00, 0x01, 0x80, 0x00, // Initial stream window size (96 KiB)
+ 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, // Initial stream window size (768 KiB)
0x00, 0x06, 0x00, 0x00, 0x80, 0x00, // Header size limit (32 KiB)
0x00, 0x08, 0x00, 0x00, 0x00, 0x01, // CONNECT enabled
0x00, 0x00, 0x04, // Payload Length (4)
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // WINDOW_UPDATE frame (type 0x08)
- 0x00, 0x01, 0x00, 0x01, // Diff between configured and protocol default (128 KiB - 0XFFFF)
+ 0x00, 0x0F, 0x00, 0x01, // Diff between configured and protocol default (1 MiB - 0XFFFF)
};
return TestSuccess(HttpProtocols.Http2,