Skip to content

Commit cb7a6f3

Browse files
committed
only send trailer fields if TE: trailers request header is present
1 parent a7f2019 commit cb7a6f3

File tree

3 files changed

+56
-2
lines changed

3 files changed

+56
-2
lines changed

src/proto/h1/conn.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ where
7575
// We assume a modern world where the remote speaks HTTP/1.1.
7676
// If they tell us otherwise, we'll downgrade in `read_head`.
7777
version: Version::HTTP_11,
78+
allow_trailer_fields: false,
7879
},
7980
_marker: PhantomData,
8081
}
@@ -266,8 +267,12 @@ where
266267

267268
if let Some(Ok(te_value)) = msg.head.headers.get("te").map(|v| v.to_str()) {
268269
if te_value.eq_ignore_ascii_case("trailers") {
269-
wants = wants.add(Wants::TRAILERS);
270+
self.state.allow_trailer_fields = true;
271+
} else {
272+
self.state.allow_trailer_fields = false;
270273
}
274+
} else {
275+
self.state.allow_trailer_fields = false;
271276
}
272277

273278
Poll::Ready(Some(Ok((msg.head, msg.decode, wants))))
@@ -647,6 +652,11 @@ where
647652
}
648653

649654
pub(crate) fn write_trailers(&mut self, trailers: HeaderMap) {
655+
if self.state.allow_trailer_fields == false {
656+
debug!("trailers not allowed to be sent");
657+
return;
658+
}
659+
650660
debug_assert!(self.can_write_body() && self.can_buffer_body());
651661

652662
match self.state.writing {
@@ -869,6 +879,8 @@ struct State {
869879
upgrade: Option<crate::upgrade::Pending>,
870880
/// Either HTTP/1.0 or 1.1 connection
871881
version: Version,
882+
/// Flag to track if trailer fields are allowed to be sent
883+
allow_trailer_fields: bool,
872884
}
873885

874886
#[derive(Debug)]

src/proto/h1/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@ impl Wants {
112112
const EMPTY: Wants = Wants(0b00);
113113
const EXPECT: Wants = Wants(0b01);
114114
const UPGRADE: Wants = Wants(0b10);
115-
const TRAILERS: Wants = Wants(0b100);
116115

117116
#[must_use]
118117
fn add(self, other: Wants) -> Wants {

tests/server.rs

+43
Original file line numberDiff line numberDiff line change
@@ -2640,6 +2640,49 @@ fn http1_trailer_fields() {
26402640
assert_eq!(body, expected_body);
26412641
}
26422642

2643+
#[test]
2644+
fn http1_trailer_fields_not_allowed() {
2645+
let body = futures_util::stream::once(async move { Ok("hello".into()) });
2646+
let mut headers = HeaderMap::new();
2647+
headers.insert("chunky-trailer", "header data".parse().unwrap());
2648+
2649+
let server = serve();
2650+
server
2651+
.reply()
2652+
.header("transfer-encoding", "chunked")
2653+
.header("trailer", "chunky-trailer")
2654+
.body_stream_with_trailers(body, headers);
2655+
let mut req = connect(server.addr());
2656+
2657+
// TE: trailers is not specified in request headers
2658+
req.write_all(
2659+
b"\
2660+
GET / HTTP/1.1\r\n\
2661+
Host: example.domain\r\n\
2662+
Connection: keep-alive\r\n\
2663+
\r\n\
2664+
",
2665+
)
2666+
.expect("writing");
2667+
2668+
let last_chunk = b"\r\n0\r\n\r\n";
2669+
let res = read_until(&mut req, |buf| buf.ends_with(last_chunk)).expect("reading");
2670+
let sres = s(&res);
2671+
2672+
let expected_head =
2673+
"HTTP/1.1 200 OK\r\ntransfer-encoding: chunked\r\ntrailer: chunky-trailer\r\n";
2674+
assert_eq!(&sres[..expected_head.len()], expected_head);
2675+
2676+
// skip the date header
2677+
let date_fragment = "GMT\r\n\r\n";
2678+
let pos = sres.find(date_fragment).expect("find GMT");
2679+
let body = &sres[pos + date_fragment.len()..];
2680+
2681+
// no trailer fields should be sent because TE: trailers was not in request headers
2682+
let expected_body = "5\r\nhello\r\n0\r\n\r\n";
2683+
assert_eq!(body, expected_body);
2684+
}
2685+
26432686
// -------------------------------------------------
26442687
// the Server that is used to run all the tests with
26452688
// -------------------------------------------------

0 commit comments

Comments
 (0)