hyper_util/server/conn/auto/upgrade.rs
1//! Upgrade utilities.
2
3use bytes::{Bytes, BytesMut};
4use hyper::{
5 rt::{Read, Write},
6 upgrade::Upgraded,
7};
8
9use 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.
20pub fn downcast<T>(upgraded: Upgraded) -> Result<Parts<T>, Upgraded>
21where
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]
54pub 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}