|
| 1 | +//! Upgrade utilities. |
| 2 | +
|
| 3 | +use bytes::{Bytes, BytesMut}; |
| 4 | +use hyper::{ |
| 5 | + rt::{Read, Write}, |
| 6 | + upgrade::Upgraded, |
| 7 | +}; |
| 8 | + |
| 9 | +use crate::common::rewind::Rewind; |
| 10 | + |
| 11 | +/// Tries to downcast the internal trait object to the type passed. |
| 12 | +/// |
| 13 | +/// On success, returns the downcasted parts. On error, returns the Upgraded back. |
| 14 | +/// This is a kludge to work around the fact that the machinery provided by |
| 15 | +/// [`hyper_util::server::con::auto`] wraps the inner `T` with a private type |
| 16 | +/// that is not reachable from outside the crate. |
| 17 | +/// |
| 18 | +/// This kludge will be removed when this machinery is added back to the main |
| 19 | +/// `hyper` code. |
| 20 | +pub fn downcast<T>(upgraded: Upgraded) -> Result<Parts<T>, Upgraded> |
| 21 | +where |
| 22 | + T: Read + Write + Unpin + 'static, |
| 23 | +{ |
| 24 | + let hyper::upgrade::Parts { |
| 25 | + io: rewind, |
| 26 | + mut read_buf, |
| 27 | + .. |
| 28 | + } = upgraded.downcast::<Rewind<T>>()?; |
| 29 | + |
| 30 | + if let Some(pre) = rewind.pre { |
| 31 | + read_buf = if read_buf.is_empty() { |
| 32 | + pre |
| 33 | + } else { |
| 34 | + let mut buf = BytesMut::from(read_buf); |
| 35 | + |
| 36 | + buf.extend_from_slice(&pre); |
| 37 | + |
| 38 | + buf.freeze() |
| 39 | + }; |
| 40 | + } |
| 41 | + |
| 42 | + Ok(Parts { |
| 43 | + io: rewind.inner, |
| 44 | + read_buf, |
| 45 | + }) |
| 46 | +} |
| 47 | + |
| 48 | +/// The deconstructed parts of an [`Upgraded`] type. |
| 49 | +/// |
| 50 | +/// Includes the original IO type, and a read buffer of bytes that the |
| 51 | +/// HTTP state machine may have already read before completing an upgrade. |
| 52 | +#[derive(Debug)] |
| 53 | +#[non_exhaustive] |
| 54 | +pub struct Parts<T> { |
| 55 | + /// The original IO object used before the upgrade. |
| 56 | + pub io: T, |
| 57 | + /// A buffer of bytes that have been read but not processed as HTTP. |
| 58 | + /// |
| 59 | + /// For instance, if the `Connection` is used for an HTTP upgrade request, |
| 60 | + /// it is possible the server sent back the first bytes of the new protocol |
| 61 | + /// along with the response upgrade. |
| 62 | + /// |
| 63 | + /// You will want to check for any existing bytes if you plan to continue |
| 64 | + /// communicating on the IO object. |
| 65 | + pub read_buf: Bytes, |
| 66 | +} |
0 commit comments