Skip to content

Commit 2f0d8b0

Browse files
author
ladeak
committed
Ingoring unknown frames as well resreved frames
1 parent 7953a7d commit 2f0d8b0

2 files changed

Lines changed: 62 additions & 10 deletions

File tree

src/CHttpServer/CHttpServer/Http3/Http3Connection.cs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -257,16 +257,21 @@ private async Task ProcessControlStreamAsync()
257257
var buffer = readResult.Buffer;
258258

259259
if (!VariableLenghtIntegerDecoder.TryRead(buffer.FirstSpan, out ulong frameType, out int bytesRead))
260-
Abort(ErrorCodes.H3FrameError);
260+
{
261+
// Not enough data.
262+
_clientControlStreamReader.AdvanceTo(buffer.Start, buffer.End);
263+
continue;
264+
}
261265

266+
long processed = bytesRead;
262267
if (!VariableLenghtIntegerDecoder.TryRead(buffer.Slice(bytesRead), out ulong payloadLength, out bytesRead))
263268
{
264269
// Not enough data.
265270
_clientControlStreamReader.AdvanceTo(buffer.Start, buffer.End);
266271
continue;
267272
}
268273

269-
long processed = 1 + bytesRead; // 1 for the frame type. Should be always one byte by spec.
274+
processed += bytesRead;
270275
switch (frameType)
271276
{
272277
case 0x03: // CANCEL_PUSH
@@ -299,14 +304,19 @@ private async Task ProcessControlStreamAsync()
299304
processed += checked((long)payloadLength);
300305
break;
301306
default:
302-
// Reserved frame types
303-
if ((frameType - 32) % 31 == 0)
307+
if (frameType < 3 || frameType == 5 || frameType == 6 || frameType == 8 || frameType == 9)
308+
{
309+
// HTTP/2 frame types that are not supported in HTTP/3 must return error.
310+
Abort(ErrorCodes.H3FrameUnexpected);
311+
break;
312+
}
313+
else
304314
{
315+
// Reserved frame types, and unknown frame types ignored.
305316
processed += checked((long)payloadLength);
306317
break;
318+
307319
}
308-
Abort(ErrorCodes.H3FrameUnexpected);
309-
break;
310320
}
311321

312322
_clientControlStreamReader.AdvanceTo(readResult.Buffer.GetPosition(processed));

tests/CHttpServer.Tests/Http3/Http3ConnectionTests.cs

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,15 @@ public async Task ClientAbortsConnection()
110110
await processing;
111111
}
112112

113-
[Fact]
114-
public async Task InvalidFrameTypeOnControlStream_Aborts()
113+
[Theory]
114+
[InlineData(0)]
115+
[InlineData(1)]
116+
[InlineData(2)]
117+
[InlineData(5)]
118+
[InlineData(6)]
119+
[InlineData(8)]
120+
[InlineData(9)]
121+
public async Task InvalidFrameTypeOnControlStream_Aborts(int frameType)
115122
{
116123
await using var fixture = await QuicConnectionFixture.SetupConnectionAsync(Port, TestContext.Current.CancellationToken);
117124
Http3Connection sut = CreateHttp3Connection(fixture.ServerConnection);
@@ -125,8 +132,43 @@ public async Task InvalidFrameTypeOnControlStream_Aborts()
125132
}, TestContext.Current.CancellationToken);
126133
var clientControlStream = await fixture.ClientConnection.OpenOutboundStreamAsync(QuicStreamType.Unidirectional, TestContext.Current.CancellationToken);
127134

128-
// StreamType: 0-control, FrameType: 4-Headers, Length: 0
129-
byte[] data = [0, 1, 0];
135+
// StreamType: 0-control, FrameType: 1-Invalid, Length: 0
136+
byte[] data = [0, (byte)frameType, 0];
137+
await clientControlStream.WriteAsync(data, TestContext.Current.CancellationToken);
138+
await clientControlStream.FlushAsync(TestContext.Current.CancellationToken);
139+
140+
await readServerControlStream;
141+
await processing;
142+
}
143+
144+
[Theory]
145+
[InlineData(1 * 31 + 33)]
146+
[InlineData(2 * 31 + 33)]
147+
[InlineData(0x0f0700)]
148+
public async Task UnknownFrameType_OnControlStream_ISgnored(int frameType)
149+
{
150+
await using var fixture = await QuicConnectionFixture.SetupConnectionAsync(Port, TestContext.Current.CancellationToken);
151+
Http3Connection sut = CreateHttp3Connection(fixture.ServerConnection);
152+
var processing = sut.ProcessConnectionAsync(new TestBase.TestApplication(_ => Task.CompletedTask))
153+
.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken);
154+
var readServerControlStream = Task.Run(async () =>
155+
{
156+
var controlStream = await fixture.ClientConnection.AcceptInboundStreamAsync(TestContext.Current.CancellationToken);
157+
await AssertReadSettigsAsync(controlStream);
158+
await AssertGoAwayAsync(controlStream, 2);
159+
}, TestContext.Current.CancellationToken);
160+
var clientControlStream = await fixture.ClientConnection.OpenOutboundStreamAsync(QuicStreamType.Unidirectional, TestContext.Current.CancellationToken);
161+
162+
// StreamType: 0-control, FrameType, Length: 0
163+
Span<byte> buffer = stackalloc byte[8];
164+
VariableLenghtIntegerDecoder.TryWrite(buffer, frameType, out var length);
165+
166+
byte[] data = [0, .. buffer[..length], 0];
167+
await clientControlStream.WriteAsync(data, TestContext.Current.CancellationToken);
168+
await clientControlStream.FlushAsync(TestContext.Current.CancellationToken);
169+
170+
// Write GOAWAY FrameType: 7, Length: 1, StreamId: 0
171+
data = [7, 1, 0];
130172
await clientControlStream.WriteAsync(data, TestContext.Current.CancellationToken);
131173
await clientControlStream.FlushAsync(TestContext.Current.CancellationToken);
132174

0 commit comments

Comments
 (0)