From 00ac95f72bba28fc534f14986b8ea67b5e4f1b9d Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Tue, 3 Dec 2019 17:25:59 +1300 Subject: [PATCH] Improve error message when TestServer finishes with a pending request read (#17164) --- .../TestHost/src/HttpContextBuilder.cs | 12 ++++- src/Hosting/TestHost/test/TestClientTests.cs | 48 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/Hosting/TestHost/src/HttpContextBuilder.cs b/src/Hosting/TestHost/src/HttpContextBuilder.cs index aab30590aa..7048e786b2 100644 --- a/src/Hosting/TestHost/src/HttpContextBuilder.cs +++ b/src/Hosting/TestHost/src/HttpContextBuilder.cs @@ -160,7 +160,17 @@ namespace Microsoft.AspNetCore.TestHost private async Task CompleteRequestAsync() { - if (!_requestPipe.Reader.TryRead(out var result) || !result.IsCompleted) + bool requestBodyInProgress; + try + { + requestBodyInProgress = !_requestPipe.Reader.TryRead(out var result) || !result.IsCompleted; + } + catch (Exception ex) + { + throw new InvalidOperationException("An error occurred when completing the request. Request delegate may have finished while there is a pending read of the request body.", ex); + } + + if (requestBodyInProgress) { // If request is still in progress then abort it. CancelRequestBody(); diff --git a/src/Hosting/TestHost/test/TestClientTests.cs b/src/Hosting/TestHost/test/TestClientTests.cs index 08600239c9..8c1ac8a2ce 100644 --- a/src/Hosting/TestHost/test/TestClientTests.cs +++ b/src/Hosting/TestHost/test/TestClientTests.cs @@ -385,6 +385,54 @@ namespace Microsoft.AspNetCore.TestHost await writeTask; } + [Fact] + public async Task ClientStreaming_ResponseCompletesWithPendingRead_ThrowError() + { + // Arrange + var requestStreamTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + + RequestDelegate appDelegate = async ctx => + { + var pendingReadTask = ctx.Request.Body.ReadAsync(new byte[1024], 0, 1024); + ctx.Response.Headers["test-header"] = "true"; + await ctx.Response.Body.FlushAsync(); + }; + + Stream requestStream = null; + + var builder = new WebHostBuilder().Configure(app => app.Run(appDelegate)); + var server = new TestServer(builder); + var client = server.CreateClient(); + + var httpRequest = new HttpRequestMessage(HttpMethod.Post, "http://localhost:12345"); + httpRequest.Version = new Version(2, 0); + httpRequest.Content = new PushContent(async stream => + { + requestStream = stream; + await requestStreamTcs.Task; + }); + + // Act + var response = await client.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead).WithTimeout(); + + var responseContent = await response.Content.ReadAsStreamAsync().WithTimeout(); + + // Assert + response.EnsureSuccessStatusCode(); + Assert.Equal("true", response.Headers.GetValues("test-header").Single()); + + // Read response + var ex = await Assert.ThrowsAsync(async () => + { + byte[] buffer = new byte[1024]; + var length = await responseContent.ReadAsync(buffer).AsTask().WithTimeout(); + }); + Assert.Equal("An error occurred when completing the request. Request delegate may have finished while there is a pending read of the request body.", ex.InnerException.Message); + + // Unblock request + requestStreamTcs.TrySetResult(null); + } + [Fact] public async Task ClientStreaming_ServerAbort() {