Skip to content

Commit

Permalink
Connection error for invalid HTTP/3 frame on request stream
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesNK committed Mar 6, 2021
1 parent e61245a commit eee57aa
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 15 deletions.
6 changes: 6 additions & 0 deletions src/Servers/Kestrel/Core/src/CoreStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -659,4 +659,10 @@ For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?l
<data name="Http3StreamErrorFrameReceivedAfterTrailers" xml:space="preserve">
<value>The client sent a {frameType} frame after trailing HEADERS.</value>
</data>
<data name="Http3ErrorUnsupportedFrameOnRequestStream" xml:space="preserve">
<value>The client sent a {frameType} frame to a request stream which isn't supported.</value>
</data>
<data name="Http3ErrorUnsupportedFrameOnServer" xml:space="preserve">
<value>The client sent a {frameType} frame to a the server which isn't supported.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,17 @@ public void PrepareData()
Length = 0;
Type = Http3FrameType.Data;
}

public string FormattedType => Type switch
{
Http3FrameType.Data => "DATA",
Http3FrameType.Headers => "HEADERS",
Http3FrameType.CancelPush => "CANCEL_PUSH",
Http3FrameType.Settings => "SETTINGS",
Http3FrameType.PushPromise => "PUSH_PROMISE",
Http3FrameType.GoAway => "GO_AWAY",
Http3FrameType.MaxPushId => "MAX_PUSH_ID",
_ => Type.ToString()
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,6 @@ private ValueTask ProcessHttp3ControlStream(in ReadOnlySequence<byte> payload)
{
case Http3FrameType.Data:
case Http3FrameType.Headers:
case Http3FrameType.DuplicatePush:
case Http3FrameType.PushPromise:
throw new Http3ConnectionException("HTTP_FRAME_UNEXPECTED");
case Http3FrameType.Settings:
Expand Down
11 changes: 6 additions & 5 deletions src/Servers/Kestrel/Core/src/Internal/Http3/Http3Stream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -446,14 +446,15 @@ private Task ProcessHttp3Stream<TContext>(IHttpApplication<TContext> application
return ProcessDataFrameAsync(payload);
case Http3FrameType.Headers:
return ProcessHeadersFrameAsync(application, payload);
// need to be on control stream
case Http3FrameType.DuplicatePush:
case Http3FrameType.PushPromise:
case Http3FrameType.Settings:
case Http3FrameType.GoAway:
case Http3FrameType.CancelPush:
case Http3FrameType.GoAway:
case Http3FrameType.MaxPushId:
throw new Http3ConnectionException("HTTP_FRAME_UNEXPECTED");
// These frames need to be on a control stream
throw new Http3StreamErrorException(CoreStrings.FormatHttp3ErrorUnsupportedFrameOnRequestStream(_incomingFrame.FormattedType), Http3ErrorCode.UnexpectedFrame);
case Http3FrameType.PushPromise:
// The server should never receive push promise
throw new Http3StreamErrorException(CoreStrings.FormatHttp3ErrorUnsupportedFrameOnServer(_incomingFrame.FormattedType), Http3ErrorCode.UnexpectedFrame);
default:
return ProcessUnknownFrameAsync();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1726,5 +1726,34 @@ public async Task TrailersWithoutEndingStream_ErrorAccessingTrailers()
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => readTrailersTcs.Task).DefaultTimeout();
Assert.Equal("The request trailers are not available yet. They may not be available until the full request body is read.", ex.Message);
}

[Theory]
[InlineData(nameof(Http3FrameType.MaxPushId))]
[InlineData(nameof(Http3FrameType.Settings))]
[InlineData(nameof(Http3FrameType.CancelPush))]
[InlineData(nameof(Http3FrameType.GoAway))]
public async Task UnexpectedRequestFrame(string frameType)
{
var requestStream = await InitializeConnectionAndStreamsAsync(_echoApplication);

var frame = new Http3RawFrame();
frame.Type = Enum.Parse<Http3FrameType>(frameType);
await requestStream.SendFrameAsync(frame, Memory<byte>.Empty);

await requestStream.WaitForStreamErrorAsync(Http3ErrorCode.UnexpectedFrame, expectedErrorMessage: CoreStrings.FormatHttp3ErrorUnsupportedFrameOnRequestStream(frame.FormattedType));
}

[Theory]
[InlineData(nameof(Http3FrameType.PushPromise))]
public async Task UnexpectedServerFrame(string frameType)
{
var requestStream = await InitializeConnectionAndStreamsAsync(_echoApplication);

var frame = new Http3RawFrame();
frame.Type = Enum.Parse<Http3FrameType>(frameType);
await requestStream.SendFrameAsync(frame, Memory<byte>.Empty);

await requestStream.WaitForStreamErrorAsync(Http3ErrorCode.UnexpectedFrame, expectedErrorMessage: CoreStrings.FormatHttp3ErrorUnsupportedFrameOnServer(frame.FormattedType));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -369,24 +369,23 @@ public async Task<bool> SendHeadersAsync(IEnumerable<KeyValuePair<string, string
frame.PrepareHeaders();
var buffer = _headerEncodingBuffer.AsMemory();
var done = _qpackEncoder.BeginEncode(headers, buffer.Span, out var length);
frame.Length = length;
// TODO may want to modify behavior of input frames to mock different client behavior (client can send anything).
Http3FrameWriter.WriteHeader(frame, outputWriter);
await SendAsync(buffer.Span.Slice(0, length));

if (endStream)
{
await _pair.Application.Output.CompleteAsync();
}
// TODO may want to modify behavior of input frames to mock different client behavior (client can send anything).
await SendFrameAsync(frame, buffer.Slice(0, length), endStream);

return done;
}

internal async Task SendDataAsync(Memory<byte> data, bool endStream = false)
{
var outputWriter = _pair.Application.Output;
var frame = new Http3RawFrame();
frame.PrepareData();
await SendFrameAsync(frame, data, endStream);
}

internal async Task SendFrameAsync(Http3RawFrame frame, Memory<byte> data, bool endStream = false)
{
var outputWriter = _pair.Application.Output;
frame.Length = data.Length;
Http3FrameWriter.WriteHeader(frame, outputWriter);
await SendAsync(data.Span);
Expand Down

0 comments on commit eee57aa

Please sign in to comment.