From ded46d8575ddba0492759b7e73bf9bf120f478a4 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 14 Jan 2022 12:45:16 -0800 Subject: [PATCH 1/2] Configure max request line size limits to be the same as maxHeaderSize As part of ReadAsHttpRequestMessageAsync, the parsing of the HTTP request line is limited by a non-configurable 2k limit. The size does not affect buffer sizes, only the maximum allowed length. This PR updates the ReadAsHttpRequestMessageAsync API to use the same limits for HTTP request line as the HTTP header line, the latter which is configurable by user code. In the default case, this means the HTTP request line size now supports a 16k limit before it throws. Fixes https://github.com/aspnet/AspNetWebStack/issues/307 --- .../HttpContentMessageExtensions.cs | 2 +- .../HttpContentMessageExtensionsTests.cs | 40 +++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs b/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs index dd801b604..12f3dad27 100644 --- a/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs +++ b/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs @@ -223,7 +223,7 @@ private static async Task ReadAsHttpRequestMessageAsyncCore( HttpUnsortedRequest httpRequest = new HttpUnsortedRequest(); HttpRequestHeaderParser parser = new HttpRequestHeaderParser(httpRequest, - HttpRequestHeaderParser.DefaultMaxRequestLineSize, maxHeaderSize); + maxHeaderSize, maxHeaderSize); ParserState parseStatus; byte[] buffer = new byte[bufferSize]; diff --git a/test/System.Net.Http.Formatting.Test/HttpContentMessageExtensionsTests.cs b/test/System.Net.Http.Formatting.Test/HttpContentMessageExtensionsTests.cs index 27273e4f2..7003cdbd5 100644 --- a/test/System.Net.Http.Formatting.Test/HttpContentMessageExtensionsTests.cs +++ b/test/System.Net.Http.Formatting.Test/HttpContentMessageExtensionsTests.cs @@ -482,16 +482,50 @@ public Task ReadAsHttpResponseMessageAsync_LargeHeaderSize() } [Fact] - public Task ReadAsHttpRequestMessageAsync_LargeHeaderSize() + public async Task ReadAsHttpRequestMessageAsync_LargeHeaderSize() { + string cookieValue = string.Format("{0}={1}", new String('a', 16 * 1024), new String('b', 16 * 1024)); string[] request = new[] { @"GET / HTTP/1.1", @"Host: msdn.microsoft.com", - String.Format("Cookie: {0}={1}", new String('a', 16 * 1024), new String('b', 16 * 1024)) + string.Format("Cookie: {0}", cookieValue), + }; + + HttpContent content = CreateContent(true, request, "sample body"); + var httpRequestMessage = await content.ReadAsHttpRequestMessageAsync(Uri.UriSchemeHttp, 64 * 1024, 64 * 1024); + + Assert.Equal(HttpMethod.Get, httpRequestMessage.Method); + Assert.Equal("/", httpRequestMessage.RequestUri.PathAndQuery); + Assert.Equal("msdn.microsoft.com", httpRequestMessage.Headers.Host); + IEnumerable actualCookieValue; + Assert.True(httpRequestMessage.Headers.TryGetValues("Cookie", out actualCookieValue)); + Assert.Equal(cookieValue, Assert.Single(actualCookieValue)); + } + + [Fact] + public async Task ReadAsHttpRequestMessageAsync_LargeHttpRequestLine() + { + string requestPath = string.Format("/myurl?{0}={1}", new string('a', 4 * 1024), new string('b', 4 * 1024)); + string cookieValue = string.Format("{0}={1}", new String('a', 4 * 1024), new String('b', 4 * 1024)); + string[] request = new[] + { + string.Format("GET {0} HTTP/1.1", requestPath), + @"Host: msdn.microsoft.com", + string.Format("Cookie: {0}", cookieValue), }; HttpContent content = CreateContent(true, request, "sample body"); - return content.ReadAsHttpRequestMessageAsync(Uri.UriSchemeHttp, 64 * 1024, 64 * 1024); + var httpRequestMessage = await content.ReadAsHttpRequestMessageAsync( + Uri.UriSchemeHttp, + bufferSize: 64 * 1024, + maxHeaderSize: 64 * 1024); + + Assert.Equal(HttpMethod.Get, httpRequestMessage.Method); + Assert.Equal(requestPath, httpRequestMessage.RequestUri.PathAndQuery); + Assert.Equal("msdn.microsoft.com", httpRequestMessage.Headers.Host); + IEnumerable actualCookieValue; + Assert.True(httpRequestMessage.Headers.TryGetValues("Cookie", out actualCookieValue)); + Assert.Equal(cookieValue, Assert.Single(actualCookieValue)); } [Theory] From f509e0fc45949e2fb4d0d2d003d1c2f5b840b91a Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 14 Jan 2022 13:43:23 -0800 Subject: [PATCH 2/2] Update src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs --- src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs b/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs index 12f3dad27..a7dcb869d 100644 --- a/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs +++ b/src/System.Net.Http.Formatting/HttpContentMessageExtensions.cs @@ -223,7 +223,7 @@ private static async Task ReadAsHttpRequestMessageAsyncCore( HttpUnsortedRequest httpRequest = new HttpUnsortedRequest(); HttpRequestHeaderParser parser = new HttpRequestHeaderParser(httpRequest, - maxHeaderSize, maxHeaderSize); + Math.Max(HttpRequestHeaderParser.DefaultMaxRequestLineSize, maxHeaderSize), maxHeaderSize); ParserState parseStatus; byte[] buffer = new byte[bufferSize];