Skip to content

Commit 164d926

Browse files
authored
Introduce hyper_util::server::conn::auto::upgrade::downcast (#147)
This fixes <hyperium/hyper#3704>.
1 parent df55aba commit 164d926

File tree

4 files changed

+75
-3
lines changed

4 files changed

+75
-3
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ hyper = "1.4.0"
2222
futures-util = { version = "0.3.16", default-features = false }
2323
http = "1.0"
2424
http-body = "1.0.0"
25-
bytes = "1"
25+
bytes = "1.7.1"
2626
pin-project-lite = "0.2.4"
2727
futures-channel = { version = "0.3", optional = true }
2828
socket2 = { version = "0.5", optional = true, features = ["all"] }

src/common/rewind.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use std::{
1111
/// Combine a buffer with an IO, rewinding reads to use the buffer.
1212
#[derive(Debug)]
1313
pub(crate) struct Rewind<T> {
14-
pre: Option<Bytes>,
15-
inner: T,
14+
pub(crate) pre: Option<Bytes>,
15+
pub(crate) inner: T,
1616
}
1717

1818
impl<T> Rewind<T> {

src/server/conn/auto.rs renamed to src/server/conn/auto/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! Http1 or Http2 connection.
22
3+
pub mod upgrade;
4+
35
use futures_util::ready;
46
use hyper::service::HttpService;
57
use std::future::Future;
@@ -163,6 +165,10 @@ impl<E> Builder<E> {
163165
/// Bind a connection together with a [`Service`], with the ability to
164166
/// handle HTTP upgrades. This requires that the IO object implements
165167
/// `Send`.
168+
///
169+
/// Note that if you ever want to use [`hyper::upgrade::Upgraded::downcast`]
170+
/// with this crate, you'll need to use [`hyper_util::server::conn::auto::upgrade::downcast`]
171+
/// instead. See the documentation of the latter to understand why.
166172
pub fn serve_connection_with_upgrades<I, S, B>(
167173
&self,
168174
io: I,

src/server/conn/auto/upgrade.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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

Comments
 (0)