use wafrift_encoding::header::{
comma_join, duplicate_header, line_fold, multi_line_fold, tab_separator, trailing_space,
whitespace_pad,
};
const CRLF_INJECTION: &str = "x\r\nEvil-Header: pwn";
const NUL_INJECTION: &str = "x\0Evil";
fn assert_no_smuggling_chars(out: &str, label: &str) {
assert!(
!out.contains('\r'),
"{label} output must not contain CR — would smuggle a header. got: {out:?}"
);
assert!(
!out.contains('\n'),
"{label} output must not contain LF — would smuggle a header. got: {out:?}"
);
assert!(
!out.contains('\0'),
"{label} output must not contain NUL — many HTTP/1 stacks truncate at NUL. got: {out:?}"
);
}
#[test]
fn tab_separator_strips_crlf_in_value() {
assert_no_smuggling_chars(
&tab_separator("X-Custom", CRLF_INJECTION),
"tab_separator",
);
}
#[test]
fn whitespace_pad_strips_crlf_in_value() {
assert_no_smuggling_chars(
&whitespace_pad("X-Custom", CRLF_INJECTION),
"whitespace_pad",
);
}
#[test]
fn line_fold_does_not_double_fold_pre_folded_value() {
let out = line_fold("X-Custom", "before\r\nafter");
let crlf_count = out.matches("\r\n").count();
assert!(
crlf_count <= 1,
"line_fold must not double-fold a pre-folded value: {out:?}"
);
}
#[test]
fn multi_line_fold_strips_crlf_in_value() {
let out = multi_line_fold("X-Custom", "abc\r\ndef\r\nghi");
let crlf_count = out.matches("\r\n").count();
assert!(
crlf_count <= 2,
"multi_line_fold must not stack value CRLF on top of its own: {out:?}"
);
}
#[test]
fn duplicate_header_strips_crlf_in_both_values() {
let (b, r) = duplicate_header("X-Custom", CRLF_INJECTION, "benign\rvalue");
assert_no_smuggling_chars(&b, "duplicate_header.benign");
assert_no_smuggling_chars(&r, "duplicate_header.real");
}
#[test]
fn trailing_space_strips_crlf_in_value() {
assert_no_smuggling_chars(&trailing_space("X-Custom", CRLF_INJECTION), "trailing_space");
}
#[test]
fn comma_join_strips_crlf_in_both_values() {
assert_no_smuggling_chars(
&comma_join("X-Custom", CRLF_INJECTION, "ok"),
"comma_join.real",
);
assert_no_smuggling_chars(
&comma_join("X-Custom", "ok", CRLF_INJECTION),
"comma_join.benign",
);
}
#[test]
fn null_byte_in_value_is_stripped() {
assert_no_smuggling_chars(&tab_separator("X", NUL_INJECTION), "tab_separator NUL");
assert_no_smuggling_chars(&whitespace_pad("X", NUL_INJECTION), "whitespace_pad NUL");
}
#[test]
fn clean_value_unchanged() {
let out = tab_separator("X-Custom", "normal value with spaces");
assert_eq!(out, "X-Custom:\tnormal value with spaces");
}