Skip to main content

hyper/
upgrade.rs

1//! HTTP Upgrades.
2//!
3//! This module deals with managing [HTTP Upgrades][mdn] in hyper. Since
4//! several concepts in HTTP allow for first talking HTTP, and then converting
5//! to a different protocol, this module conflates them into a single API.
6//! Those include:
7//!
8//! - HTTP/1.1 Upgrades
9//! - HTTP `CONNECT`
10//!
11//! You are responsible for any other pre-requisites to establish an upgrade,
12//! such as sending the appropriate headers, methods, and status codes. You can
13//! then use [`on`][] to grab a `Future` which will resolve to the upgraded
14//! connection object, or an error if the upgrade fails.
15//!
16//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism
17//!
18//! # Client
19//!
20//! Sending an HTTP upgrade from the [`client`](super::client) involves setting
21//! either the appropriate method, if wanting to `CONNECT`, or headers such as
22//! `Upgrade` and `Connection`, on the `http::Request`. Once receiving the
23//! `http::Response` back, you must check for the specific information that the
24//! upgrade is agreed upon by the server (such as a `101` status code), and then
25//! get the `Future` from the `Response`.
26//!
27//! # Server
28//!
29//! Receiving upgrade requests in a server requires you to check the relevant
30//! headers in a `Request`, and if an upgrade should be done, you then send the
31//! corresponding headers in a response. To then wait for hyper to finish the
32//! upgrade, you call `on()` with the `Request`, and then can spawn a task
33//! awaiting it.
34//!
35//! # Example
36//!
37//! See [this example][example] showing how upgrades work with both
38//! Clients and Servers.
39//!
40//! [example]: https://github.com/hyperium/hyper/blob/master/examples/upgrades.rs
41
42use std::any::TypeId;
43use std::error::Error as StdError;
44use std::fmt;
45use std::future::Future;
46use std::io;
47use std::pin::Pin;
48use std::sync::{Arc, Mutex};
49use std::task::{Context, Poll};
50
51use crate::rt::{Read, ReadBufCursor, Write};
52use bytes::Bytes;
53use tokio::sync::oneshot;
54
55use crate::common::io::Rewind;
56use crate::common::lock::LockResultExt;
57
58/// An upgraded HTTP connection.
59///
60/// This type holds a trait object internally of the original IO that
61/// was used to speak HTTP before the upgrade. It can be used directly
62/// as a [`Read`] or [`Write`] for convenience.
63///
64/// Alternatively, if the exact type is known, this can be deconstructed
65/// into its parts.
66pub struct Upgraded {
67    io: Rewind<Box<dyn Io + Send>>,
68}
69
70/// A future for a possible HTTP upgrade.
71///
72/// If no upgrade was available, or it doesn't succeed, yields an `Error`.
73#[derive(Clone)]
74pub struct OnUpgrade {
75    rx: Option<Arc<Mutex<oneshot::Receiver<crate::Result<Upgraded>>>>>,
76}
77
78/// The deconstructed parts of an [`Upgraded`] type.
79///
80/// Includes the original IO type, and a read buffer of bytes that the
81/// HTTP state machine may have already read before completing an upgrade.
82#[derive(Debug)]
83#[non_exhaustive]
84pub struct Parts<T> {
85    /// The original IO object used before the upgrade.
86    pub io: T,
87    /// A buffer of bytes that have been read but not processed as HTTP.
88    ///
89    /// For instance, if the `Connection` is used for an HTTP upgrade request,
90    /// it is possible the server sent back the first bytes of the new protocol
91    /// along with the response upgrade.
92    ///
93    /// You will want to check for any existing bytes if you plan to continue
94    /// communicating on the IO object.
95    pub read_buf: Bytes,
96}
97
98/// Gets a pending HTTP upgrade from this message.
99///
100/// This can be called on the following types:
101///
102/// - `http::Request<B>`
103/// - `http::Response<B>`
104/// - `&mut http::Request<B>`
105/// - `&mut http::Response<B>`
106pub fn on<T: sealed::CanUpgrade>(msg: T) -> OnUpgrade {
107    msg.on_upgrade()
108}
109
110#[cfg(all(
111    any(feature = "client", feature = "server"),
112    any(feature = "http1", feature = "http2"),
113))]
114pub(super) struct Pending {
115    tx: oneshot::Sender<crate::Result<Upgraded>>,
116}
117
118#[cfg(all(
119    any(feature = "client", feature = "server"),
120    any(feature = "http1", feature = "http2"),
121))]
122pub(super) fn pending() -> (Pending, OnUpgrade) {
123    let (tx, rx) = oneshot::channel();
124    (
125        Pending { tx },
126        OnUpgrade {
127            rx: Some(Arc::new(Mutex::new(rx))),
128        },
129    )
130}
131
132// ===== impl Upgraded =====
133
134impl Upgraded {
135    #[cfg(all(
136        any(feature = "client", feature = "server"),
137        any(feature = "http1", feature = "http2")
138    ))]
139    pub(super) fn new<T>(io: T, read_buf: Bytes) -> Self
140    where
141        T: Read + Write + Unpin + Send + 'static,
142    {
143        Upgraded {
144            io: Rewind::new_buffered(Box::new(io), read_buf),
145        }
146    }
147
148    /// Tries to downcast the internal trait object to the type passed.
149    ///
150    /// On success, returns the downcasted parts.
151    ///
152    /// # Errors
153    /// On error, returns the `Upgraded` back.
154    pub fn downcast<T: Read + Write + Unpin + 'static>(self) -> Result<Parts<T>, Self> {
155        let (io, buf) = self.io.into_inner();
156        match io.__hyper_downcast() {
157            Ok(t) => Ok(Parts {
158                io: *t,
159                read_buf: buf,
160            }),
161            Err(io) => Err(Upgraded {
162                io: Rewind::new_buffered(io, buf),
163            }),
164        }
165    }
166}
167
168impl Read for Upgraded {
169    fn poll_read(
170        mut self: Pin<&mut Self>,
171        cx: &mut Context<'_>,
172        buf: ReadBufCursor<'_>,
173    ) -> Poll<io::Result<()>> {
174        Pin::new(&mut self.io).poll_read(cx, buf)
175    }
176}
177
178impl Write for Upgraded {
179    fn poll_write(
180        mut self: Pin<&mut Self>,
181        cx: &mut Context<'_>,
182        buf: &[u8],
183    ) -> Poll<io::Result<usize>> {
184        Pin::new(&mut self.io).poll_write(cx, buf)
185    }
186
187    fn poll_write_vectored(
188        mut self: Pin<&mut Self>,
189        cx: &mut Context<'_>,
190        bufs: &[io::IoSlice<'_>],
191    ) -> Poll<io::Result<usize>> {
192        Pin::new(&mut self.io).poll_write_vectored(cx, bufs)
193    }
194
195    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
196        Pin::new(&mut self.io).poll_flush(cx)
197    }
198
199    fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
200        Pin::new(&mut self.io).poll_shutdown(cx)
201    }
202
203    fn is_write_vectored(&self) -> bool {
204        self.io.is_write_vectored()
205    }
206}
207
208impl fmt::Debug for Upgraded {
209    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210        f.debug_struct("Upgraded").finish()
211    }
212}
213
214// ===== impl OnUpgrade =====
215
216impl OnUpgrade {
217    pub(super) fn none() -> Self {
218        OnUpgrade { rx: None }
219    }
220
221    #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
222    pub(super) fn is_none(&self) -> bool {
223        self.rx.is_none()
224    }
225}
226
227impl Future for OnUpgrade {
228    type Output = Result<Upgraded, crate::Error>;
229
230    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
231        match &self.rx {
232            Some(rx) => {
233                Pin::new(&mut *rx.lock().panic_if_poisoned())
234                    .poll(cx)
235                    .map(|res| match res {
236                        Ok(Ok(upgraded)) => Ok(upgraded),
237                        Ok(Err(err)) => Err(err),
238                        Err(_oneshot_canceled) => {
239                            Err(crate::Error::new_canceled().with(UpgradeExpected))
240                        }
241                    })
242            }
243            None => Poll::Ready(Err(crate::Error::new_user_no_upgrade())),
244        }
245    }
246}
247
248impl fmt::Debug for OnUpgrade {
249    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250        f.debug_struct("OnUpgrade").finish()
251    }
252}
253
254// ===== impl Pending =====
255
256#[cfg(all(
257    any(feature = "client", feature = "server"),
258    any(feature = "http1", feature = "http2")
259))]
260impl Pending {
261    pub(super) fn fulfill(self, upgraded: Upgraded) {
262        trace!("pending upgrade fulfill");
263        let _ = self.tx.send(Ok(upgraded));
264    }
265
266    #[cfg(feature = "http1")]
267    /// Don't fulfill the pending Upgrade, but instead signal that
268    /// upgrades are handled manually.
269    pub(super) fn manual(self) {
270        #[cfg(any(feature = "http1", feature = "http2"))]
271        trace!("pending upgrade handled manually");
272        let _ = self.tx.send(Err(crate::Error::new_user_manual_upgrade()));
273    }
274}
275
276// ===== impl UpgradeExpected =====
277
278/// Error cause returned when an upgrade was expected but canceled
279/// for whatever reason.
280///
281/// This likely means the actual `Conn` future wasn't polled and upgraded.
282#[derive(Debug)]
283struct UpgradeExpected;
284
285impl fmt::Display for UpgradeExpected {
286    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
287        f.write_str("upgrade expected but not completed")
288    }
289}
290
291impl StdError for UpgradeExpected {}
292
293// ===== impl Io =====
294
295pub(super) trait Io: Read + Write + Unpin + 'static {
296    fn __hyper_type_id(&self) -> TypeId {
297        TypeId::of::<Self>()
298    }
299}
300
301impl<T: Read + Write + Unpin + 'static> Io for T {}
302
303impl dyn Io + Send {
304    fn __hyper_is<T: Io>(&self) -> bool {
305        let t = TypeId::of::<T>();
306        self.__hyper_type_id() == t
307    }
308    /// downcast a Box wrapped Type to a Box<T>
309    /// implemented by raw pointer cast.
310    fn __hyper_downcast<T: Io>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
311        if self.__hyper_is::<T>() {
312            // Taken from `std::error::Error::downcast()`.
313            // SAFETY:
314            // 1. `self.__hyper_is::<T>()` performs a runtime type check (typically via `TypeId`),
315            //    guaranteeing that the underlying concrete type is indeed `T`.
316            // 2. We use `Box::into_raw` to obtain a pointer to the trait object, which
317            //    has the same memory layout as the underlying concrete type `T` at the
318            //    location identified by the runtime check.
319            // 3. `Box::from_raw` is safe to call here because we are reconstructing the
320            //    box from the pointer that was originally created by `Box::into_raw`,
321            //    and the type `T` matches the original type of the allocated memory.
322            unsafe {
323                let raw: *mut dyn Io = Box::into_raw(self);
324                Ok(Box::from_raw(raw.cast()))
325            }
326        } else {
327            Err(self)
328        }
329    }
330}
331
332mod sealed {
333    use super::OnUpgrade;
334
335    pub trait CanUpgrade {
336        fn on_upgrade(self) -> OnUpgrade;
337    }
338
339    impl<B> CanUpgrade for http::Request<B> {
340        fn on_upgrade(mut self) -> OnUpgrade {
341            self.extensions_mut()
342                .remove::<OnUpgrade>()
343                .unwrap_or_else(OnUpgrade::none)
344        }
345    }
346
347    impl<B> CanUpgrade for &'_ mut http::Request<B> {
348        fn on_upgrade(self) -> OnUpgrade {
349            self.extensions_mut()
350                .remove::<OnUpgrade>()
351                .unwrap_or_else(OnUpgrade::none)
352        }
353    }
354
355    impl<B> CanUpgrade for http::Response<B> {
356        fn on_upgrade(mut self) -> OnUpgrade {
357            self.extensions_mut()
358                .remove::<OnUpgrade>()
359                .unwrap_or_else(OnUpgrade::none)
360        }
361    }
362
363    impl<B> CanUpgrade for &'_ mut http::Response<B> {
364        fn on_upgrade(self) -> OnUpgrade {
365            self.extensions_mut()
366                .remove::<OnUpgrade>()
367                .unwrap_or_else(OnUpgrade::none)
368        }
369    }
370}
371
372#[cfg(all(
373    any(feature = "client", feature = "server"),
374    any(feature = "http1", feature = "http2"),
375))]
376#[cfg(test)]
377mod tests {
378    use super::*;
379
380    #[test]
381    fn upgraded_downcast() {
382        let upgraded = Upgraded::new(Mock, Bytes::new());
383
384        let upgraded = upgraded
385            .downcast::<crate::common::io::Compat<std::io::Cursor<Vec<u8>>>>()
386            .unwrap_err();
387
388        upgraded.downcast::<Mock>().unwrap();
389    }
390
391    // TODO: replace with tokio_test::io when it can test write_buf
392    struct Mock;
393
394    impl Read for Mock {
395        fn poll_read(
396            self: Pin<&mut Self>,
397            _cx: &mut Context<'_>,
398            _buf: ReadBufCursor<'_>,
399        ) -> Poll<io::Result<()>> {
400            unreachable!("Mock::poll_read")
401        }
402    }
403
404    impl Write for Mock {
405        fn poll_write(
406            self: Pin<&mut Self>,
407            _: &mut Context<'_>,
408            buf: &[u8],
409        ) -> Poll<io::Result<usize>> {
410            Poll::Ready(Ok(buf.len()))
411        }
412
413        fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
414            unreachable!("Mock::poll_flush")
415        }
416
417        fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
418            unreachable!("Mock::poll_shutdown")
419        }
420    }
421}