Skip to content

Commit 764b8a6

Browse files
GlenDCseanmonstarfinnbeartottoto
committed
sync rama-http-core code with hyperium/hyper v1.6.0
- ext: add ext::on_informational() callback extension (<hyperium/hyper#3818>) (<hyperium/hyper@8ce1fcf>, closes <hyperium/hyper#2565>) - server: add http1::Builder::ignore_invalid_headers(bool) option (<hyperium/hyper#3824>) (<hyperium/hyper@3817a79>) - server: - start http1 header read timeout when conn is idle (<hyperium/hyper#3828>) (<hyperium/hyper@10b09ff>, closes <hyperium/hyper#3780>, <hyperium/hyper#3781>) - change max_local_error_reset_streams function to &mut self (#3820) (e981a91e) - http2::Builder::max_local_error_reset_streams() now takes &mut self and returns &mut Self. In practice, this shouldn't break almost anyone. It was the wrong receiver and return types. (<hyperium/hyper@e981a91>) Co-authored-by: Sean McArthur <sean@seanmonstar.com> Co-authored-by: Finn Bear <finnbearlabs@gmail.com> Co-authored-by: tottoto <tottotodev@gmail.com>
1 parent c271fe4 commit 764b8a6

File tree

13 files changed

+234
-9
lines changed

13 files changed

+234
-9
lines changed

FORK.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ as a distant relative.
1010
### hyperium
1111

1212
- <https://github.com/hyperium/h2/tree/v0.4.8>
13-
- <https://github.com/hyperium/hyper/tree/v1.5.2>
13+
- <https://github.com/hyperium/hyper/tree/v1.6.0>
1414
- <https://github.com/hyperium/hyper-util/tree/v0.1.10>
1515

1616
### tower-rs

LICENSE-MIT

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2023 - Glen Henri J. De Cauwsemaecker
3+
Copyright (c) 2022-2025 Glen Henri J. De Cauwsemaecker
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1818
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1919
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2020
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21-
SOFTWARE.
21+
SOFTWARE.

rama-http-core/src/error.rs

+3
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,9 @@ impl Error {
167167

168168
/// Returns true if the error was caused by a timeout.
169169
pub fn is_timeout(&self) -> bool {
170+
if matches!(self.inner.kind, Kind::HeaderTimeout) {
171+
return true;
172+
}
170173
self.find_source::<TimedOut>().is_some()
171174
}
172175

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
use std::sync::Arc;
2+
3+
#[derive(Clone)]
4+
pub(crate) struct OnInformational(Arc<dyn OnInformationalCallback + Send + Sync>);
5+
6+
/// Add a callback for 1xx informational responses.
7+
///
8+
/// # Example
9+
///
10+
/// ```
11+
/// # let some_body = ();
12+
/// let mut req = rama_http_types::Request::new(some_body);
13+
///
14+
/// rama_http_core::ext::on_informational(&mut req, |res| {
15+
/// println!("informational: {:?}", res.status());
16+
/// });
17+
///
18+
/// // send request on a client connection...
19+
/// ```
20+
pub fn on_informational<B, F>(req: &mut rama_http_types::Request<B>, callback: F)
21+
where
22+
F: Fn(Response<'_>) + Send + Sync + 'static,
23+
{
24+
on_informational_raw(req, OnInformationalClosure(callback));
25+
}
26+
27+
pub(crate) fn on_informational_raw<B, C>(req: &mut rama_http_types::Request<B>, callback: C)
28+
where
29+
C: OnInformationalCallback + Send + Sync + 'static,
30+
{
31+
req.extensions_mut()
32+
.insert(OnInformational(Arc::new(callback)));
33+
}
34+
35+
// Sealed, not actually nameable bounds
36+
pub(crate) trait OnInformationalCallback {
37+
fn on_informational(&self, res: rama_http_types::Response<()>);
38+
}
39+
40+
impl OnInformational {
41+
pub(crate) fn call(&self, res: rama_http_types::Response<()>) {
42+
self.0.on_informational(res);
43+
}
44+
}
45+
46+
struct OnInformationalClosure<F>(F);
47+
48+
impl<F> OnInformationalCallback for OnInformationalClosure<F>
49+
where
50+
F: Fn(Response<'_>) + Send + Sync + 'static,
51+
{
52+
fn on_informational(&self, res: rama_http_types::Response<()>) {
53+
let res = Response(&res);
54+
(self.0)(res);
55+
}
56+
}
57+
58+
// A facade over rama_http_types::Response.
59+
//
60+
// It purposefully hides being able to move the response out of the closure,
61+
// while also not being able to expect it to be a reference `&Response`.
62+
// (Otherwise, a closure can be written as `|res: &_|`, and then be broken if
63+
// we make the closure take ownership.)
64+
//
65+
// With the type not being nameable, we could change from being a facade to
66+
// being either a real reference, or moving the rama_http_types::Response into the closure,
67+
// in a backwards-compatible change in the future.
68+
#[derive(Debug)]
69+
pub struct Response<'a>(&'a rama_http_types::Response<()>);
70+
71+
impl Response<'_> {
72+
#[inline]
73+
pub fn status(&self) -> rama_http_types::StatusCode {
74+
self.0.status()
75+
}
76+
77+
#[inline]
78+
pub fn version(&self) -> rama_http_types::Version {
79+
self.0.version()
80+
}
81+
82+
#[inline]
83+
pub fn headers(&self) -> &rama_http_types::HeaderMap {
84+
self.0.headers()
85+
}
86+
}

rama-http-core/src/ext/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ use std::fmt;
55
mod h1_reason_phrase;
66
pub use h1_reason_phrase::ReasonPhrase;
77

8+
mod informational;
9+
pub use informational::on_informational;
10+
pub(crate) use informational::OnInformational;
11+
// pub(crate) use informational::{on_informational_raw, OnInformationalCallback}; // ffi feature in hyperium/hyper
12+
813
/// Represents the `:protocol` pseudo-header used by
914
/// the [Extended CONNECT Protocol].
1015
///

rama-http-core/src/proto/h1/conn.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ where
5959
date_header: true,
6060
title_case_headers: false,
6161
h09_responses: false,
62+
on_informational: None,
6263
notify_read: false,
6364
reading: Reading::Init,
6465
writing: Writing::Init,
@@ -203,6 +204,7 @@ where
203204
h1_parser_config: self.state.h1_parser_config.clone(),
204205
h1_max_headers: self.state.h1_max_headers,
205206
h09_responses: self.state.h09_responses,
207+
on_informational: &mut self.state.on_informational,
206208
},
207209
) {
208210
Poll::Ready(Ok(msg)) => msg,
@@ -236,6 +238,9 @@ where
236238
// Prevent accepting HTTP/0.9 responses after the initial one, if any.
237239
self.state.h09_responses = false;
238240

241+
// Drop any OnInformational callbacks, we're done there!
242+
self.state.on_informational = None;
243+
239244
self.state.busy();
240245
self.state.keep_alive &= msg.keep_alive;
241246
self.state.version = msg.head.version;
@@ -579,7 +584,11 @@ where
579584
},
580585
buf,
581586
) {
582-
Ok(encoder) => Some(encoder),
587+
Ok(encoder) => {
588+
self.state.on_informational =
589+
head.extensions.remove::<crate::ext::OnInformational>();
590+
Some(encoder)
591+
}
583592
Err(err) => {
584593
self.state.error = Some(err);
585594
self.state.writing = Writing::Closed;
@@ -861,6 +870,10 @@ struct State {
861870
date_header: bool,
862871
title_case_headers: bool,
863872
h09_responses: bool,
873+
/// If set, called with each 1xx informational response received for
874+
/// the current request. MUST be unset after a non-1xx response is
875+
/// received.
876+
on_informational: Option<crate::ext::OnInformational>,
864877
/// Set to true when the Dispatcher should poll read operations
865878
/// again. See the `maybe_notify` method for more.
866879
notify_read: bool,
@@ -1039,6 +1052,13 @@ impl State {
10391052
if !T::should_read_first() {
10401053
self.notify_read = true;
10411054
}
1055+
1056+
if self.h1_header_read_timeout.is_some() {
1057+
// Next read will start and poll the header read timeout,
1058+
// so we can close the connection if another header isn't
1059+
// received in a timely manner.
1060+
self.notify_read = true;
1061+
}
10421062
}
10431063

10441064
fn is_idle(&self) -> bool {

rama-http-core/src/proto/h1/io.rs

+2
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ where
180180
h1_parser_config: parse_ctx.h1_parser_config.clone(),
181181
h1_max_headers: parse_ctx.h1_max_headers,
182182
h09_responses: parse_ctx.h09_responses,
183+
on_informational: parse_ctx.on_informational,
183184
},
184185
)? {
185186
Some(msg) => {
@@ -690,6 +691,7 @@ mod tests {
690691
h1_parser_config: Default::default(),
691692
h1_max_headers: None,
692693
h09_responses: false,
694+
on_informational: &mut None,
693695
};
694696
assert!(buffered
695697
.parse::<ClientTransaction>(cx, parse_ctx)

rama-http-core/src/proto/h1/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ pub(crate) struct ParseContext<'a> {
6868
h1_parser_config: ParserConfig,
6969
h1_max_headers: Option<usize>,
7070
h09_responses: bool,
71+
on_informational: &'a mut Option<crate::ext::OnInformational>,
7172
}
7273

7374
struct EncodeHead<'a, S> {

rama-http-core/src/proto/h1/role.rs

+22
Original file line numberDiff line numberDiff line change
@@ -956,6 +956,12 @@ impl Http1Transaction for Client {
956956
}));
957957
}
958958

959+
if head.subject.is_informational() {
960+
if let Some(callback) = ctx.on_informational {
961+
callback.call(head.into_response(()));
962+
}
963+
}
964+
959965
// Parsing a 1xx response could have consumed the buffer, check if
960966
// it is empty now...
961967
if buf.is_empty() {
@@ -1430,6 +1436,7 @@ mod tests {
14301436
h1_parser_config: Default::default(),
14311437
h1_max_headers: None,
14321438
h09_responses: false,
1439+
on_informational: &mut None,
14331440
},
14341441
)
14351442
.unwrap()
@@ -1451,6 +1458,7 @@ mod tests {
14511458
h1_parser_config: Default::default(),
14521459
h1_max_headers: None,
14531460
h09_responses: false,
1461+
on_informational: &mut None,
14541462
};
14551463
let msg = Client::parse(&mut raw, ctx).unwrap().unwrap();
14561464
assert_eq!(raw.len(), 0);
@@ -1468,6 +1476,7 @@ mod tests {
14681476
h1_parser_config: Default::default(),
14691477
h1_max_headers: None,
14701478
h09_responses: false,
1479+
on_informational: &mut None,
14711480
};
14721481
Server::parse(&mut raw, ctx).unwrap_err();
14731482
}
@@ -1482,6 +1491,7 @@ mod tests {
14821491
h1_parser_config: Default::default(),
14831492
h1_max_headers: None,
14841493
h09_responses: true,
1494+
on_informational: &mut None,
14851495
};
14861496
let msg = Client::parse(&mut raw, ctx).unwrap().unwrap();
14871497
assert_eq!(raw, H09_RESPONSE);
@@ -1498,6 +1508,7 @@ mod tests {
14981508
h1_parser_config: Default::default(),
14991509
h1_max_headers: None,
15001510
h09_responses: false,
1511+
on_informational: &mut None,
15011512
};
15021513
Client::parse(&mut raw, ctx).unwrap_err();
15031514
assert_eq!(raw, H09_RESPONSE);
@@ -1518,6 +1529,7 @@ mod tests {
15181529
h1_parser_config,
15191530
h1_max_headers: None,
15201531
h09_responses: false,
1532+
on_informational: &mut None,
15211533
};
15221534
let msg = Client::parse(&mut raw, ctx).unwrap().unwrap();
15231535
assert_eq!(raw.len(), 0);
@@ -1535,6 +1547,7 @@ mod tests {
15351547
h1_parser_config: Default::default(),
15361548
h1_max_headers: None,
15371549
h09_responses: false,
1550+
on_informational: &mut None,
15381551
};
15391552
Client::parse(&mut raw, ctx).unwrap_err();
15401553
}
@@ -1548,6 +1561,7 @@ mod tests {
15481561
h1_parser_config: Default::default(),
15491562
h1_max_headers: None,
15501563
h09_responses: false,
1564+
on_informational: &mut None,
15511565
};
15521566
let parsed_message = Server::parse(&mut raw, ctx).unwrap().unwrap();
15531567
let mut orig_headers = parsed_message
@@ -1572,6 +1586,7 @@ mod tests {
15721586
h1_parser_config: Default::default(),
15731587
h1_max_headers: None,
15741588
h09_responses: false,
1589+
on_informational: &mut None,
15751590
},
15761591
)
15771592
.expect("parse ok")
@@ -1587,6 +1602,7 @@ mod tests {
15871602
h1_parser_config: Default::default(),
15881603
h1_max_headers: None,
15891604
h09_responses: false,
1605+
on_informational: &mut None,
15901606
},
15911607
)
15921608
.expect_err(comment)
@@ -1811,6 +1827,7 @@ mod tests {
18111827
h1_parser_config: Default::default(),
18121828
h1_max_headers: None,
18131829
h09_responses: false,
1830+
on_informational: &mut None,
18141831
}
18151832
)
18161833
.expect("parse ok")
@@ -1826,6 +1843,7 @@ mod tests {
18261843
h1_parser_config: Default::default(),
18271844
h1_max_headers: None,
18281845
h09_responses: false,
1846+
on_informational: &mut None,
18291847
},
18301848
)
18311849
.expect("parse ok")
@@ -1841,6 +1859,7 @@ mod tests {
18411859
h1_parser_config: Default::default(),
18421860
h1_max_headers: None,
18431861
h09_responses: false,
1862+
on_informational: &mut None,
18441863
},
18451864
)
18461865
.expect_err("parse should err")
@@ -2433,6 +2452,7 @@ mod tests {
24332452
h1_parser_config: Default::default(),
24342453
h1_max_headers: None,
24352454
h09_responses: false,
2455+
on_informational: &mut None,
24362456
},
24372457
)
24382458
.expect("parse ok")
@@ -2470,6 +2490,7 @@ mod tests {
24702490
h1_parser_config: Default::default(),
24712491
h1_max_headers: max_headers,
24722492
h09_responses: false,
2493+
on_informational: &mut None,
24732494
},
24742495
);
24752496
if should_success {
@@ -2488,6 +2509,7 @@ mod tests {
24882509
h1_parser_config: Default::default(),
24892510
h1_max_headers: max_headers,
24902511
h09_responses: false,
2512+
on_informational: &mut None,
24912513
},
24922514
);
24932515
if should_success {

rama-http-core/src/server/conn/http2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ impl Builder {
121121
/// This is not advised, as it can potentially expose servers to DOS vulnerabilities.
122122
///
123123
/// See <https://rustsec.org/advisories/RUSTSEC-2024-0003.html> for more information.
124-
pub fn max_local_error_reset_streams(mut self, max: impl Into<Option<usize>>) -> Self {
124+
pub fn max_local_error_reset_streams(&mut self, max: impl Into<Option<usize>>) -> &mut Self {
125125
self.h2_builder.max_local_error_reset_streams = max.into();
126126
self
127127
}

0 commit comments

Comments
 (0)