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 45b74472b402cb..8ec6cdb2b190e7 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 @@ -1028,6 +1028,11 @@ private int ReadResponseContent(HttpResponseMessage response, Span buffer) totalBytesRead += bytesRead; _responseDataPayloadRemaining -= bytesRead; buffer = buffer.Slice(bytesRead); + + if (_responseDataPayloadRemaining == 0) + { + break; + } } } @@ -1085,6 +1090,11 @@ private async ValueTask ReadResponseContentAsync(HttpResponseMessage respon totalBytesRead += bytesRead; _responseDataPayloadRemaining -= bytesRead; buffer = buffer.Slice(bytesRead); + + if (_responseDataPayloadRemaining == 0) + { + break; + } } } diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs index aced77794ce751..4132bcef76cb75 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs @@ -8,6 +8,7 @@ using System.Net.Security; using System.Net.Sockets; using System.Security.Authentication; +using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading; @@ -801,5 +802,59 @@ await Task.Run(async () => await Assert.ThrowsAsync(() => serverStream.ReadAsync(buffer).AsTask()); }).WaitAsync(TimeSpan.FromMilliseconds(PassingTestTimeoutMilliseconds)); } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task BigWrite_SmallRead_Success(bool closeWithData) + { + const int size = 100; + (QuicConnection clientConnection, QuicConnection serverConnection) = await CreateConnectedQuicConnection(); + using (clientConnection) + using (serverConnection) + { + byte[] buffer = new byte[1] { 42 }; + + QuicStream clientStream = clientConnection.OpenBidirectionalStream(); + Task t = serverConnection.AcceptStreamAsync().AsTask(); + await TaskTimeoutExtensions.WhenAllOrAnyFailed(clientStream.WriteAsync(buffer).AsTask(), t, PassingTestTimeoutMilliseconds); + QuicStream serverStream = t.Result; + Assert.Equal(1, await serverStream.ReadAsync(buffer)); + + // streams are new established and in good shape. + using (clientStream) + using (serverStream) + { + byte[] expected = RandomNumberGenerator.GetBytes(size); + byte[] actual = new byte[size]; + + // should be small enough to fit. + await serverStream.WriteAsync(expected, closeWithData); + + // Add delay to have chance to receive the 100b block before ReadAsync starts. + await Task.Delay(10); + int remaining = size; + int readLength; + while (remaining > 0) + { + readLength = await clientStream.ReadAsync(new Memory(actual, size - remaining, 1)); + Assert.Equal(1, readLength); + remaining--; + } + + Assert.Equal(expected, actual); + + if (!closeWithData) + { + serverStream.Shutdown(); + } + + readLength = await clientStream.ReadAsync(actual); + Assert.Equal(0, readLength); + + Assert.Equal(expected, actual); + } + } + } } }