Skip to content

Commit 00ac95f

Browse files
authored
Improve error message when TestServer finishes with a pending request read (#17164)
1 parent 3cc84ce commit 00ac95f

File tree

2 files changed

+59
-1
lines changed

2 files changed

+59
-1
lines changed

src/Hosting/TestHost/src/HttpContextBuilder.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,17 @@ internal void ClientInitiatedAbort()
160160

161161
private async Task CompleteRequestAsync()
162162
{
163-
if (!_requestPipe.Reader.TryRead(out var result) || !result.IsCompleted)
163+
bool requestBodyInProgress;
164+
try
165+
{
166+
requestBodyInProgress = !_requestPipe.Reader.TryRead(out var result) || !result.IsCompleted;
167+
}
168+
catch (Exception ex)
169+
{
170+
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);
171+
}
172+
173+
if (requestBodyInProgress)
164174
{
165175
// If request is still in progress then abort it.
166176
CancelRequestBody();

src/Hosting/TestHost/test/TestClientTests.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,54 @@ public async Task ClientStreaming_ResponseCompletesWithoutReadingRequest()
385385
await writeTask;
386386
}
387387

388+
[Fact]
389+
public async Task ClientStreaming_ResponseCompletesWithPendingRead_ThrowError()
390+
{
391+
// Arrange
392+
var requestStreamTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
393+
394+
RequestDelegate appDelegate = async ctx =>
395+
{
396+
var pendingReadTask = ctx.Request.Body.ReadAsync(new byte[1024], 0, 1024);
397+
ctx.Response.Headers["test-header"] = "true";
398+
await ctx.Response.Body.FlushAsync();
399+
};
400+
401+
Stream requestStream = null;
402+
403+
var builder = new WebHostBuilder().Configure(app => app.Run(appDelegate));
404+
var server = new TestServer(builder);
405+
var client = server.CreateClient();
406+
407+
var httpRequest = new HttpRequestMessage(HttpMethod.Post, "http://localhost:12345");
408+
httpRequest.Version = new Version(2, 0);
409+
httpRequest.Content = new PushContent(async stream =>
410+
{
411+
requestStream = stream;
412+
await requestStreamTcs.Task;
413+
});
414+
415+
// Act
416+
var response = await client.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead).WithTimeout();
417+
418+
var responseContent = await response.Content.ReadAsStreamAsync().WithTimeout();
419+
420+
// Assert
421+
response.EnsureSuccessStatusCode();
422+
Assert.Equal("true", response.Headers.GetValues("test-header").Single());
423+
424+
// Read response
425+
var ex = await Assert.ThrowsAsync<IOException>(async () =>
426+
{
427+
byte[] buffer = new byte[1024];
428+
var length = await responseContent.ReadAsync(buffer).AsTask().WithTimeout();
429+
});
430+
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);
431+
432+
// Unblock request
433+
requestStreamTcs.TrySetResult(null);
434+
}
435+
388436
[Fact]
389437
public async Task ClientStreaming_ServerAbort()
390438
{

0 commit comments

Comments
 (0)