diff --git a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs index 900ed0b82ba3..ce7ee215be8d 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs @@ -717,8 +717,13 @@ private Task ProcessRstStreamFrameAsync() // Second reset if (stream.RstStreamReceived) { - // Hard abort, do not allow any more frames on this stream. - throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamAborted(_incomingFrame.Type, stream.StreamId), Http2ErrorCode.STREAM_CLOSED); + // https://tools.ietf.org/html/rfc7540#section-5.1 + // If RST_STREAM has already been received then the stream is in a closed state. + // Additional frames (other than PRIORITY) are a stream error. + // The server will usually send a RST_STREAM for a stream error, but RST_STREAM + // shouldn't be sent in response to RST_STREAM to avoid a loop. + // The best course of action here is to do nothing. + return Task.CompletedTask; } // No additional inbound header or data frames are allowed for this stream after receiving a reset. diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs index b3115f9147af..1d407e402fc5 100644 --- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs +++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs @@ -3067,7 +3067,7 @@ await WaitForConnectionErrorAsync(ignoreNonGoAway } [Fact] - public async Task RST_STREAM_IncompleteRequest_AdditionalResetFrame_ConnectionAborted() + public async Task RST_STREAM_IncompleteRequest_AdditionalResetFrame_IgnoreAdditionalReset() { var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -3085,8 +3085,7 @@ public async Task RST_STREAM_IncompleteRequest_AdditionalResetFrame_ConnectionAb await SendRstStreamAsync(1); tcs.TrySetResult(0); - await WaitForConnectionErrorAsync(ignoreNonGoAwayFrames: false, expectedLastStreamId: 1, - Http2ErrorCode.STREAM_CLOSED, CoreStrings.FormatHttp2ErrorStreamAborted(Http2FrameType.RST_STREAM, 1)); + await StopConnectionAsync(expectedLastStreamId: 1, ignoreNonGoAwayFrames: false); } [Fact]