Skip to content

Commit 21c8bec

Browse files
[release/7.0-rc1] Increase Kestrel's default HTTP/2 upload window sizes (#43324)
1 parent def580f commit 21c8bec

File tree

4 files changed

+43
-18
lines changed

4 files changed

+43
-18
lines changed

src/Servers/Kestrel/Core/src/Http2Limits.cs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ public class Http2Limits
1616
private int _headerTableSize = (int)Http2PeerSettings.DefaultHeaderTableSize;
1717
private int _maxFrameSize = (int)Http2PeerSettings.DefaultMaxFrameSize;
1818
private int _maxRequestHeaderFieldSize = (int)Http2PeerSettings.DefaultMaxFrameSize;
19-
private int _initialConnectionWindowSize = 1024 * 128; // Larger than the default 64kb, and larger than any one single stream.
20-
private int _initialStreamWindowSize = 1024 * 96; // Larger than the default 64kb
19+
private int _initialConnectionWindowSize = 1024 * 1024; // Equal to SocketTransportOptions.MaxReadBufferSize and larger than any one single stream.
20+
private int _initialStreamWindowSize = 768 * 1024; // Larger than the default 64kb and able to use most (3/4ths) of the connection window by itself.
2121
private TimeSpan _keepAlivePingDelay = TimeSpan.MaxValue;
2222
private TimeSpan _keepAlivePingTimeout = TimeSpan.FromSeconds(20);
2323

2424
/// <summary>
2525
/// Limits the number of concurrent request streams per HTTP/2 connection. Excess streams will be refused.
2626
/// <para>
27-
/// Value must be greater than 0, defaults to 100.
27+
/// Value must be greater than 0, defaults to 100 streams.
2828
/// </para>
2929
/// </summary>
3030
public int MaxStreamsPerConnection
@@ -44,7 +44,7 @@ public int MaxStreamsPerConnection
4444
/// <summary>
4545
/// Limits the size of the header compression tables, in octets, the HPACK encoder and decoder on the server can use.
4646
/// <para>
47-
/// Value must be greater than or equal to 0, defaults to 4096.
47+
/// Value must be greater than or equal to 0, defaults to 4096 octets (4 KiB).
4848
/// </para>
4949
/// </summary>
5050
public int HeaderTableSize
@@ -64,7 +64,7 @@ public int HeaderTableSize
6464
/// <summary>
6565
/// 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.
6666
/// <para>
67-
/// Value must be between 2^14 and 2^24, defaults to 2^14 (16,384).
67+
/// Value must be between 2^14 and 2^24, defaults to 2^14 octets (16 KiB).
6868
/// </para>
6969
/// </summary>
7070
public int MaxFrameSize
@@ -82,9 +82,9 @@ public int MaxFrameSize
8282
}
8383

8484
/// <summary>
85-
/// 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.
85+
/// 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.
8686
/// <para>
87-
/// Value must be greater than 0, defaults to 2^14 (16,384).
87+
/// Value must be greater than 0, defaults to 2^14 octets (16 KiB).
8888
/// </para>
8989
/// </summary>
9090
public int MaxRequestHeaderFieldSize
@@ -102,10 +102,10 @@ public int MaxRequestHeaderFieldSize
102102
}
103103

104104
/// <summary>
105-
/// Indicates how much request body data the server is willing to receive and buffer at a time aggregated across all
105+
/// Indicates how much request body data, in bytes, the server is willing to receive and buffer at a time aggregated across all
106106
/// requests (streams) per connection. Note requests are also limited by <see cref="InitialStreamWindowSize"/>
107107
/// <para>
108-
/// Value must be greater than or equal to 65,535 and less than 2^31, defaults to 128 kb.
108+
/// Value must be greater than or equal to 64 KiB and less than 2 GiB, defaults to 1 MiB.
109109
/// </para>
110110
/// </summary>
111111
public int InitialConnectionWindowSize
@@ -124,10 +124,11 @@ public int InitialConnectionWindowSize
124124
}
125125

126126
/// <summary>
127-
/// Indicates how much request body data the server is willing to receive and buffer at a time per stream.
128-
/// Note connections are also limited by <see cref="InitialConnectionWindowSize"/>
127+
/// Indicates how much request body data, in bytes, the server is willing to receive and buffer at a time per stream.
128+
/// Note connections are also limited by <see cref="InitialConnectionWindowSize"/>. There must be space in both the stream
129+
/// window and connection window for a client to upload request body data.
129130
/// <para>
130-
/// Value must be greater than or equal to 65,535 and less than 2^31, defaults to 96 kb.
131+
/// Value must be greater than or equal to 64 KiB and less than 2 GiB, defaults to 768 KiB.
131132
/// </para>
132133
/// </summary>
133134
public int InitialStreamWindowSize

src/Servers/Kestrel/Transport.Sockets/src/SocketTransportOptions.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,32 @@ public class SocketTransportOptions
4141
/// The maximum length of the pending connection queue.
4242
/// </summary>
4343
/// <remarks>
44-
/// Defaults to 512.
44+
/// Defaults to 512 pending connections.
4545
/// </remarks>
4646
public int Backlog { get; set; } = 512;
4747

4848
/// <summary>
4949
/// Gets or sets the maximum unconsumed incoming bytes the transport will buffer.
50+
/// <para>
51+
/// A value of <see langword="null"/> or 0 disables backpressure entirely allowing unlimited buffering.
52+
/// Unlimited server buffering is a security risk given untrusted clients.
53+
/// </para>
5054
/// </summary>
55+
/// <remarks>
56+
/// Defaults to 1 MiB.
57+
/// </remarks>
5158
public long? MaxReadBufferSize { get; set; } = 1024 * 1024;
5259

5360
/// <summary>
5461
/// Gets or sets the maximum outgoing bytes the transport will buffer before applying write backpressure.
62+
/// <para>
63+
/// A value of <see langword="null"/> or 0 disables backpressure entirely allowing unlimited buffering.
64+
/// Unlimited server buffering is a security risk given untrusted clients.
65+
/// </para>
5566
/// </summary>
67+
/// <remarks>
68+
/// Defaults to 64 KiB.
69+
/// </remarks>
5670
public long? MaxWriteBufferSize { get; set; } = 64 * 1024;
5771

5872
/// <summary>
@@ -65,6 +79,9 @@ public class SocketTransportOptions
6579
/// This setting can make performance worse if there is expensive work that will end up holding onto the IO thread for longer than needed.
6680
/// Test to make sure this setting helps performance.
6781
/// </remarks>
82+
/// <remarks>
83+
/// Defaults to false.
84+
/// </remarks>
6885
public bool UnsafePreferInlineScheduling { get; set; }
6986

7087
/// <summary>
@@ -77,6 +94,9 @@ public class SocketTransportOptions
7794
/// calls <see cref="Socket.Bind"/> as part of its implementation, so implementors
7895
/// using this method do not need to call it again.
7996
/// </remarks>
97+
/// <remarks>
98+
/// Defaults to <see cref="CreateDefaultBoundListenSocket"/>.
99+
/// </remarks>
80100
public Func<EndPoint, Socket> CreateBoundListenSocket { get; set; } = CreateDefaultBoundListenSocket;
81101

82102
/// <summary>

src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,6 +1345,10 @@ await ExpectAsync(Http2FrameType.HEADERS,
13451345
[Fact]
13461346
public async Task DATA_BufferRequestBodyLargerThanStreamSizeSmallerThanConnectionPipe_Works()
13471347
{
1348+
// This test was not written to allow for arbitrary initial stream sizes. It was tuned to the old defaults.
1349+
_serviceContext.ServerOptions.Limits.Http2.InitialConnectionWindowSize = 128 * 1024;
1350+
_serviceContext.ServerOptions.Limits.Http2.InitialStreamWindowSize = 96 * 1024;
1351+
13481352
var initialStreamWindowSize = _serviceContext.ServerOptions.Limits.Http2.InitialStreamWindowSize;
13491353
var framesInStreamWindow = initialStreamWindowSize / Http2PeerSettings.DefaultMaxFrameSize;
13501354
var initialConnectionWindowSize = _serviceContext.ServerOptions.Limits.Http2.InitialConnectionWindowSize;
@@ -3374,7 +3378,7 @@ public async Task SETTINGS_KestrelDefaults_Sent()
33743378

33753379
setting = settings[1];
33763380
Assert.Equal(Http2SettingsParameter.SETTINGS_INITIAL_WINDOW_SIZE, setting.Parameter);
3377-
Assert.Equal(96 * 1024u, setting.Value);
3381+
Assert.Equal(768 * 1024u, setting.Value);
33783382

33793383
setting = settings[2];
33803384
Assert.Equal(Http2SettingsParameter.SETTINGS_MAX_HEADER_LIST_SIZE, setting.Parameter);
@@ -3389,7 +3393,7 @@ public async Task SETTINGS_KestrelDefaults_Sent()
33893393
withFlags: (byte)Http2SettingsFrameFlags.NONE,
33903394
withStreamId: 0);
33913395

3392-
Assert.Equal(1024 * 128 - (int)Http2PeerSettings.DefaultInitialWindowSize, update.WindowUpdateSizeIncrement);
3396+
Assert.Equal(1024 * 1024 - (int)Http2PeerSettings.DefaultInitialWindowSize, update.WindowUpdateSizeIncrement);
33933397

33943398
await ExpectAsync(Http2FrameType.SETTINGS,
33953399
withLength: 0,
@@ -3448,7 +3452,7 @@ public async Task SETTINGS_Custom_Sent()
34483452
withFlags: (byte)Http2SettingsFrameFlags.NONE,
34493453
withStreamId: 0);
34503454

3451-
Assert.Equal(1024 * 128u - Http2PeerSettings.DefaultInitialWindowSize, (uint)update.WindowUpdateSizeIncrement);
3455+
Assert.Equal(1024 * 1024u - Http2PeerSettings.DefaultInitialWindowSize, (uint)update.WindowUpdateSizeIncrement);
34523456

34533457
await ExpectAsync(Http2FrameType.SETTINGS,
34543458
withLength: 0,

src/Servers/Kestrel/test/InMemory.FunctionalTests/HttpProtocolSelectionTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,12 @@ public Task Server_Http2Only_Cleartext_Success()
4343
0x00, 0x00, 0x18, // Payload Length (6 * settings count)
4444
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // SETTINGS frame (type 0x04)
4545
0x00, 0x03, 0x00, 0x00, 0x00, 0x64, // Connection limit (100)
46-
0x00, 0x04, 0x00, 0x01, 0x80, 0x00, // Initial stream window size (96 KiB)
46+
0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, // Initial stream window size (768 KiB)
4747
0x00, 0x06, 0x00, 0x00, 0x80, 0x00, // Header size limit (32 KiB)
4848
0x00, 0x08, 0x00, 0x00, 0x00, 0x01, // CONNECT enabled
4949
0x00, 0x00, 0x04, // Payload Length (4)
5050
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // WINDOW_UPDATE frame (type 0x08)
51-
0x00, 0x01, 0x00, 0x01, // Diff between configured and protocol default (128 KiB - 0XFFFF)
51+
0x00, 0x0F, 0x00, 0x01, // Diff between configured and protocol default (1 MiB - 0XFFFF)
5252
};
5353

5454
return TestSuccess(HttpProtocols.Http2,

0 commit comments

Comments
 (0)