From bae4a122cee3ea5d9d272eb904fb5a894d4d65b3 Mon Sep 17 00:00:00 2001 From: ManickaP Date: Sun, 10 Mar 2024 18:29:01 +0100 Subject: [PATCH 1/2] Fix handling effectively empty DATA frame --- .../System/Net/Http/SocketsHttpHandler/Http2Connection.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs index 4d84e54748e3a..3ffa35fa00fec 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs @@ -765,9 +765,12 @@ private void ProcessDataFrame(FrameHeader frameHeader) // Just ignore the frame in this case. ReadOnlySpan frameData = GetFrameData(_incomingBuffer.ActiveSpan.Slice(0, frameHeader.PayloadLength), hasPad: frameHeader.PaddedFlag, hasPriority: false); - bool endStream = frameHeader.EndStreamFlag; - http2Stream?.OnResponseData(frameData, endStream); + + if (frameData.Length > 0 || endStream) + { + http2Stream?.OnResponseData(frameData, endStream); + } if (frameData.Length > 0) { From b1e6ee7e6c2ad91157a52ed05ae034010166af12 Mon Sep 17 00:00:00 2001 From: ManickaP Date: Sun, 10 Mar 2024 20:21:32 +0100 Subject: [PATCH 2/2] Added test --- .../HttpClientHandlerTest.Http2.cs | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs index 33c94856d270c..3036935ef5533 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs @@ -205,6 +205,50 @@ public async Task Http2_ZeroLengthResponseBody_Success() } } + [Fact] + public async Task Http2_DataFrameOnlyPadding_Success() + { + using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer()) + using (HttpClient client = CreateHttpClient()) + { + Task sendTask = client.GetAsync(server.Address, HttpCompletionOption.ResponseHeadersRead); + + Http2LoopbackConnection connection = await server.EstablishConnectionAsync(); + + int streamId = await connection.ReadRequestHeaderAsync(); + + await connection.SendDefaultResponseHeadersAsync(streamId); + + // Send zero-length DATA frame with padding + byte paddingLength = byte.MaxValue; + int dataLength = 1024; + DataFrame frame = new DataFrame(new byte[0], FrameFlags.Padded, paddingLength, streamId); + await connection.WriteFrameAsync(frame); + + HttpResponseMessage response = await sendTask; + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + + using var responseStream = response.Content.ReadAsStream(); + + // The read must pend because we havent received any data yet. + var buffer = new byte[dataLength]; + var readTask = responseStream.ReadAtLeastAsync(buffer, dataLength); + Assert.False(readTask.IsCompleted); + + // Send DATA frame with padding + frame = new DataFrame(new byte[dataLength], FrameFlags.Padded, paddingLength, streamId); + await connection.WriteFrameAsync(frame); + + Assert.Equal(dataLength, await readTask); + + // Send zero-length, end-stream DATA frame with padding + frame = new DataFrame(new byte[0], FrameFlags.Padded | FrameFlags.EndStream, paddingLength, streamId); + await connection.WriteFrameAsync(frame); + + Assert.Equal(0, await responseStream.ReadAsync(buffer)); + } + } + [Theory] [InlineData("Client content", null)] [InlineData("Client content", "Server content")]