diff options
author | Carlos Sanchez <1175054+carlossanlop@users.noreply.github.com> | 2022-05-11 05:12:57 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-11 05:12:57 +0300 |
commit | 4aadfea70082ae23e6c54a449268341e9429434e (patch) | |
tree | 40ca76ac8df97a2ee75519a1ec821957007449f0 | |
parent | f3cd2f06521e3793da7667e05a629ecb0e2dadf5 (diff) | |
parent | 6a984143635bde23e728abaaccbde52f5ea8fa3e (diff) |
Merge pull request #69152 from vseanreesermsft/internal-merge-5.0-2022-05-10-1213v5.0.18release/5.0
Merging internal commits for release/5.0
3 files changed, 62 insertions, 6 deletions
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ChunkedEncodingReadStream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ChunkedEncodingReadStream.cs index b9ccbcef76d..06b541f7662 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ChunkedEncodingReadStream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ChunkedEncodingReadStream.cs @@ -21,8 +21,6 @@ namespace System.Net.Http /// infinite chunk length is sent. This value is arbitrary and can be changed as needed. /// </remarks> private const int MaxChunkBytesAllowed = 16 * 1024; - /// <summary>How long a trailing header can be. This value is arbitrary and can be changed as needed.</summary> - private const int MaxTrailingHeaderLength = 16 * 1024; /// <summary>The number of bytes remaining in the chunk.</summary> private ulong _chunkBytesRemaining; /// <summary>The current state of the parsing state machine for the chunked response.</summary> @@ -297,6 +295,9 @@ namespace System.Net.Http else { _state = ParsingState.ConsumeTrailers; + // Apply the MaxResponseHeadersLength limit to all trailing headers. + // The limit is applied to regular response headers and trailing headers separately. + _connection._allowedReadLineBytes = _connection.MaxResponseHeadersLength; goto case ParsingState.ConsumeTrailers; } @@ -343,7 +344,6 @@ namespace System.Net.Http while (true) { - _connection._allowedReadLineBytes = MaxTrailingHeaderLength; if (!_connection.TryReadNextLine(out currentLine)) { break; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs index c8bfc919e9c..4c862f03f8a 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs @@ -204,6 +204,8 @@ namespace System.Net.Http public HttpConnectionKind Kind => _pool.Kind; + private int MaxResponseHeadersLength => (int)Math.Min(int.MaxValue, _pool.Settings._maxResponseHeadersLength * 1024L); + private int ReadBufferSize => _readBuffer.Length; private ReadOnlyMemory<byte> RemainingBuffer => new ReadOnlyMemory<byte>(_readBuffer, _readOffset, _readLength - _readOffset); @@ -497,7 +499,7 @@ namespace System.Net.Http } // Start to read response. - _allowedReadLineBytes = (int)Math.Min(int.MaxValue, _pool.Settings._maxResponseHeadersLength * 1024L); + _allowedReadLineBytes = MaxResponseHeadersLength; // We should not have any buffered data here; if there was, it should have been treated as an error // by the previous request handling. (Note we do not support HTTP pipelining.) @@ -1412,7 +1414,7 @@ namespace System.Net.Http { if (_allowedReadLineBytes < buffer.Length) { - throw new HttpRequestException(SR.Format(SR.net_http_response_headers_exceeded_length, _pool.Settings._maxResponseHeadersLength * 1024L)); + throw new HttpRequestException(SR.Format(SR.net_http_response_headers_exceeded_length, MaxResponseHeadersLength)); } line = default; @@ -1523,7 +1525,7 @@ namespace System.Net.Http { if (_allowedReadLineBytes < 0) { - throw new HttpRequestException(SR.Format(SR.net_http_response_headers_exceeded_length, _pool.Settings._maxResponseHeadersLength * 1024L)); + throw new HttpRequestException(SR.Format(SR.net_http_response_headers_exceeded_length, MaxResponseHeadersLength)); } } diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs index 02e18e91090..295986b8201 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs @@ -754,6 +754,60 @@ namespace System.Net.Http.Functional.Tests } }); } + + [Theory] + [InlineData(1024, 64, false)] + [InlineData(1024, 1024 - 2, false)] // we need at least 2 spare bytes for the next CRLF + [InlineData(1024, 1024 - 1, true)] + [InlineData(1024, 1024, true)] + [InlineData(1024, 1024 + 1, true)] + [InlineData(1024 * 1024, 1024 * 1024 - 2, false)] + [InlineData(1024 * 1024, 1024 * 1024 - 1, true)] + [InlineData(1024 * 1024, 1024 * 1024, true)] + public async Task GetAsync_MaxResponseHeadersLength_EnforcedOnTrailingHeaders(int maxResponseHeadersLength, int trailersLength, bool shouldThrow) + { + await LoopbackServer.CreateClientAndServerAsync( + async uri => + { + using HttpClientHandler handler = CreateHttpClientHandler(); + using HttpClient client = CreateHttpClient(handler); + + handler.MaxResponseHeadersLength = maxResponseHeadersLength / 1024; + + if (shouldThrow) + { + await Assert.ThrowsAsync<HttpRequestException>(() => client.GetAsync(uri)); + } + else + { + (await client.GetAsync(uri)).Dispose(); + } + }, + async server => + { + try + { + const string TrailerName1 = "My-Trailer-1"; + const string TrailerName2 = "My-Trailer-2"; + + int trailerOneLength = trailersLength / 2; + int trailerTwoLength = trailersLength - trailerOneLength; + + await server.AcceptConnectionSendCustomResponseAndCloseAsync( + "HTTP/1.1 200 OK\r\n" + + "Connection: close\r\n" + + "Transfer-Encoding: chunked\r\n" + + "\r\n" + + "4\r\n" + + "data\r\n" + + "0\r\n" + + $"{TrailerName1}: {new string('a', trailerOneLength - TrailerName1.Length - 4)}\r\n" + + $"{TrailerName2}: {new string('b', trailerTwoLength - TrailerName2.Length - 4)}\r\n" + + "\r\n"); + } + catch { } + }); + } } // TODO: make generic to support HTTP/2 and HTTP/3. |