we (web engine): Experimental web browser project to understand the limits of Claude
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix case-insensitive header matching in body strategy detection

Replace strip_prefix-based header matching (only matched exact case and
lowercase) with a proper case-insensitive helper that splits on the
first colon and compares the header name using eq_ignore_ascii_case.
Adds tests for all-caps header names (CONTENT-LENGTH, TRANSFER-ENCODING).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

authored by

Pierre Le Fevre
Claude Opus 4.6
and committed by tangled.org 8b86fdda d9195fac

+32 -10
+32 -10
crates/net/src/client.rs
··· 477 477 ReadUntilClose, 478 478 } 479 479 480 + /// Extract the value for a header name (case-insensitive match). 481 + fn header_value<'a>(line: &'a str, name: &str) -> Option<&'a str> { 482 + let colon = line.find(':')?; 483 + if line[..colon].eq_ignore_ascii_case(name) { 484 + Some(line[colon + 1..].trim()) 485 + } else { 486 + None 487 + } 488 + } 489 + 480 490 /// Determine how to read the body from headers. 481 491 fn determine_body_strategy(headers: &str, status_code: u16) -> BodyStrategy { 482 492 // 1xx, 204, 304 have no body ··· 486 496 487 497 // Check for Transfer-Encoding: chunked 488 498 for line in headers.split("\r\n").skip(1) { 489 - if let Some(val) = line 490 - .strip_prefix("Transfer-Encoding:") 491 - .or_else(|| line.strip_prefix("transfer-encoding:")) 492 - { 493 - if val.trim().eq_ignore_ascii_case("chunked") { 499 + if let Some(val) = header_value(line, "transfer-encoding") { 500 + if val.eq_ignore_ascii_case("chunked") { 494 501 return BodyStrategy::Chunked; 495 502 } 496 503 } ··· 498 505 499 506 // Check for Content-Length 500 507 for line in headers.split("\r\n").skip(1) { 501 - if let Some(val) = line 502 - .strip_prefix("Content-Length:") 503 - .or_else(|| line.strip_prefix("content-length:")) 504 - { 505 - if let Ok(len) = val.trim().parse::<usize>() { 508 + if let Some(val) = header_value(line, "content-length") { 509 + if let Ok(len) = val.parse::<usize>() { 506 510 return BodyStrategy::ContentLength(len); 507 511 } 508 512 } ··· 840 844 #[test] 841 845 fn strategy_chunked_uppercase_value() { 842 846 let headers = "HTTP/1.1 200 OK\r\nTransfer-Encoding: CHUNKED"; 847 + assert!(matches!( 848 + determine_body_strategy(headers, 200), 849 + BodyStrategy::Chunked 850 + )); 851 + } 852 + 853 + #[test] 854 + fn strategy_content_length_mixed_case() { 855 + let headers = "HTTP/1.1 200 OK\r\nCONTENT-LENGTH: 99"; 856 + match determine_body_strategy(headers, 200) { 857 + BodyStrategy::ContentLength(99) => {} 858 + _ => panic!("expected ContentLength(99)"), 859 + } 860 + } 861 + 862 + #[test] 863 + fn strategy_chunked_mixed_case_name() { 864 + let headers = "HTTP/1.1 200 OK\r\nTRANSFER-ENCODING: chunked"; 843 865 assert!(matches!( 844 866 determine_body_strategy(headers, 200), 845 867 BodyStrategy::Chunked