diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index b41add8142..f9e32d91eb 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -305,7 +305,7 @@ https://github.com/dotnet/corefx 00000 - + https://github.com/dotnet/corefx 00000 diff --git a/eng/Versions.props b/eng/Versions.props index d7bd40e97a..e7d82c184c 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 4.6.0-preview4.19156.2 4.7.0-preview4.19156.2 4.6.0-preview4.19156.2 - 4.6.0-preview4.19127.11 + 4.6.0-preview4.19156.2 4.6.0-preview4.19156.2 4.6.0-preview4.19156.2 1.7.0-preview4.19156.2 diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/Http1ChunkedEncodingMessageBody.cs b/src/Servers/Kestrel/Core/src/Internal/Http/Http1ChunkedEncodingMessageBody.cs index 963fd5d85c..4f7a15826d 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/Http1ChunkedEncodingMessageBody.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/Http1ChunkedEncodingMessageBody.cs @@ -323,6 +323,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return; } + // Assigned this before calculating the chunk size since that can throw + examined = reader.Position; + var chunkSize = CalculateChunkSize(ch1, 0); ch1 = ch2; @@ -360,6 +363,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http ch1 = ch2; } + // Set examined so that we capture the progress that way made + examined = reader.Position; + // At this point, 10 bytes have been consumed which is enough to parse the max value "7FFFFFFF\r\n". BadHttpRequestException.Throw(RequestRejectionReason.BadChunkSizeData); } diff --git a/src/Servers/Kestrel/Core/test/MessageBodyTests.cs b/src/Servers/Kestrel/Core/test/MessageBodyTests.cs index 785097ab17..bd11ad9d81 100644 --- a/src/Servers/Kestrel/Core/test/MessageBodyTests.cs +++ b/src/Servers/Kestrel/Core/test/MessageBodyTests.cs @@ -198,6 +198,94 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests } } + [Fact] + public async Task BadChunkPrefixThrowsBadRequestException() + { + using (var input = new TestInput()) + { + var body = Http1MessageBody.For(HttpVersion.Http11, new HttpRequestHeaders { HeaderTransferEncoding = "chunked" }, input.Http1Connection); + var mockBodyControl = new Mock(); + mockBodyControl.Setup(m => m.AllowSynchronousIO).Returns(true); + var reader = new HttpRequestPipeReader(); + var stream = new HttpRequestStream(mockBodyControl.Object, reader); + reader.StartAcceptingReads(body); + var buffer = new byte[1024]; + var task = stream.ReadAsync(buffer, 0, buffer.Length); + + input.Add("g"); + input.Add("g"); + + await Assert.ThrowsAsync(() => task); + + await body.StopAsync(); + } + } + + [Fact] + public async Task WritingChunkOverMaxChunkSizeThrowsBadRequest() + { + using (var input = new TestInput()) + { + var body = Http1MessageBody.For(HttpVersion.Http11, new HttpRequestHeaders { HeaderTransferEncoding = "chunked" }, input.Http1Connection); + var mockBodyControl = new Mock(); + mockBodyControl.Setup(m => m.AllowSynchronousIO).Returns(true); + var reader = new HttpRequestPipeReader(); + var stream = new HttpRequestStream(mockBodyControl.Object, reader); + reader.StartAcceptingReads(body); + var buffer = new byte[1024]; + var task = stream.ReadAsync(buffer, 0, buffer.Length); + + // Max is 10 bytes + for (int i = 0; i < 11; i++) + { + input.Add(i.ToString()); + } + + await Assert.ThrowsAsync(() => task); + + await body.StopAsync(); + } + } + + [Fact] + public async Task InvalidChunkSuffixThrowsBadRequest() + { + using (var input = new TestInput()) + { + var body = Http1MessageBody.For(HttpVersion.Http11, new HttpRequestHeaders { HeaderTransferEncoding = "chunked" }, input.Http1Connection); + var mockBodyControl = new Mock(); + mockBodyControl.Setup(m => m.AllowSynchronousIO).Returns(true); + var reader = new HttpRequestPipeReader(); + var stream = new HttpRequestStream(mockBodyControl.Object, reader); + reader.StartAcceptingReads(body); + var buffer = new byte[1024]; + + async Task ReadAsync() + { + while (true) + { + await stream.ReadAsync(buffer, 0, buffer.Length); + } + } + + var task = ReadAsync(); + + input.Add("1"); + input.Add("\r"); + input.Add("\n"); + input.Add("h"); + input.Add("0"); + input.Add("\r"); + input.Add("\n"); + input.Add("\r"); + input.Add("n"); + + await Assert.ThrowsAsync(() => task); + + await body.StopAsync(); + } + } + [Fact] public async Task CanReadAsyncFromChunkedEncoding() {