Respond 400 + Reset to malformed request#748
Open
franfastly wants to merge 6 commits intohyperium:masterfrom
Open
Respond 400 + Reset to malformed request#748franfastly wants to merge 6 commits intohyperium:masterfrom
franfastly wants to merge 6 commits intohyperium:masterfrom
Conversation
Author
|
I'm not sure why clippy started complaining about this. I could amend this PR to appease clippy or push a fix in separate PR. |
Member
|
Could be a newer clippy being a jerk. |
7b41f65 to
f98522a
Compare
`h2` returns `RST_STREAM` frames with the `PROTOCOL_ERROR` bit set as a response to many types of errors in client requests. Many of those cases, when handled by an HTTP/1 server such as the one used in `hyper`, would result in an HTTP 400 Bad Request response returned to the client rather than a TCP reset (the HTTP/1 equivalent of a `RST_STREAM`). As a consequence, a client will observe differences in behaviour between HTTP/1 and HTTP/2: a malformed request will result in a 400 response when HTTP/1 is used whereas the same request will result in a reset stream with `h2`. Make `h2` reply a `HEADERS`+`400`+`END_STREAM` frame followed by a `RST_STREAM`+`PROTOCOL_ERROR` frame to all the `malformed!()` macro invocations in `Peer::convert_poll_message()` in `src/server.rs`. The `Reset` variant in the `h2::proto::error::Error` Enum now contains an `Option<http::StatusCode>` value that is set by the `malformed!()` macro with a `Some(400)`. That value is propagated all the way until `h2::proto::streams::send::Send::send_reset()` where, if not `None`, a `h2::frame::headers::Headers` frame with the status code and the `END_STREAM` flag set will now be sent to the client before the `RST_STREAM` frame. Some of the parameters passed to `send_reset()` have been grouped into a new `SendResetContext` Struct in order to avoid a `clippy::too_many_arguments` lint. Tests where malformed requests were sent have been updated to check that an additional `HEADERS`+`400`+`END_STREAM` frame is now received before the `RST_STREAM + PROTOCOL_ERROR` frame. This change has been validated with other clients like `curl`, a custom ad-hoc client written with `python3+httpx` and `varnishtest`.
f98522a to
7481e41
Compare
Member
|
@seanmonstar I'm taking over this one from Fran while he's on vacation for the next few weeks. I would offer to do the review myself, but I'm the coauthor of the internal predecessor to this patch; it probably would be good to have a third party perspective before landing this change. |
Author
|
Hi! Is there anything I can do to help with the review of this PR? Thank you in advance! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
h2returnsRST_STREAMframes with thePROTOCOL_ERRORbit set as a response to many types of errors in client requests. Many of those cases, when handled by an HTTP/1 server such as the one used inhyper, would result in an HTTP 400 Bad Request response returned to the client rather than a TCP reset (the HTTP/1 equivalent of aRST_STREAM). As a consequence, a client will observe differences in behaviour between HTTP/1 and HTTP/2: a malformed request will result in a 400 response when HTTP/1 is used whereas the same request will result in a reset stream withh2.This PR makes
h2reply aHEADERS+400+END_STREAMframe followed by aRST_STREAM+PROTOCOL_ERRORframe to all themalformed!()macro invocations inPeer::convert_poll_message()insrc/server.rs.The
Resetvariant in theh2::proto::error::ErrorEnum now contains anOption<http::StatusCode>value that is set by themalformed!()macro with aSome(400). That value is propagated all the way untilh2::proto::streams::send::Send::send_reset()where, if notNone, ah2::frame::headers::Headersframe with the status code and theEND_STREAMflag set will now be sent to the client before theRST_STREAMframe.Some of the parameters passed to
send_reset()have been grouped into a newSendResetContextStruct in order to avoid aclippy::too_many_argumentslint.Tests where malformed requests were sent have been updated to check that an additional
HEADERS+400+END_STREAMframe is now received before theRST_STREAM + PROTOCOL_ERRORframe.This change has been validated with other clients like
curl, a custom ad-hoc client written withpython3+httpxandvarnishtest.Fixes #747