Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Http/2] Fix handling of effectively empty DATA frame #99502

Merged
merged 2 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -765,9 +765,12 @@ 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);

bool endStream = frameHeader.EndStreamFlag;
http2Stream?.OnResponseData(frameData, endStream);

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

if (frameData.Length > 0)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<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