diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs index 75b9d9b1f8a964..b76c0b79ec0665 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs @@ -28,6 +28,8 @@ internal sealed class Http3Connection : HttpConnectionBase // Keep a collection of requests around so we can process GOAWAY. private readonly Dictionary _activeRequests = new Dictionary(); + internal readonly List _streamDisposals = []; + // Set when GOAWAY is being processed, when aborting, or when disposing. private long _firstRejectedStreamId = -1; @@ -126,6 +128,10 @@ private void CheckForShutdown() if (_connection != null) { + // Make sure we've disposed every stream before closing the connection. + + Task.WhenAll(_streamDisposals).GetAwaiter().GetResult(); + // Close the QuicConnection in the background. _connectionClosedTask ??= _connection.CloseAsync((long)Http3ErrorCode.NoError).AsTask(); @@ -363,6 +369,14 @@ public void RemoveStream(QuicStream stream) } } + public void QueueStreamForDisposal(QuicStream stream) + { + lock (SyncObj) + { + _streamDisposals.Add(stream.DisposeAsync().AsTask()); + } + } + public override long GetIdleTicks(long nowTicks) => throw new NotImplementedException("We aren't scavenging HTTP3 connections yet"); public override void Trace(string message, [CallerMemberName] string? memberName = null) => diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs index ef2532b2b22d08..67d2487b9c0edd 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs @@ -88,7 +88,7 @@ public void Dispose() { _disposed = true; AbortStream(); - _stream.Dispose(); + _connection.QueueStreamForDisposal(_stream); DisposeSyncHelper(); } }