diff --git a/src/Kestrel.Core/Internal/Http/Http1MessageBody.cs b/src/Kestrel.Core/Internal/Http/Http1MessageBody.cs index 521a9c58f8..4910ae18be 100644 --- a/src/Kestrel.Core/Internal/Http/Http1MessageBody.cs +++ b/src/Kestrel.Core/Internal/Http/Http1MessageBody.cs @@ -294,6 +294,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http RequestUpgrade = true; } + public override bool IsEmpty => true; + protected override bool Read(ReadOnlyBuffer readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined) { Copy(readableBuffer, writableBuffer); diff --git a/src/Kestrel.Core/Internal/Http/HttpProtocol.cs b/src/Kestrel.Core/Internal/Http/HttpProtocol.cs index f8ada6f76e..09f6b54af5 100644 --- a/src/Kestrel.Core/Internal/Http/HttpProtocol.cs +++ b/src/Kestrel.Core/Internal/Http/HttpProtocol.cs @@ -533,7 +533,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http await ProduceEnd(); // ForZeroContentLength does not complete the reader nor the writer - if (!messageBody.IsEmpty && _keepAlive) + if (!messageBody.IsEmpty) { // Finish reading the request body in case the app did not. await messageBody.ConsumeAsync(); diff --git a/test/Kestrel.Core.Tests/Http1ConnectionTests.cs b/test/Kestrel.Core.Tests/Http1ConnectionTests.cs index 7e286aad82..75c7f4f560 100644 --- a/test/Kestrel.Core.Tests/Http1ConnectionTests.cs +++ b/test/Kestrel.Core.Tests/Http1ConnectionTests.cs @@ -12,6 +12,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Server.Kestrel.Core.Features; @@ -792,6 +793,26 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests Assert.StartsWith(CoreStrings.NonNegativeNumberOrNullRequired, ex.Message); } + [Fact] + public async Task ConsumesRequestWhenApplicationDoesNotConsumeIt() + { + var httpApplication = new DummyApplication(async context => + { + var buffer = new byte[10]; + await context.Response.Body.WriteAsync(buffer, 0, 10); + }); + var mockMessageBody = new Mock(null); + _http1Connection.NextMessageBody = mockMessageBody.Object; + + var requestProcessingTask = _http1Connection.ProcessRequestsAsync(httpApplication); + + var data = Encoding.ASCII.GetBytes("POST / HTTP/1.1\r\nHost:\r\nConnection: close\r\ncontent-length: 1\r\n\r\n"); + await _application.Output.WriteAsync(data); + await requestProcessingTask.TimeoutAfter(TestConstants.DefaultTimeout); + + mockMessageBody.Verify(body => body.ConsumeAsync(), Times.Once); + } + private static async Task WaitForCondition(TimeSpan timeout, Func condition) { const int MaxWaitLoop = 150; diff --git a/test/shared/TestHttp1Connection.cs b/test/shared/TestHttp1Connection.cs index d98f2e91e0..f53a2a52db 100644 --- a/test/shared/TestHttp1Connection.cs +++ b/test/shared/TestHttp1Connection.cs @@ -25,9 +25,16 @@ namespace Microsoft.AspNetCore.Testing set => _keepAlive = value; } + public MessageBody NextMessageBody { private get; set; } + public Task ProduceEndAsync() { return ProduceEnd(); } + + protected override MessageBody CreateMessageBody() + { + return NextMessageBody ?? base.CreateMessageBody(); + } } }