Skip to content

Commit 7912bde

Browse files
committed
[Http/2] Fix handling of effectively empty DATA frame (dotnet#99502)
* Fix handling effectively empty DATA frame * Added test
1 parent bc5e878 commit 7912bde

File tree

2 files changed

+48
-2
lines changed

2 files changed

+48
-2
lines changed

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -746,12 +746,14 @@ private void ProcessDataFrame(FrameHeader frameHeader)
746746
// Just ignore the frame in this case.
747747

748748
ReadOnlySpan<byte> frameData = GetFrameData(_incomingBuffer.ActiveSpan.Slice(0, frameHeader.PayloadLength), hasPad: frameHeader.PaddedFlag, hasPriority: false);
749-
750749
if (http2Stream != null)
751750
{
752751
bool endStream = frameHeader.EndStreamFlag;
753752

754-
http2Stream.OnResponseData(frameData, endStream);
753+
if (frameData.Length > 0 || endStream)
754+
{
755+
http2Stream.OnResponseData(frameData, endStream);
756+
}
755757

756758
if (!endStream && frameData.Length > 0)
757759
{

src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,50 @@ public async Task Http2_ZeroLengthResponseBody_Success()
177177
}
178178
}
179179

180+
[Fact]
181+
public async Task Http2_DataFrameOnlyPadding_Success()
182+
{
183+
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
184+
using (HttpClient client = CreateHttpClient())
185+
{
186+
Task<HttpResponseMessage> sendTask = client.GetAsync(server.Address, HttpCompletionOption.ResponseHeadersRead);
187+
188+
Http2LoopbackConnection connection = await server.EstablishConnectionAsync();
189+
190+
int streamId = await connection.ReadRequestHeaderAsync();
191+
192+
await connection.SendDefaultResponseHeadersAsync(streamId);
193+
194+
// Send zero-length DATA frame with padding
195+
byte paddingLength = byte.MaxValue;
196+
int dataLength = 1024;
197+
DataFrame frame = new DataFrame(new byte[0], FrameFlags.Padded, paddingLength, streamId);
198+
await connection.WriteFrameAsync(frame);
199+
200+
HttpResponseMessage response = await sendTask;
201+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
202+
203+
using var responseStream = response.Content.ReadAsStream();
204+
205+
// The read must pend because we havent received any data yet.
206+
var buffer = new byte[dataLength];
207+
var readTask = responseStream.ReadAtLeastAsync(buffer, dataLength);
208+
Assert.False(readTask.IsCompleted);
209+
210+
// Send DATA frame with padding
211+
frame = new DataFrame(new byte[dataLength], FrameFlags.Padded, paddingLength, streamId);
212+
await connection.WriteFrameAsync(frame);
213+
214+
Assert.Equal(dataLength, await readTask);
215+
216+
// Send zero-length, end-stream DATA frame with padding
217+
frame = new DataFrame(new byte[0], FrameFlags.Padded | FrameFlags.EndStream, paddingLength, streamId);
218+
await connection.WriteFrameAsync(frame);
219+
220+
Assert.Equal(0, await responseStream.ReadAsync(buffer));
221+
}
222+
}
223+
180224
[Theory]
181225
[InlineData("Client content", null)]
182226
[InlineData("Client content", "Server content")]

0 commit comments

Comments
 (0)