Skip to main content

wreq_proto/
upgrade.rs

1//! HTTP Upgrades
2//!
3//! This module deals with managing [HTTP Upgrades][mdn] in crate::core:. 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//! Sending an HTTP upgrade from the client involves setting
19//! either the appropriate method, if wanting to `CONNECT`, or headers such as
20//! `Upgrade` and `Connection`, on the `http::Request`. Once receiving the
21//! `http::Response` back, you must check for the specific information that the
22//! upgrade is agreed upon by the server (such as a `101` status code), and then
23//! get the `Future` from the `Response`.
24
25use std::{
26    error::Error as StdError,
27    fmt,
28    future::Future,
29    io,
30    pin::Pin,
31    sync::{Arc, Mutex},
32    task::{Context, Poll},
33};
34
35use bytes::Bytes;
36use tokio::{
37    io::{AsyncRead, AsyncWrite, ReadBuf},
38    sync::oneshot,
39};
40
41use self::rewind::Rewind;
42use super::{Error, Result};
43use crate::lock::LockResultExt;
44
45/// An upgraded HTTP connection.
46///
47/// This type holds a trait object internally of the original IO that
48/// was used to speak HTTP before the upgrade. It can be used directly
49/// as a [`AsyncRead`] or [`AsyncWrite`] for convenience.
50///
51/// Alternatively, if the exact type is known, this can be deconstructed
52/// into its parts.
53pub struct Upgraded {
54    io: Rewind<Box<dyn Io + Send>>,
55}
56
57/// A future for a possible HTTP upgrade.
58///
59/// If no upgrade was available, or it doesn't succeed, yields an `Error`.
60#[derive(Clone)]
61pub struct OnUpgrade {
62    rx: Option<Arc<Mutex<oneshot::Receiver<Result<Upgraded>>>>>,
63}
64
65/// Gets a pending HTTP upgrade from this message.
66///
67/// This can be called on the following types:
68///
69/// - `http::Request<B>`
70/// - `http::Response<B>`
71/// - `&mut http::Request<B>`
72/// - `&mut http::Response<B>`
73#[inline]
74pub fn on<T: sealed::CanUpgrade>(msg: T) -> OnUpgrade {
75    msg.on_upgrade()
76}
77
78pub(crate) struct Pending {
79    tx: oneshot::Sender<Result<Upgraded>>,
80}
81
82pub(crate) fn pending() -> (Pending, OnUpgrade) {
83    let (tx, rx) = oneshot::channel();
84    (
85        Pending { tx },
86        OnUpgrade {
87            rx: Some(Arc::new(Mutex::new(rx))),
88        },
89    )
90}
91
92// ===== impl Upgraded =====
93
94impl Upgraded {
95    #[inline]
96    pub(crate) fn new<T>(io: T, read_buf: Bytes) -> Self
97    where
98        T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
99    {
100        Upgraded {
101            io: Rewind::new_buffered(Box::new(io), read_buf),
102        }
103    }
104}
105
106impl AsyncRead for Upgraded {
107    #[inline]
108    fn poll_read(
109        mut self: Pin<&mut Self>,
110        cx: &mut Context<'_>,
111        buf: &mut ReadBuf<'_>,
112    ) -> Poll<io::Result<()>> {
113        Pin::new(&mut self.io).poll_read(cx, buf)
114    }
115}
116
117impl AsyncWrite for Upgraded {
118    #[inline]
119    fn poll_write(
120        mut self: Pin<&mut Self>,
121        cx: &mut Context<'_>,
122        buf: &[u8],
123    ) -> Poll<io::Result<usize>> {
124        Pin::new(&mut self.io).poll_write(cx, buf)
125    }
126
127    #[inline]
128    fn poll_write_vectored(
129        mut self: Pin<&mut Self>,
130        cx: &mut Context<'_>,
131        bufs: &[io::IoSlice<'_>],
132    ) -> Poll<io::Result<usize>> {
133        Pin::new(&mut self.io).poll_write_vectored(cx, bufs)
134    }
135
136    #[inline]
137    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
138        Pin::new(&mut self.io).poll_flush(cx)
139    }
140
141    #[inline]
142    fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
143        Pin::new(&mut self.io).poll_shutdown(cx)
144    }
145
146    #[inline]
147    fn is_write_vectored(&self) -> bool {
148        self.io.is_write_vectored()
149    }
150}
151
152impl fmt::Debug for Upgraded {
153    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154        f.debug_struct("Upgraded").finish()
155    }
156}
157
158// ===== impl OnUpgrade =====
159
160impl OnUpgrade {
161    #[inline]
162    pub(super) fn none() -> Self {
163        OnUpgrade { rx: None }
164    }
165
166    #[inline]
167    pub(super) fn is_none(&self) -> bool {
168        self.rx.is_none()
169    }
170}
171
172impl Future for OnUpgrade {
173    type Output = Result<Upgraded, Error>;
174
175    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
176        match self.rx {
177            Some(ref rx) => Pin::new(&mut *rx.lock().panic_if_poisoned())
178                .poll(cx)
179                .map(|res| match res {
180                    Ok(Ok(upgraded)) => Ok(upgraded),
181                    Ok(Err(err)) => Err(err),
182                    Err(_oneshot_canceled) => Err(Error::new_canceled().with(UpgradeExpected)),
183                }),
184            None => Poll::Ready(Err(Error::new_user_no_upgrade())),
185        }
186    }
187}
188
189// ===== impl Pending =====
190
191impl Pending {
192    #[inline]
193    pub(super) fn fulfill(self, upgraded: Upgraded) {
194        trace!("pending upgrade fulfill");
195        let _ = self.tx.send(Ok(upgraded));
196    }
197
198    /// Don't fulfill the pending Upgrade, but instead signal that
199    /// upgrades are handled manually.
200    #[inline]
201    pub(super) fn manual(self) {
202        trace!("pending upgrade handled manually");
203        let _ = self.tx.send(Err(Error::new_user_manual_upgrade()));
204    }
205}
206
207// ===== impl UpgradeExpected =====
208
209/// Error cause returned when an upgrade was expected but canceled
210/// for whatever reason.
211///
212/// This likely means the actual `Conn` future wasn't polled and upgraded.
213#[derive(Debug)]
214struct UpgradeExpected;
215
216impl fmt::Display for UpgradeExpected {
217    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218        f.write_str("upgrade expected but not completed")
219    }
220}
221
222impl StdError for UpgradeExpected {}
223
224// ===== impl Io =====
225
226trait Io: AsyncRead + AsyncWrite + Unpin + 'static {}
227
228impl<T: AsyncRead + AsyncWrite + Unpin + 'static> Io for T {}
229
230mod sealed {
231    use super::OnUpgrade;
232
233    pub trait CanUpgrade {
234        fn on_upgrade(self) -> OnUpgrade;
235    }
236
237    impl<B> CanUpgrade for http::Request<B> {
238        fn on_upgrade(mut self) -> OnUpgrade {
239            self.extensions_mut()
240                .remove::<OnUpgrade>()
241                .unwrap_or_else(OnUpgrade::none)
242        }
243    }
244
245    impl<B> CanUpgrade for &'_ mut http::Request<B> {
246        fn on_upgrade(self) -> OnUpgrade {
247            self.extensions_mut()
248                .remove::<OnUpgrade>()
249                .unwrap_or_else(OnUpgrade::none)
250        }
251    }
252
253    impl<B> CanUpgrade for http::Response<B> {
254        fn on_upgrade(mut self) -> OnUpgrade {
255            self.extensions_mut()
256                .remove::<OnUpgrade>()
257                .unwrap_or_else(OnUpgrade::none)
258        }
259    }
260
261    impl<B> CanUpgrade for &'_ mut http::Response<B> {
262        fn on_upgrade(self) -> OnUpgrade {
263            self.extensions_mut()
264                .remove::<OnUpgrade>()
265                .unwrap_or_else(OnUpgrade::none)
266        }
267    }
268}
269
270mod rewind {
271    use std::{
272        cmp, io,
273        pin::Pin,
274        task::{Context, Poll},
275    };
276
277    use bytes::{Buf, Bytes};
278    use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
279
280    /// Combine a buffer with an IO, rewinding reads to use the buffer.
281    #[derive(Debug)]
282    pub(crate) struct Rewind<T> {
283        pre: Option<Bytes>,
284        inner: T,
285    }
286
287    impl<T> Rewind<T> {
288        #[inline]
289        pub(crate) fn new_buffered(io: T, buf: Bytes) -> Self {
290            Rewind {
291                pre: Some(buf),
292                inner: io,
293            }
294        }
295
296        #[cfg(test)]
297        pub(crate) fn rewind(&mut self, bs: Bytes) {
298            debug_assert!(self.pre.is_none());
299            self.pre = Some(bs);
300        }
301    }
302
303    impl<T> AsyncRead for Rewind<T>
304    where
305        T: AsyncRead + Unpin,
306    {
307        fn poll_read(
308            mut self: Pin<&mut Self>,
309            cx: &mut Context<'_>,
310            buf: &mut ReadBuf<'_>,
311        ) -> Poll<io::Result<()>> {
312            if let Some(mut prefix) = self.pre.take() {
313                // If there are no remaining bytes, let the bytes get dropped.
314                if !prefix.is_empty() {
315                    let copy_len = cmp::min(prefix.len(), buf.remaining());
316                    // TODO: There should be a way to do following two lines cleaner...
317                    buf.put_slice(&prefix[..copy_len]);
318                    prefix.advance(copy_len);
319                    // Put back what's left
320                    if !prefix.is_empty() {
321                        self.pre = Some(prefix);
322                    }
323
324                    return Poll::Ready(Ok(()));
325                }
326            }
327            Pin::new(&mut self.inner).poll_read(cx, buf)
328        }
329    }
330
331    impl<T> AsyncWrite for Rewind<T>
332    where
333        T: AsyncWrite + Unpin,
334    {
335        #[inline]
336        fn poll_write(
337            mut self: Pin<&mut Self>,
338            cx: &mut Context<'_>,
339            buf: &[u8],
340        ) -> Poll<io::Result<usize>> {
341            Pin::new(&mut self.inner).poll_write(cx, buf)
342        }
343
344        #[inline]
345        fn poll_write_vectored(
346            mut self: Pin<&mut Self>,
347            cx: &mut Context<'_>,
348            bufs: &[io::IoSlice<'_>],
349        ) -> Poll<io::Result<usize>> {
350            Pin::new(&mut self.inner).poll_write_vectored(cx, bufs)
351        }
352
353        #[inline]
354        fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
355            Pin::new(&mut self.inner).poll_flush(cx)
356        }
357
358        #[inline]
359        fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
360            Pin::new(&mut self.inner).poll_shutdown(cx)
361        }
362
363        #[inline]
364        fn is_write_vectored(&self) -> bool {
365            self.inner.is_write_vectored()
366        }
367    }
368
369    #[cfg(test)]
370    mod tests {
371        use bytes::Bytes;
372        use tokio::io::AsyncReadExt;
373
374        use super::Rewind;
375
376        #[tokio::test]
377        async fn partial_rewind() {
378            let underlying = [104, 101, 108, 108, 111];
379
380            let mock = tokio_test::io::Builder::new().read(&underlying).build();
381
382            let mut stream = Rewind::new_buffered(mock, Bytes::new());
383
384            // Read off some bytes, ensure we filled o1
385            let mut buf = [0; 2];
386            stream.read_exact(&mut buf).await.expect("read1");
387
388            // Rewind the stream so that it is as if we never read in the first place.
389            stream.rewind(Bytes::copy_from_slice(&buf[..]));
390
391            let mut buf = [0; 5];
392            stream.read_exact(&mut buf).await.expect("read1");
393
394            // At this point we should have read everything that was in the MockStream
395            assert_eq!(&buf, &underlying);
396        }
397
398        #[tokio::test]
399        async fn full_rewind() {
400            let underlying = [104, 101, 108, 108, 111];
401
402            let mock = tokio_test::io::Builder::new().read(&underlying).build();
403
404            let mut stream = Rewind::new_buffered(mock, Bytes::new());
405
406            let mut buf = [0; 5];
407            stream.read_exact(&mut buf).await.expect("read1");
408
409            // Rewind the stream so that it is as if we never read in the first place.
410            stream.rewind(Bytes::copy_from_slice(&buf[..]));
411
412            let mut buf = [0; 5];
413            stream.read_exact(&mut buf).await.expect("read1");
414
415            assert_eq!(&buf, &underlying);
416        }
417    }
418}