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

[release/7.0-preview7] Implement HttpProtocolException for HTTP/3 #72210

Merged
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 @@ -84,10 +84,7 @@ public override async ValueTask DisposeAsync()
#endif
}

public async Task CloseAsync(long errorCode)
{
await _connection.CloseAsync(errorCode).ConfigureAwait(false);
}
public Task CloseAsync(long errorCode) => _connection.CloseAsync(errorCode).AsTask();

public async ValueTask<Http3LoopbackStream> OpenUnidirectionalStreamAsync()
{
Expand Down
9 changes: 9 additions & 0 deletions src/libraries/System.Net.Http/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -408,9 +408,15 @@
<data name="net_http_http2_connection_error" xml:space="preserve">
<value>The HTTP/2 server sent invalid data on the connection. HTTP/2 error code '{0}' (0x{1}).</value>
</data>
<data name="net_http_http2_connection_close" xml:space="preserve">
<value>The HTTP/2 server closed the connection. HTTP/2 error code '{0}' (0x{1}).</value>
</data>
<data name="net_http_http2_stream_error" xml:space="preserve">
<value>The HTTP/2 server reset the stream. HTTP/2 error code '{0}' (0x{1}).</value>
</data>
<data name="net_http_http3_stream_error" xml:space="preserve">
<value>The HTTP/3 server reset the stream. HTTP/3 error code '{0}' (0x{1}).</value>
</data>
<data name="net_http_http2_connection_not_established" xml:space="preserve">
<value>An HTTP/2 connection could not be established because the server did not complete the HTTP/2 handshake.</value>
</data>
Expand Down Expand Up @@ -477,6 +483,9 @@
<data name="net_http_http3_connection_error" xml:space="preserve">
<value>The HTTP/3 server sent invalid data on the connection. HTTP/3 error code '{0}' (0x{1}).</value>
</data>
<data name="net_http_http3_connection_close" xml:space="preserve">
<value>The HTTP/3 server closed the connection. HTTP/3 error code '{0}' (0x{1}).</value>
</data>
<data name="net_http_retry_on_older_version" xml:space="preserve">
<value>The server is unable to process the request using the current HTTP version and indicates the request should be retried on an older HTTP version.</value>
</data>
Expand Down
2 changes: 0 additions & 2 deletions src/libraries/System.Net.Http/src/System.Net.Http.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,6 @@
<Compile Include="System\Net\Http\SocketsHttpHandler\Http2Stream.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\Http2StreamWindowManager.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\Http3Connection.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\Http3ConnectionException.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\Http3ProtocolException.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\Http3RequestStream.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\HttpAuthenticatedConnectionHandler.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\HttpAuthority.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,21 @@ internal static HttpProtocolException CreateHttp2StreamException(Http2ProtocolEr
return new HttpProtocolException((long)protocolError, message, null);
}

internal static HttpProtocolException CreateHttp2ConnectionException(Http2ProtocolErrorCode protocolError)
internal static HttpProtocolException CreateHttp2ConnectionException(Http2ProtocolErrorCode protocolError, string? message = null)
{
string message = SR.Format(SR.net_http_http2_connection_error, GetName(protocolError), ((int)protocolError).ToString("x"));
message = SR.Format(message ?? SR.net_http_http2_connection_error, GetName(protocolError), ((int)protocolError).ToString("x"));
return new HttpProtocolException((long)protocolError, message, null);
}

internal static HttpProtocolException CreateHttp3StreamException(Http3ErrorCode protocolError)
{
string message = SR.Format(SR.net_http_http3_stream_error, GetName(protocolError), ((int)protocolError).ToString("x"));
return new HttpProtocolException((long)protocolError, message, null);
}

internal static HttpProtocolException CreateHttp3ConnectionException(Http3ErrorCode protocolError, string? message = null)
{
message = SR.Format(message ?? SR.net_http_http3_connection_error, GetName(protocolError), ((int)protocolError).ToString("x"));
return new HttpProtocolException((long)protocolError, message, null);
}

Expand All @@ -67,6 +79,29 @@ private static string GetName(Http2ProtocolErrorCode code) =>
Http2ProtocolErrorCode.Http11Required => "HTTP_1_1_REQUIRED",
_ => "(unknown error)",
};

private static string GetName(Http3ErrorCode code) =>
// These strings come from the H3 spec and should not be localized.
code switch
{
Http3ErrorCode.NoError => "H3_NO_ERROR",
Http3ErrorCode.ProtocolError => "H3_GENERAL_PROTOCOL_ERROR",
Http3ErrorCode.InternalError => "H3_INTERNAL_ERROR",
Http3ErrorCode.StreamCreationError => "H3_STREAM_CREATION_ERROR",
Http3ErrorCode.ClosedCriticalStream => "H3_CLOSED_CRITICAL_STREAM",
Http3ErrorCode.UnexpectedFrame => "H3_FRAME_UNEXPECTED",
Http3ErrorCode.FrameError => "H3_FRAME_ERROR",
Http3ErrorCode.ExcessiveLoad => "H3_EXCESSIVE_LOAD",
Http3ErrorCode.IdError => "H3_ID_ERROR",
Http3ErrorCode.SettingsError => "H3_SETTINGS_ERROR",
Http3ErrorCode.MissingSettings => "H3_MISSING_SETTINGS",
Http3ErrorCode.RequestRejected => "H3_REQUEST_REJECTED",
Http3ErrorCode.RequestCancelled => "H3_REQUEST_CANCELLED",
Http3ErrorCode.RequestIncomplete => "H3_REQUEST_INCOMPLETE",
Http3ErrorCode.ConnectError => "H3_CONNECT_ERROR",
Http3ErrorCode.VersionFallback => "H3_VERSION_FALLBACK",
_ => "(unknown error)"
};
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,8 @@ public Http2Connection(HttpConnectionPool pool, Stream stream)

if (NetEventSource.Log.IsEnabled()) TraceConnection(_stream);

static long TimeSpanToMs(TimeSpan value) {
static long TimeSpanToMs(TimeSpan value)
{
double milliseconds = value.TotalMilliseconds;
return (long)(milliseconds > int.MaxValue ? int.MaxValue : milliseconds);
}
Expand Down Expand Up @@ -486,7 +487,7 @@ private async Task ProcessIncomingFramesAsync()
if (frameHeader.Type == FrameType.GoAway)
{
var (_, errorCode) = ReadGoAwayFrame(frameHeader);
ThrowProtocolError(errorCode);
ThrowProtocolError(errorCode, SR.net_http_http2_connection_close);
}
else
{
Expand Down Expand Up @@ -1045,7 +1046,7 @@ private void ProcessGoAwayFrame(FrameHeader frameHeader)
var (lastStreamId, errorCode) = ReadGoAwayFrame(frameHeader);

Debug.Assert(lastStreamId >= 0);
Exception resetException = HttpProtocolException.CreateHttp2ConnectionException(errorCode);
Exception resetException = HttpProtocolException.CreateHttp2ConnectionException(errorCode, SR.net_http_http2_connection_close);

// There is no point sending more PING frames for RTT estimation:
_rttEstimator.OnGoAwayReceived();
Expand Down Expand Up @@ -1258,7 +1259,7 @@ private Task SendPingAsync(long pingContent, bool isAck = false) =>
Debug.Assert(sizeof(long) == FrameHeader.PingLength);

Span<byte> span = writeBuffer.Span;
FrameHeader.WriteTo(span, FrameHeader.PingLength, FrameType.Ping, state.isAck ? FrameFlags.Ack: FrameFlags.None, streamId: 0);
FrameHeader.WriteTo(span, FrameHeader.PingLength, FrameType.Ping, state.isAck ? FrameFlags.Ack : FrameFlags.None, streamId: 0);
BinaryPrimitives.WriteInt64BigEndian(span.Slice(FrameHeader.Size), state.pingContent);

return true;
Expand Down Expand Up @@ -2140,7 +2141,7 @@ private static void ThrowProtocolError() =>
ThrowProtocolError(Http2ProtocolErrorCode.ProtocolError);

[DoesNotReturn]
private static void ThrowProtocolError(Http2ProtocolErrorCode errorCode) =>
throw HttpProtocolException.CreateHttp2ConnectionException(errorCode);
private static void ThrowProtocolError(Http2ProtocolErrorCode errorCode, string? message = null) =>
throw HttpProtocolException.CreateHttp2ConnectionException(errorCode, message);
}
}
Loading