-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Implement HttpProtocolException for HTTP/3 #72095
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
Conversation
|
Tagging subscribers to this area: @dotnet/ncl |
|
We have plenty of tests for HTTP/2 exercising error scenarios, for example: runtime/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs Lines 300 to 316 in a248f40
Is it possible to cover at least a few HTTP/3 cases to verify that we are throwing this exception (including at least one response stream case)? |
| Priority = 0b00100000, | ||
|
|
||
| ValidBits = 0b00101101 | ||
| ValidBits = 0b00101101 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was this formatting alignment intentionally removed?
|
Please don't merge this before #71969 unless you're 100% sure it will not create conflicts. I really need to get that PR in main. |
| // Our stream was reset. | ||
| Exception? abortException = _connection.AbortException; | ||
| throw new HttpRequestException(SR.net_http_client_execution_error, abortException ?? ex); | ||
| throw new HttpRequestException(SR.net_http_client_execution_error, HttpProtocolException.CreateHttp3StreamException(code)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it ok that we are ignoring both _connection.AbortException and ex now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think there is any value of including ex in the HttpProtocolException (it will always be the same and the error code is already in HttpProtocolException.
To tell the truth, I am not 100% sure what the right behavior here is. I didn't notice anything in the RFC which would let server close the stream with other error codes than the two handled above. I would consider it protocol violation and tear down the connection, but the RFC does not AFAIK prohibit using any other code, so we should just pass it by.
As for the _connection.AbortException, there is no harm in checking first and prioritizing it if there is some already. This branch should be pretty rare anyway as explained above.
| Exception abortException = _connection.Abort(ex); | ||
| throw new IOException(SR.net_http_client_execution_error, new HttpRequestException(SR.net_http_client_execution_error, abortException)); | ||
| case Http3ConnectionException: | ||
| case HttpProtocolException: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Judging by CreateHttp3StreamException in HttpProtocolException it seems to me like HttpProtocolException may not always be connection-level. Is that right? This line does not seem as equivalent change then. Or am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The HttpProtocolException thrown from stream is not on a code path which would affect this. In other words, only connection-level exceptions can be encountered here
| _output.WriteLine(outerEx.InnerException.Message); | ||
| HttpProtocolException protocolEx = Assert.IsType<HttpProtocolException>(outerEx.InnerException); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it be this instead?
| _output.WriteLine(outerEx.InnerException.Message); | |
| HttpProtocolException protocolEx = Assert.IsType<HttpProtocolException>(outerEx.InnerException); | |
| HttpProtocolException protocolEx = Assert.IsType<HttpProtocolException>(outerEx.InnerException); | |
| _output.WriteLine(protocolEx.Message); |
Also, if I'm wrong and it's for diagnostics purposes in case it was not a HttpProtocolException, would it be better to include all the info about exceptions, even the top one? Meaning, should we log ToString instead of just Message
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I copied it from HttpClientHandlerTest.Http2 implementation, I can change it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was somewhat accidental in my PR, we don't have to print anything, though it's informative for manual validation of HttpProtocolException's message.
d467805 to
9e4324b
Compare
| await new[] { clientTask, serverTask }.WhenAllOrAnyFailed(20_000); | ||
| } | ||
|
|
||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| case QuicException e when (e.QuicError == QuicError.ConnectionAborted): | ||
| // Our connection was reset. Start aborting the connection. | ||
| Exception abortException = _connection.Abort(ex); | ||
| throw new IOException(SR.net_http_client_execution_error, new HttpRequestException(SR.net_http_client_execution_error, abortException)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering why are we throwing IOException here? Aren't these errors supposed to surface as HttpProtocolException from HttpContent's Http3ReadStream (which seems to delegate to this method)?
| HttpProtocolException protocolEx = Assert.IsType<HttpProtocolException>(outerEx.InnerException); | ||
| _output.WriteLine(protocolEx.Message); | ||
| Assert.Equal(errorCode, protocolEx.ErrorCode); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add yet another test (or a parameteric variant of existing tests), that validates the exception thrown from the response content stream. See AssertProtocolErrorForIOExceptionAsync in http2 tests (I should have renamed that method ...).
antonfirsov
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
|
/backport to release/7.0-preview7 |
|
Started backporting to release/7.0-preview7: https://github.com/dotnet/runtime/actions/runs/2672573752 |
Follow-up on #71432.
Closes #70684.