Skip to content

Commit

Permalink
[Http/2] Fix handling of effectively empty DATA frame (#99502) (#99677)
Browse files Browse the repository at this point in the history
* Fix handling effectively empty DATA frame

* Added test
  • Loading branch information
ManickaP authored Mar 26, 2024
1 parent 99c7022 commit b7f0477
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -765,12 +765,14 @@ private void ProcessDataFrame(FrameHeader frameHeader)
// Just ignore the frame in this case.

ReadOnlySpan<byte> frameData = GetFrameData(_incomingBuffer.ActiveSpan.Slice(0, frameHeader.PayloadLength), hasPad: frameHeader.PaddedFlag, hasPriority: false);

if (http2Stream != null)
{
bool endStream = frameHeader.EndStreamFlag;

http2Stream.OnResponseData(frameData, endStream);
if (frameData.Length > 0 || endStream)
{
http2Stream.OnResponseData(frameData, endStream);
}

if (!endStream && frameData.Length > 0)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,50 @@ public async Task Http2_ZeroLengthResponseBody_Success()
}
}

[Fact]
public async Task Http2_DataFrameOnlyPadding_Success()
{
using (Http2LoopbackServer server = Http2LoopbackServer.CreateServer())
using (HttpClient client = CreateHttpClient())
{
Task<HttpResponseMessage> 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")]
Expand Down

0 comments on commit b7f0477

Please sign in to comment.