use super::super::*;
use std::collections::HashMap;
#[test]
fn test_header_crlf_injection_in_value() {
let req = Request::new(
Method::Get,
"/".to_string(),
vec![(
"X-Test".to_string(),
"value\r\nX-Injected: hacked".to_string(),
)],
None,
HashMap::new(),
);
let value = req.header("x-test").unwrap();
assert!(value.contains('\r') || value.contains('\n') || value == "value\r\nX-Injected: hacked");
}
#[test]
fn test_header_null_byte_in_value() {
let req = Request::new(
Method::Get,
"/".to_string(),
vec![("X-Test".to_string(), "before\0after".to_string())],
None,
HashMap::new(),
);
let value = req.header("x-test").unwrap();
assert!(value.contains('\0'));
}
#[test]
fn test_header_very_long_value() {
let long_value = "x".repeat(100_000);
let req = Request::new(
Method::Get,
"/".to_string(),
vec![("X-Long".to_string(), long_value)],
None,
HashMap::new(),
);
assert_eq!(req.header("x-long").unwrap().len(), 100_000);
}
#[test]
fn test_header_value_at_limit() {
let at_limit_value = "x".repeat(MAX_HEADER_VALUE_LEN);
let req = Request::new(
Method::Get,
"/".to_string(),
vec![("X-AtLimit".to_string(), at_limit_value)],
None,
HashMap::new(),
);
assert_eq!(req.header("x-atlimit").unwrap().len(), MAX_HEADER_VALUE_LEN);
}
#[test]
fn test_header_value_just_over_limit() {
let over_limit_value = "x".repeat(MAX_HEADER_VALUE_LEN + 1);
let req = Request::new(
Method::Get,
"/".to_string(),
vec![("X-OverLimit".to_string(), over_limit_value)],
None,
HashMap::new(),
);
assert_eq!(
req.header("x-overlimit").unwrap().len(),
MAX_HEADER_VALUE_LEN + 1
);
}
#[test]
fn test_total_headers_size_limit() {
let large_value = "x".repeat(1024);
let headers: Vec<(String, String)> = (0..1100)
.map(|i| (format!("X-Header-{i}"), large_value.clone()))
.collect();
let req = Request::new(Method::Get, "/".to_string(), headers, None, HashMap::new());
assert_eq!(req.header("x-header-0").unwrap().len(), 1024);
assert_eq!(req.header("x-header-1099").unwrap().len(), 1024);
}
#[test]
fn test_multiple_oversized_headers() {
let oversized_value = "x".repeat(MAX_HEADER_VALUE_LEN + 100);
let req = Request::new(
Method::Get,
"/".to_string(),
vec![
("X-Oversized-1".to_string(), oversized_value.clone()),
("X-Oversized-2".to_string(), oversized_value.clone()),
("X-Oversized-3".to_string(), oversized_value),
],
None,
HashMap::new(),
);
assert_eq!(
req.header("x-oversized-1").unwrap().len(),
MAX_HEADER_VALUE_LEN + 100
);
assert_eq!(
req.header("x-oversized-2").unwrap().len(),
MAX_HEADER_VALUE_LEN + 100
);
assert_eq!(
req.header("x-oversized-3").unwrap().len(),
MAX_HEADER_VALUE_LEN + 100
);
}
#[test]
fn test_header_many_headers() {
let headers: Vec<(String, String)> = (0..1000)
.map(|i| (format!("X-Header-{i}"), format!("value-{i}")))
.collect();
let req = Request::new(Method::Get, "/".to_string(), headers, None, HashMap::new());
assert_eq!(req.header("x-header-0"), Some("value-0"));
assert_eq!(req.header("x-header-999"), Some("value-999"));
}
#[test]
fn test_header_duplicate_with_different_values() {
let req = Request::new(
Method::Get,
"/".to_string(),
vec![
("Set-Cookie".to_string(), "session=abc".to_string()),
("Set-Cookie".to_string(), "csrf=xyz".to_string()),
("Set-Cookie".to_string(), "theme=dark".to_string()),
],
None,
HashMap::new(),
);
let cookies = req.header_all("set-cookie");
assert_eq!(cookies.len(), 3);
}
#[test]
fn test_header_empty_name() {
let req = Request::new(
Method::Get,
"/".to_string(),
vec![(String::new(), "value".to_string())],
None,
HashMap::new(),
);
assert_eq!(req.header(""), Some("value"));
}
#[test]
fn test_header_control_characters() {
let req = Request::new(
Method::Get,
"/".to_string(),
vec![
("X-Tab".to_string(), "before\tafter".to_string()),
("X-Bell".to_string(), "before\x07after".to_string()),
("X-Escape".to_string(), "before\x1Bafter".to_string()),
],
None,
HashMap::new(),
);
assert!(req.header("x-tab").unwrap().contains('\t'));
assert!(req.header("x-bell").unwrap().contains('\x07'));
assert!(req.header("x-escape").unwrap().contains('\x1B'));
}
#[test]
fn test_path_traversal_basic() {
let paths = [
"../../../etc/passwd",
"..\\..\\..\\windows\\system32\\config\\sam",
"/..../....//etc/passwd",
"....//....//etc/passwd",
];
for path in paths {
let req = Request::new(Method::Get, path.to_string(), vec![], None, HashMap::new());
assert_eq!(req.path(), path);
}
}
#[test]
fn test_path_traversal_null_byte_paths() {
let paths = [
"/files/image.png%00.jpg",
"/download%00/../../etc/passwd",
"/%00../secret",
];
for path in paths {
let req = Request::new(Method::Get, path.to_string(), vec![], None, HashMap::new());
assert_eq!(req.path(), path);
}
}
#[test]
fn test_path_with_query_injection() {
let req = Request::new(
Method::Get,
"/page?id=1&evil=../../etc/passwd".to_string(),
vec![],
None,
HashMap::new(),
);
assert_eq!(req.path_without_query(), "/page");
assert_eq!(req.query("id"), Some("1"));
assert_eq!(req.query("evil"), Some("../../etc/passwd"));
}
#[test]
fn test_path_param_traversal() {
let req = Request::new(
Method::Get,
"/files/../../../etc/passwd".to_string(),
vec![],
None,
[("filename".to_string(), "../../../etc/passwd".to_string())]
.into_iter()
.collect(),
);
assert_eq!(req.param("filename"), Some("../../../etc/passwd"));
}
#[test]
fn test_path_special_sequences() {
let special_paths = [
"/./././file", "/foo/bar/./baz/../qux", "//double//slashes//", "/\\/mixed\\slashes/", "/path/to/file;param", "/path#fragment", ];
for path in special_paths {
let req = Request::new(Method::Get, path.to_string(), vec![], None, HashMap::new());
assert_eq!(req.path(), path);
}
}
#[test]
fn test_path_very_long() {
let long_path = format!("/{}", "a".repeat(10_000));
let req = Request::new(Method::Get, long_path, vec![], None, HashMap::new());
assert_eq!(req.path().len(), 10_001);
}
#[test]
fn test_path_deeply_nested() {
let deep_path = format!("/{}", "dir/".repeat(100));
let req = Request::new(Method::Get, deep_path.clone(), vec![], None, HashMap::new());
assert_eq!(req.path(), deep_path);
}
#[test]
fn test_very_long_query_value() {
let long_value = "x".repeat(100_000);
let path = format!("/api?data={long_value}");
let req = Request::new(Method::Get, path, vec![], None, HashMap::new());
assert_eq!(req.query("data"), None);
}
#[test]
fn test_malformed_path_with_nulls() {
let req = Request::new(
Method::Get,
"/path\0with\0nulls".to_string(),
vec![],
None,
HashMap::new(),
);
assert!(req.path().contains('\0'));
}
#[test]
fn test_null_in_various_places() {
let req = Request::new(
Method::Post,
"/path\0end?key\0=val\0ue".to_string(),
vec![("header\0name".to_string(), "header\0value".to_string())],
Some(b"form\0data=val\0ue".to_vec()),
[("param\0key".to_string(), "param\0value".to_string())]
.into_iter()
.collect(),
);
assert!(req.path().contains('\0'));
assert!(req.header("header\0name").is_some());
assert!(req.param("param\0key").is_some());
}