Add higher-level HTTP upgrade support to Client and Server #1563
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.
This proposes a way to offer an easier way to manage HTTP upgrades than using the lower-level
client::conn
andserver::conn
APIs. This includes bothUpgrade
+101 Switching Protocols
, andCONNECT
tunneling.Body::on_upgrade
It makes use of the
Body
type that is returned by hyper. When the HTTP1 state machine notices an attempt to trigger an upgrade in either the client or the server, the returnedBody
will have some additional state to allow getting aFuture
of an eventual upgrade:Body::on_upgrade(self) -> impl Future
.This
on_upgrade
future, if successful, will return a newhyper::upgrade::Upgraded
type that fully owns the original IO transport, after the upgrade. TheUpgraded
can itself be used as anAsyncRead
/AsyncWrite
for convenience (and automatically including any buffered bytes as part of theread
s). However, if desired, you can also try to deconstruct/downcast from anUpgraded
intohyper::upgrade::Parts<T>
.hyper::upgrade::Upgraded
An added benefit to this API is that it allows adding support for
CONNECT
over HTTP2 without breaking backwards compatibility. The tricky part there normally is thatCONNECT
in HTTP2 doesn't actually take control of the IO transport, but instead continues to sendDATA
frames over the h2 stream. So, once theh2
library adds support, hyper can encapsulate that support in a privateimpl AsyncRead + AsyncWrite
implementation, and still just return anUpgraded
.A papercut in the proposal is that
Upgraded
needs to put the IO in a trait object that can be putBody
, which isSend
. There was a missingI: Send
bounds onserver::conn::Connection
, which makes it impossible to use this new API when using the lower-levelHttp::server_connection
. The proposed solution is to addConnection::with_upgrades()
that converts into a type that does have aSend
bound, and allows using this API.Any usage of
serve_connection
that forgets to addwith_upgrades
will not have upgrades work. Theon_upgrade
future will yield anError
. This error however, does include specific messaging when an upgrade was expected to work, but couldn't because of use of lower-level APIs. Additionally, this means that manual upgrades with the lower-level APIs still work correctly.TODO
hyper::upgrade
module.server::conn::Connection::with_upgrades
method.Closes #1395