Skip to content

Commit c9f75a1

Browse files
committed
Merged PR 9163: [3.1] Fix HttSys tests
The 3.1 PR builds aren't working so I missed some new test failures caused by my prior change. https://dev.azure.com/dnceng/internal/_build/results?buildId=734369&view=ms.vss-test-web.build-test-results-tab HttpSys has some odd behavior when you call SendFileAsync multiple times on an aborted response. The first time throws an OperationCancelledException, but the second time throws an ObjectDisposedException. This only happens if you enable HttpSysOptions.ThrowWriteExceptions and pass in a cancelled token. https://github.com/dotnet/aspnetcore/blob/472fc5058ecbddd4cd546a40628ec5a0545b8125/src/Servers/HttpSys/src/RequestProcessing/ResponseBody.cs#L577 I'm not aware of any scenarios where SendFileAsync is called multiple times like this, so for now I'm only fixing up the tests.
1 parent b110c81 commit c9f75a1

File tree

1 file changed

+12
-4
lines changed

1 file changed

+12
-4
lines changed

src/Servers/HttpSys/test/FunctionalTests/ResponseSendFileTests.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -487,17 +487,21 @@ public async Task ResponseSendFileExceptions_ClientDisconnectsBeforeFirstSend_Se
487487

488488
try
489489
{
490+
// Note Response.SendFileAsync uses RequestAborted by default. This can cause the response to be disposed
491+
// before it throws an IOException, but there's a race depending on when the disconnect is noticed.
492+
// Passing our own token to skip that.
493+
using var cts = new CancellationTokenSource();
490494
await Assert.ThrowsAsync<IOException>(async () =>
491495
{
492496
// It can take several tries before Send notices the disconnect.
493497
for (int i = 0; i < Utilities.WriteRetryLimit; i++)
494498
{
495-
await httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null);
499+
await httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
496500
}
497501
});
498502

499503
await Assert.ThrowsAsync<ObjectDisposedException>(() =>
500-
httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null));
504+
httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token));
501505

502506
testComplete.SetResult(0);
503507
}
@@ -573,9 +577,13 @@ public async Task ResponseSendFileExceptions_ClientDisconnectsBeforeSecondSend_S
573577
var testComplete = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
574578
using (Utilities.CreateHttpServer(out var address, async httpContext =>
575579
{
580+
// Note Response.SendFileAsync uses RequestAborted by default. This can cause the response to be disposed
581+
// before it throws an IOException, but there's a race depending on when the disconnect is noticed.
582+
// Passing our own token to skip that.
583+
using var cts = new CancellationTokenSource();
576584
httpContext.RequestAborted.Register(() => cancellationReceived.SetResult(0));
577585
// First write sends headers
578-
await httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null);
586+
await httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
579587
firstSendComplete.SetResult(0);
580588
await clientDisconnected.Task;
581589

@@ -586,7 +594,7 @@ await Assert.ThrowsAsync<IOException>(async () =>
586594
// It can take several tries before Write notices the disconnect.
587595
for (int i = 0; i < Utilities.WriteRetryLimit; i++)
588596
{
589-
await httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None);
597+
await httpContext.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
590598
}
591599
});
592600

0 commit comments

Comments
 (0)