Skip to content

Commit 9245e94

Browse files
committed
fix(header): fix panic when parsing header names larger than 64kb
1 parent 976a77a commit 9245e94

File tree

2 files changed

+31
-3
lines changed

2 files changed

+31
-3
lines changed

src/proto/h1/role.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ impl Http1Transaction for Server {
104104
Version::HTTP_10
105105
};
106106

107-
record_header_indices(bytes, &req.headers, &mut headers_indices);
107+
record_header_indices(bytes, &req.headers, &mut headers_indices)?;
108108
headers_len = req.headers.len();
109109
//(len, subject, version, headers_len)
110110
}
@@ -590,7 +590,7 @@ impl Http1Transaction for Client {
590590
} else {
591591
Version::HTTP_10
592592
};
593-
record_header_indices(bytes, &res.headers, &mut headers_indices);
593+
record_header_indices(bytes, &res.headers, &mut headers_indices)?;
594594
let headers_len = res.headers.len();
595595
(len, status, version, headers_len)
596596
},
@@ -918,7 +918,11 @@ struct HeaderIndices {
918918
value: (usize, usize),
919919
}
920920

921-
fn record_header_indices(bytes: &[u8], headers: &[httparse::Header], indices: &mut [HeaderIndices]) {
921+
fn record_header_indices(
922+
bytes: &[u8],
923+
headers: &[httparse::Header],
924+
indices: &mut [HeaderIndices]
925+
) -> Result<(), ::error::Parse> {
922926
let bytes_ptr = bytes.as_ptr() as usize;
923927

924928
// FIXME: This should be a single plain `for` loop.
@@ -945,6 +949,10 @@ fn record_header_indices(bytes: &[u8], headers: &[httparse::Header], indices: &m
945949
cfg(all(target_arch = "arm", target_feature = "v7", target_feature = "neon"))
946950
for (header, indices) in (headers.iter().zip(indices.iter_mut())) {
947951
{
952+
if header.name.len() >= (1 << 16) {
953+
debug!("header name larger than 64kb: {:?}", header.name);
954+
return Err(::error::Parse::TooLarge);
955+
}
948956
let name_start = header.name.as_ptr() as usize - bytes_ptr;
949957
let name_end = name_start + header.name.len();
950958
indices.name = (name_start, name_end);
@@ -956,6 +964,8 @@ fn record_header_indices(bytes: &[u8], headers: &[httparse::Header], indices: &m
956964
}
957965
}
958966
}
967+
968+
Ok(())
959969
}
960970

961971
// Write header names as title case. The header name is assumed to be ASCII,

tests/server.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,24 @@ fn returning_1xx_response_is_error() {
10241024
rt.block_on(fut).expect_err("1xx status code should error");
10251025
}
10261026

1027+
#[test]
1028+
fn header_name_too_long() {
1029+
let server = serve();
1030+
1031+
let mut req = connect(server.addr());
1032+
let mut write = Vec::with_capacity(1024 * 66);
1033+
write.extend_from_slice(b"GET / HTTP/1.1\r\n");
1034+
for _ in 0..(1024 * 65) {
1035+
write.push(b'x');
1036+
}
1037+
write.extend_from_slice(b": foo\r\n\r\n");
1038+
req.write_all(&write).unwrap();
1039+
1040+
let mut buf = [0; 1024];
1041+
let n = req.read(&mut buf).unwrap();
1042+
assert!(s(&buf[..n]).starts_with("HTTP/1.1 431 Request Header Fields Too Large\r\n"));
1043+
}
1044+
10271045
#[test]
10281046
fn upgrades() {
10291047
use tokio_io::io::{read_to_end, write_all};

0 commit comments

Comments
 (0)