-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Implement CONNECT support over HTTP/2 #2523
Conversation
6a6d080
to
d6ba136
Compare
14876e5
to
817e111
Compare
3c7a507
to
c04e447
Compare
b3c9b60
to
82dd5bb
Compare
a68864d
to
e015d47
Compare
@seanmonstar may I ask you to take a look as well? |
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 is fantastic, excellent work! Love the detailed tests too!
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.
Made an exhaustive review of the additional bounds, they are unfortunately indeed breaking changes.
170a72f
to
a2385ae
Compare
I have an idea to remove the bound on |
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 have implemented my cursed idea, tell me what you think about it.
845c9c9
to
3d5caf1
Compare
I added preliminary client-side support. |
} else { | ||
if content_length.map_or(false, |len| len != 0) { | ||
warn!("h2 connect request with non-zero body not supported"); | ||
respond.send_reset(h2::Reason::INTERNAL_ERROR); |
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.
Since, at this stage it is the client breaking the rules, maybe this should be a PROTOCOL_ERROR
,
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.
Does it truly break the rules? I don't remember seeing prose explicitly rejecting this.
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.
So the most current HTTP specs (close to being RFCs) say https://httpwg.org/http-core/draft-ietf-httpbis-semantics-latest.html#rfc.section.9.3.6.p.12
A server MUST NOT send any Transfer-Encoding or Content-Length header fields in a 2xx (Successful) response to CONNECT. A client MUST ignore any Content-Length or Transfer-Encoding header fields received in a successful response to CONNECT.
A CONNECT request message does not have content. The interpretation of and allowability of data sent after the header section of the CONNECT request message is specific to the version of HTTP in use.
And the HTTP/2 spec doesn't seem to clearly state things either way. No point splitting hairs over an error code so lets leave that. In the meantime I opened an issue on the HTTP/2 spec in the hope that RFC 7540 CONNECT definition could get tightened up. See httpwg/http2-spec#849
} | ||
let (pending, upgrade) = crate::upgrade::pending(); | ||
debug_assert!(parts.extensions.get::<OnUpgrade>().is_none()); | ||
parts.extensions.insert(upgrade); |
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 might be missing it, does the server enforce that the authority form is used?
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.
h2
itself will fail if passed a non-authority URI for a CONNECT request, on the Hyper side I just did like what already exists for HTTP/1.
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.
SGTM, thanks for explaining.
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.
Replied to Lucas' comments, I'll make sure we don't reject bodies on non-200 responses.
} | ||
let (pending, upgrade) = crate::upgrade::pending(); | ||
debug_assert!(parts.extensions.get::<OnUpgrade>().is_none()); | ||
parts.extensions.insert(upgrade); |
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.
h2
itself will fail if passed a non-authority URI for a CONNECT request, on the Hyper side I just did like what already exists for HTTP/1.
} else { | ||
if content_length.map_or(false, |len| len != 0) { | ||
warn!("h2 connect request with non-zero body not supported"); | ||
respond.send_reset(h2::Reason::INTERNAL_ERROR); |
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.
Does it truly break the rules? I don't remember seeing prose explicitly rejecting this.
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.
Stupendous!
Back in hyperium#2523, @nox introduced the notion of an UpgradedSendStream, to support the CONNECT method of HTTP/2. This used `unsafe {}` to support `http_body::Body`, where `Body::Data` did not implement `Send`, since the `Data` type wouldn't be sent across the stream once upgraded. Unfortunately, according to this [thread], I think this may be undefined behavior, because this relies on us requiring the transmute to execute. This patch fixes the potential UB by adding the unncessary `Send` constraints. It appears that all the internal users of `UpgradeSendStream` already work with `http_body::Body` types that have `Send`-able `Data` constraints. We can add this constraint without breaking any external APIs, which lets us remove the `unsafe {}` blocks. [thread]: https://users.rust-lang.org/t/is-a-reference-to-impossible-value-considered-ub/31383
Back in hyperium#2523, @nox introduced the notion of an UpgradedSendStream, to support the CONNECT method of HTTP/2. This used `unsafe {}` to support `http_body::Body`, where `Body::Data` did not implement `Send`, since the `Data` type wouldn't be sent across the stream once upgraded. Unfortunately, according to this [thread], I think this may be undefined behavior, because this relies on us requiring the transmute to execute. This patch fixes the potential UB by adding the unncessary `Send` constraints. It appears that all the internal users of `UpgradeSendStream` already work with `http_body::Body` types that have `Send`-able `Data` constraints. We can add this constraint without breaking any external APIs, which lets us remove the `unsafe {}` blocks. [thread]: https://users.rust-lang.org/t/is-a-reference-to-impossible-value-considered-ub/31383
There are quite a few details to sort out, grep for
FIXME(nox)
.