diff --git a/crates/net/src/client.rs b/crates/net/src/client.rs index 90f6f27..11ecae9 100644 --- a/crates/net/src/client.rs +++ b/crates/net/src/client.rs @@ -477,6 +477,16 @@ enum BodyStrategy { ReadUntilClose, } +/// Extract the value for a header name (case-insensitive match). +fn header_value<'a>(line: &'a str, name: &str) -> Option<&'a str> { + let colon = line.find(':')?; + if line[..colon].eq_ignore_ascii_case(name) { + Some(line[colon + 1..].trim()) + } else { + None + } +} + /// Determine how to read the body from headers. fn determine_body_strategy(headers: &str, status_code: u16) -> BodyStrategy { // 1xx, 204, 304 have no body @@ -486,11 +496,8 @@ fn determine_body_strategy(headers: &str, status_code: u16) -> BodyStrategy { // Check for Transfer-Encoding: chunked for line in headers.split("\r\n").skip(1) { - if let Some(val) = line - .strip_prefix("Transfer-Encoding:") - .or_else(|| line.strip_prefix("transfer-encoding:")) - { - if val.trim().eq_ignore_ascii_case("chunked") { + if let Some(val) = header_value(line, "transfer-encoding") { + if val.eq_ignore_ascii_case("chunked") { return BodyStrategy::Chunked; } } @@ -498,11 +505,8 @@ fn determine_body_strategy(headers: &str, status_code: u16) -> BodyStrategy { // Check for Content-Length for line in headers.split("\r\n").skip(1) { - if let Some(val) = line - .strip_prefix("Content-Length:") - .or_else(|| line.strip_prefix("content-length:")) - { - if let Ok(len) = val.trim().parse::() { + if let Some(val) = header_value(line, "content-length") { + if let Ok(len) = val.parse::() { return BodyStrategy::ContentLength(len); } } @@ -846,6 +850,24 @@ mod tests { )); } + #[test] + fn strategy_content_length_mixed_case() { + let headers = "HTTP/1.1 200 OK\r\nCONTENT-LENGTH: 99"; + match determine_body_strategy(headers, 200) { + BodyStrategy::ContentLength(99) => {} + _ => panic!("expected ContentLength(99)"), + } + } + + #[test] + fn strategy_chunked_mixed_case_name() { + let headers = "HTTP/1.1 200 OK\r\nTRANSFER-ENCODING: chunked"; + assert!(matches!( + determine_body_strategy(headers, 200), + BodyStrategy::Chunked + )); + } + // -- URL scheme handling -- #[test]