From 9e2353618abdb380f0e1e8a6588cd4daab07c740 Mon Sep 17 00:00:00 2001 From: Aditya Mandaleeka Date: Tue, 17 Feb 2026 13:51:10 -0800 Subject: [PATCH 1/3] Fix race in RST_STREAM_IncompleteRequest tests Move tcs.TrySetResult() after WaitForConnectionErrorAsync to prevent the response HEADERS from racing with the GOAWAY frame. Same fix pattern as #57450 applied to AdditionalDataFrames and AdditionalTrailerFrames variants. --- .../InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs index 3d0d0d10ba3b..3025786e5350 100644 --- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs +++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs @@ -3549,11 +3549,12 @@ public async Task RST_STREAM_IncompleteRequest_AdditionalDataFrames_ConnectionAb await SendDataAsync(1, new byte[2], endStream: false); await SendRstStreamAsync(1); await SendDataAsync(1, new byte[10], endStream: false); - tcs.TrySetResult(); await WaitForConnectionErrorAsync(ignoreNonGoAwayFrames: false, expectedLastStreamId: 1, Http2ErrorCode.STREAM_CLOSED, CoreStrings.FormatHttp2ErrorStreamAborted(Http2FrameType.DATA, 1)); + tcs.TrySetResult(); // Don't let the response start until after the abort + AssertConnectionEndReason(ConnectionEndReason.FrameAfterStreamClose); } @@ -3575,11 +3576,12 @@ public async Task RST_STREAM_IncompleteRequest_AdditionalTrailerFrames_Connectio await SendDataAsync(1, new byte[2], endStream: false); await SendRstStreamAsync(1); await SendHeadersAsync(1, Http2HeadersFrameFlags.END_HEADERS | Http2HeadersFrameFlags.END_STREAM, _requestTrailers); - tcs.TrySetResult(); await WaitForConnectionErrorAsync(ignoreNonGoAwayFrames: false, expectedLastStreamId: 1, Http2ErrorCode.STREAM_CLOSED, CoreStrings.FormatHttp2ErrorStreamAborted(Http2FrameType.HEADERS, 1)); + tcs.TrySetResult(); // Don't let the response start until after the abort + AssertConnectionEndReason(ConnectionEndReason.FrameAfterStreamClose); } From 7366b533bad51af3a962eeb82ef0cbd35c781152 Mon Sep 17 00:00:00 2001 From: Aditya Mandaleeka Date: Tue, 17 Feb 2026 20:01:29 -0800 Subject: [PATCH 2/3] Fix flaky Http2 test by using consistent ConnectionEndReason for closed streams. --- src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs | 2 +- .../test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs index 9d3fb8302012..434400f70f8e 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs @@ -754,7 +754,7 @@ private Task ProcessDataFrameAsync(in ReadOnlySequence payload) // // We choose to do that here so we don't have to keep state to track implicitly closed // streams vs. streams closed with END_STREAM or RST_STREAM. - throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamClosed(_incomingFrame.Type, _incomingFrame.StreamId), Http2ErrorCode.STREAM_CLOSED, ConnectionEndReason.UnknownStream); + throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamClosed(_incomingFrame.Type, _incomingFrame.StreamId), Http2ErrorCode.STREAM_CLOSED, ConnectionEndReason.FrameAfterStreamClose); } private Http2ConnectionErrorException CreateReceivedFrameStreamAbortedException(Http2Stream stream) diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs index 3025786e5350..3209cec1cba0 100644 --- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs +++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs @@ -5835,7 +5835,7 @@ await WaitForConnectionErrorAsync( switch (finalFrameType) { case Http2FrameType.DATA: - AssertConnectionEndReason(ConnectionEndReason.UnknownStream); + AssertConnectionEndReason(ConnectionEndReason.FrameAfterStreamClose); break; case Http2FrameType.HEADERS: From 9a5ec0c9768cc09a76d2db784b14c25ebc1463d6 Mon Sep 17 00:00:00 2001 From: Aditya Mandaleeka Date: Wed, 18 Feb 2026 08:21:33 -0800 Subject: [PATCH 3/3] Update remaining test assertions to use FrameAfterStreamClose. --- .../InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs | 6 +++--- .../InMemory.FunctionalTests/Http2/Http2TimeoutTests.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs index 3209cec1cba0..b5f6006cf220 100644 --- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs +++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs @@ -1639,7 +1639,7 @@ await WaitForConnectionErrorAsync( CoreStrings.FormatHttp2ErrorStreamClosed(Http2FrameType.DATA, streamId: 1), CoreStrings.FormatHttp2ErrorStreamHalfClosedRemote(Http2FrameType.DATA, streamId: 1) }); - AssertConnectionEndReason(ConnectionEndReason.UnknownStream); + AssertConnectionEndReason(ConnectionEndReason.FrameAfterStreamClose); } [Fact] @@ -1853,7 +1853,7 @@ await WaitForConnectionErrorAsync( expectedErrorCode: Http2ErrorCode.STREAM_CLOSED, expectedErrorMessage: CoreStrings.FormatHttp2ErrorStreamClosed(Http2FrameType.DATA, streamId: 1)); - AssertConnectionEndReason(ConnectionEndReason.UnknownStream); + AssertConnectionEndReason(ConnectionEndReason.FrameAfterStreamClose); } [Fact] @@ -5744,7 +5744,7 @@ await WaitForConnectionErrorAsync( CoreStrings.FormatHttp2ErrorStreamClosed(Http2FrameType.DATA, streamId: 1), CoreStrings.FormatHttp2ErrorStreamHalfClosedRemote(Http2FrameType.DATA, streamId: 1) }); - AssertConnectionEndReason(ConnectionEndReason.UnknownStream); + AssertConnectionEndReason(ConnectionEndReason.FrameAfterStreamClose); break; case Http2FrameType.HEADERS: diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2TimeoutTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2TimeoutTests.cs index 0e10567e68b9..6c0486a8e224 100644 --- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2TimeoutTests.cs +++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2TimeoutTests.cs @@ -304,7 +304,7 @@ await WaitForConnectionErrorAsyncDoNotCloseTransport