Reject signed chunk sizes in the HTTP chunked decoder

Found while testing crates/fetch/src/http.rs:522

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
NetterSilver
2026-10-25 06:57:27 +01:00
co-authored by Claude Haiku 5.5
parent 31ec62cd03
commit d2e6222a22
2 changed files with 15 additions and 1 deletions
+2 -1
View File
@@ -519,7 +519,8 @@ impl Response {
if *left == 0 {
let line = self.conn.line(1024, limits)?;
let hex = line.split(';').next().unwrap_or_default().trim();
let size = u64::from_str_radix(hex, 16).map_err(|_| HttpError::Protocol(format!("bad chunk size `{hex}`")))?;
let size = if hex.bytes().all(|b| b.is_ascii_hexdigit()) { u64::from_str_radix(hex, 16).ok() } else { None }
.ok_or_else(|| HttpError::Protocol(format!("bad chunk size `{hex}`")))?;
if size == 0 {
// trailers, up to the empty line
let mut n = 0;
+13
View File
@@ -86,6 +86,9 @@ fn handle(mut s: TcpStream, hits: &AtomicUsize) {
b.extend_from_slice(&[7u8; 5000]);
send(&mut s, "200 OK", "", &b)
}
"signedchunk" => {
let _ = s.write_all(b"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\nConnection: close\r\n\r\n+5\r\nhello\r\n0\r\n\r\n");
}
"chunked" => {
let _ = s.write_all(b"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\nConnection: close\r\n\r\n");
for c in body.chunks(70_001) {
@@ -249,6 +252,16 @@ fn a_416_or_a_bad_complete_part_starts_over() {
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
fn signed_chunk_size_is_rejected() {
let srv = server();
let dir = tmp("signedchunk");
let f = FileSpec { name: "vocab.json", size: None, sha256: None, max: 1 << 20 };
let r = run(&[f], &[format!("{}/signedchunk", srv.base)], &dir, &AtomicBool::new(false)).0;
assert!(r.is_err(), "a chunk size of `+5` was accepted");
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
fn chunked_bodies_and_unpinned_files() {
let srv = server();