Skip to content

Commit 42535ef

Browse files
committed
feat(upgrade): Moved HTTP upgrades off Body to a new API
BREAKING CHANGE: The method `Body::on_upgrade()` is gone. It is essentially replaced with `hyper::upgrade::on(msg)`.
1 parent ed2b22a commit 42535ef

File tree

3 files changed

+57
-20
lines changed

3 files changed

+57
-20
lines changed

examples/upgrades.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ async fn server_upgraded_io(mut upgraded: Upgraded) -> Result<()> {
3434
}
3535

3636
/// Our server HTTP handler to initiate HTTP upgrades.
37-
async fn server_upgrade(req: Request<Body>) -> Result<Response<Body>> {
37+
async fn server_upgrade(mut req: Request<Body>) -> Result<Response<Body>> {
3838
let mut res = Response::new(Body::empty());
3939

4040
// Send a 400 to any request that doesn't have
@@ -52,7 +52,7 @@ async fn server_upgrade(req: Request<Body>) -> Result<Response<Body>> {
5252
// is returned below, so it's better to spawn this future instead
5353
// waiting for it to complete to then return a response.
5454
tokio::task::spawn(async move {
55-
match req.into_body().on_upgrade().await {
55+
match hyper::upgrade::on(&mut req).await {
5656
Ok(upgraded) => {
5757
if let Err(e) = server_upgraded_io(upgraded).await {
5858
eprintln!("server foobar io error: {}", e)

src/body/body.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -187,13 +187,15 @@ impl Body {
187187
Body::new(Kind::Wrapped(SyncWrapper::new(Box::pin(mapped))))
188188
}
189189

190-
/// Converts this `Body` into a `Future` of a pending HTTP upgrade.
191-
///
192-
/// See [the `upgrade` module](crate::upgrade) for more.
193-
pub fn on_upgrade(self) -> OnUpgrade {
194-
self.extra
195-
.map(|ex| ex.on_upgrade)
196-
.unwrap_or_else(OnUpgrade::none)
190+
// TODO: Eventually the pending upgrade should be stored in the
191+
// `Extensions`, and all these pieces can be removed. In v0.14, we made
192+
// the breaking changes, so now this TODO can be done without breakage.
193+
pub(crate) fn take_upgrade(&mut self) -> OnUpgrade {
194+
if let Some(ref mut extra) = self.extra {
195+
std::mem::replace(&mut extra.on_upgrade, OnUpgrade::none())
196+
} else {
197+
OnUpgrade::none()
198+
}
197199
}
198200

199201
fn new(kind: Kind) -> Body {

src/upgrade.rs

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,16 @@ pub struct Parts<T> {
5757
_inner: (),
5858
}
5959

60+
/// Gets a pending HTTP upgrade from this message.
61+
pub fn on<T: sealed::CanUpgrade>(msg: T) -> OnUpgrade {
62+
msg.on_upgrade()
63+
}
64+
6065
#[cfg(feature = "http1")]
6166
pub(crate) struct Pending {
6267
tx: oneshot::Sender<crate::Result<Upgraded>>,
6368
}
6469

65-
/// Error cause returned when an upgrade was expected but canceled
66-
/// for whatever reason.
67-
///
68-
/// This likely means the actual `Conn` future wasn't polled and upgraded.
69-
#[derive(Debug)]
70-
struct UpgradeExpected(());
71-
7270
#[cfg(feature = "http1")]
7371
pub(crate) fn pending() -> (Pending, OnUpgrade) {
7472
let (tx, rx) = oneshot::channel();
@@ -162,9 +160,7 @@ impl Future for OnUpgrade {
162160
Some(ref mut rx) => Pin::new(rx).poll(cx).map(|res| match res {
163161
Ok(Ok(upgraded)) => Ok(upgraded),
164162
Ok(Err(err)) => Err(err),
165-
Err(_oneshot_canceled) => {
166-
Err(crate::Error::new_canceled().with(UpgradeExpected(())))
167-
}
163+
Err(_oneshot_canceled) => Err(crate::Error::new_canceled().with(UpgradeExpected)),
168164
}),
169165
None => Poll::Ready(Err(crate::Error::new_user_no_upgrade())),
170166
}
@@ -196,9 +192,16 @@ impl Pending {
196192

197193
// ===== impl UpgradeExpected =====
198194

195+
/// Error cause returned when an upgrade was expected but canceled
196+
/// for whatever reason.
197+
///
198+
/// This likely means the actual `Conn` future wasn't polled and upgraded.
199+
#[derive(Debug)]
200+
struct UpgradeExpected;
201+
199202
impl fmt::Display for UpgradeExpected {
200203
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201-
write!(f, "upgrade expected but not completed")
204+
f.write_str("upgrade expected but not completed")
202205
}
203206
}
204207

@@ -277,6 +280,38 @@ impl<T: AsyncRead + AsyncWrite + Unpin + 'static> Io for ForwardsWriteBuf<T> {
277280
}
278281
}
279282

283+
mod sealed {
284+
use super::OnUpgrade;
285+
286+
pub trait CanUpgrade {
287+
fn on_upgrade(self) -> OnUpgrade;
288+
}
289+
290+
impl CanUpgrade for http::Request<crate::Body> {
291+
fn on_upgrade(self) -> OnUpgrade {
292+
self.into_body().take_upgrade()
293+
}
294+
}
295+
296+
impl CanUpgrade for &'_ mut http::Request<crate::Body> {
297+
fn on_upgrade(self) -> OnUpgrade {
298+
self.body_mut().take_upgrade()
299+
}
300+
}
301+
302+
impl CanUpgrade for http::Response<crate::Body> {
303+
fn on_upgrade(self) -> OnUpgrade {
304+
self.into_body().take_upgrade()
305+
}
306+
}
307+
308+
impl CanUpgrade for &'_ mut http::Response<crate::Body> {
309+
fn on_upgrade(self) -> OnUpgrade {
310+
self.body_mut().take_upgrade()
311+
}
312+
}
313+
}
314+
280315
#[cfg(test)]
281316
mod tests {
282317
use super::*;

0 commit comments

Comments
 (0)