diff --git a/src/libraries/System.Net.Http/src/System.Net.Http.csproj b/src/libraries/System.Net.Http/src/System.Net.Http.csproj index 0ce5ec1aa171e..f295f8d391a18 100644 --- a/src/libraries/System.Net.Http/src/System.Net.Http.csproj +++ b/src/libraries/System.Net.Http/src/System.Net.Http.csproj @@ -621,7 +621,7 @@ - + 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 51f65a875fe54..939f944eab49d 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 @@ -168,6 +168,7 @@ public override async Task SendAsync(HttpRequestMessage req { while (true) { + Console.WriteLine($"H3 connection loop"); lock (SyncObj) { if (_connection == null) @@ -182,12 +183,16 @@ public override async Task SendAsync(HttpRequestMessage req _activeRequests.Add(quicStream, requestStream); break; } + Console.WriteLine($"H3 connection loop getting wait task"); waitTask = _connection.WaitForAvailableBidirectionalStreamsAsync(cancellationToken); } + Console.WriteLine($"H3 connection loop waiting"); // Wait for an available stream (based on QUIC MAX_STREAMS) if there isn't one available yet. await waitTask.ConfigureAwait(false); + Console.WriteLine($"H3 connection loop done waiting"); } + Console.WriteLine($"H3 connection loop done"); if (quicStream == null) { diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs index 0a193684e4ce7..7ac9970516205 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs @@ -26,7 +26,7 @@ public HttpClientHandlerTest_Http3(ITestOutputHelper output) : base(output) { } - [Theory] + /*[Theory] [InlineData(10)] // 2 bytes settings value. [InlineData(100)] // 4 bytes settings value. [InlineData(10_000_000)] // 8 bytes settings value. @@ -160,12 +160,12 @@ public async Task SendStreamLimitRequestsConcurrently_Succeeds(int streamLimit) }); await new[] { clientTask, serverTask }.WhenAllOrAnyFailed(20_000); - } + }*/ [Theory] [InlineData(10)] - [InlineData(100)] - [InlineData(1000)] + //[InlineData(100)] + //[InlineData(1000)] public async Task SendMoreThanStreamLimitRequestsConcurrently_LastWaits(int streamLimit) { // This combination leads to a hang manifesting in CI only. Disabling it until there's more time to investigate. @@ -190,12 +190,16 @@ public async Task SendMoreThanStreamLimitRequestsConcurrently_LastWaits(int stre streams[i] = stream; } + _output.WriteLine($"Server {streamLimit} streams openned."); + // Make the last request running independently. var lastRequest = Task.Run(async () => { using Http3LoopbackStream stream = await connection.AcceptRequestStreamAsync(); await stream.HandleRequestAsync(); }); + _output.WriteLine($"Server last request content should not be completed yet IsCompleted={lastRequestContentStarted.Task.IsCompleted}"); + // All the initial streamLimit streams are still opened so the last request cannot started yet. Assert.False(lastRequestContentStarted.Task.IsCompleted); @@ -207,10 +211,13 @@ public async Task SendMoreThanStreamLimitRequestsConcurrently_LastWaits(int stre // After the first request is fully processed, the last request should unblock and get processed. if (i == 0) { + _output.WriteLine($"Server awaiting last request content Status={lastRequestContentStarted.Task.Status}"); await lastRequestContentStarted.Task; + _output.WriteLine($"Server awaited last request content Status={lastRequestContentStarted.Task.Status}"); } } await lastRequest; + _output.WriteLine($"Server finished"); }); Task clientTask = Task.Run(async () => @@ -240,6 +247,8 @@ public async Task SendMoreThanStreamLimitRequestsConcurrently_LastWaits(int stre tasks[i] = client.SendAsync(request); }); + _output.WriteLine($"Client waiting for {streamLimit} streams to open."); + // Wait for the first streamLimit request to get started. countdown.Wait(); @@ -259,17 +268,28 @@ public async Task SendMoreThanStreamLimitRequestsConcurrently_LastWaits(int stre })) }; var lastTask = client.SendAsync(last); + _output.WriteLine($"Client started the last request content Status={lastRequestContentStarted.Task.Status}."); // Wait for all requests to finish. Whether the last request was pending is checked on the server side. var responses = await Task.WhenAll(tasks); + _output.WriteLine($"Client {streamLimit} requests finished."); foreach (var response in responses) { response.Dispose(); } await lastTask; + _output.WriteLine($"Client finished."); }); - await new[] { clientTask, serverTask }.WhenAllOrAnyFailed(20_000); + try + { + await new[] { clientTask, serverTask }.WhenAllOrAnyFailed(20_000); + } + catch + { + throw; + //Environment.FailFast("On purpose crash to get a dump"); + } } [Fact] diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs index 640f468ec9236..09a3adcf4c459 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs @@ -3084,7 +3084,7 @@ public sealed class SocketsHttpHandlerTest_Http3_Mock : HttpClientHandlerTest_Ht protected override QuicImplementationProvider UseQuicImplementationProvider => QuicImplementationProviders.Mock; } - [ConditionalClass(typeof(HttpClientHandlerTestBase), nameof(IsMsQuicSupported))] + /*[ConditionalClass(typeof(HttpClientHandlerTestBase), nameof(IsMsQuicSupported))] public sealed class SocketsHttpHandlerTest_HttpClientHandlerTest_Http3_MsQuic : HttpClientHandlerTest { public SocketsHttpHandlerTest_HttpClientHandlerTest_Http3_MsQuic(ITestOutputHelper output) : base(output) { } @@ -3187,5 +3187,5 @@ public sealed class SocketsHttpHandler_HttpClientHandler_Finalization_Http3_Mock public SocketsHttpHandler_HttpClientHandler_Finalization_Http3_Mock(ITestOutputHelper output) : base(output) { } protected override Version UseVersion => HttpVersion.Version30; protected override QuicImplementationProvider UseQuicImplementationProvider => QuicImplementationProviders.Mock; - } + }*/ } diff --git a/src/libraries/System.Net.Quic/src/System.Net.Quic.csproj b/src/libraries/System.Net.Quic/src/System.Net.Quic.csproj index e1f29c77f0f32..c3645a7211d72 100644 --- a/src/libraries/System.Net.Quic/src/System.Net.Quic.csproj +++ b/src/libraries/System.Net.Quic/src/System.Net.Quic.csproj @@ -46,7 +46,7 @@ - + diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/Mock/MockStream.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/Mock/MockStream.cs index bd814f690d952..5f21c4a07193a 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/Mock/MockStream.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/Mock/MockStream.cs @@ -205,6 +205,7 @@ internal override ValueTask ShutdownCompleted(CancellationToken cancellationToke internal override void Shutdown() { + Console.WriteLine($"MockStream shutdown {this.StreamId}"); CheckDisposed(); // This seems to mean shutdown send, in particular, not both. @@ -212,10 +213,12 @@ internal override void Shutdown() if (_streamState._inboundStreamBuffer is null) // unidirectional stream { + Console.WriteLine($"MockStream unidi decrement {this.StreamId}"); _connection.LocalStreamLimit!.Unidirectional.Decrement(); } else { + Console.WriteLine($"MockStream bidi decrement {this.StreamId}"); _connection.LocalStreamLimit!.Bidirectional.Decrement(); } }