diff --git a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2OutputProducer.cs b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2OutputProducer.cs index c1c8a320f5..0f95f70ef7 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2OutputProducer.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2OutputProducer.cs @@ -86,7 +86,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 _streamEnded = false; _suffixSent = false; - _suffixSent = false; _startedWritingDataFrames = false; _streamCompleted = false; _writerComplete = false; @@ -462,17 +461,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 // Stream state will move to RequestProcessingStatus.ResponseCompleted _responseCompleteTaskSource.SetResult(flushResult); - if (readResult.IsCompleted) - { - // Successfully read all data. Wait here for the stream to be reset. - await new ValueTask(_resetAwaitable, _resetAwaitable.Version); - _resetAwaitable.Reset(); - } - else - { - // Stream was aborted. - break; - } + // Wait here for the stream to be reset or disposed. + await new ValueTask(_resetAwaitable, _resetAwaitable.Version); + _resetAwaitable.Reset(); } while (!_disposed); static void ThrowUnexpectedState() @@ -537,6 +528,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 } _disposed = true; + // Set awaitable after disposed is true to ensure ProcessDataWrites exits successfully. _resetAwaitable.SetResult(null); } } diff --git a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Stream.cs b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Stream.cs index 67c1e993d2..f6a19584f2 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Stream.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Stream.cs @@ -156,10 +156,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 // connection's flow-control window. _inputFlowControl.Abort(); - // We only want to reuse a stream that has completely finished writing. - // This is to prevent the situation where Http2OutputProducer.ProcessDataWrites - // is still running in the background. - CanReuse = !_keepAlive && HasResponseCompleted; + // We only want to reuse a stream that was not aborted and has completely finished writing. + // This ensures Http2OutputProducer.ProcessDataWrites is in the correct state to be reused. + CanReuse = !_connectionAborted && HasResponseCompleted; } finally {