pub fn is_ascii_ws(b: u8) -> bool {
b == b' ' || b == b'\t'
}
pub(super) fn trim_ws_range(bytes: &[u8], start: usize, end: usize) -> (usize, usize) {
let mut vs = start;
let mut ve = end;
while vs < ve && is_ascii_ws(bytes[vs]) {
vs += 1;
}
while ve > vs && is_ascii_ws(bytes[ve - 1]) {
ve -= 1;
}
(vs, ve)
}
pub fn header_lines(wire: &[u8]) -> impl Iterator<Item = (&[u8], &[u8])> {
wire.split(|&b| b == b'\n')
.map(|line| line.strip_suffix(b"\r").unwrap_or(line))
.take_while(|line| !line.is_empty())
.filter_map(|line| {
let pos = line.iter().position(|&b| b == b':')?;
let (ns, ne) = trim_ws_range(line, 0, pos);
let (vs, ve) = trim_ws_range(line, pos + 1, line.len());
Some((&line[ns..ne], &line[vs..ve]))
})
}
pub(super) fn is_forbidden_value_byte(b: u8) -> bool {
(b < 0x20 && b != b'\t') || b == 0x7f
}
pub(super) fn value_has_forbidden_byte(bytes: &[u8]) -> bool {
const ONES: u64 = 0x0101_0101_0101_0101;
const HIGH: u64 = 0x8080_8080_8080_8080;
let mut chunks = bytes.chunks_exact(8);
for chunk in &mut chunks {
let x = u64::from_le_bytes(chunk.try_into().unwrap());
let lt_ctl = x.wrapping_sub(ONES * 0x20) & !x & HIGH;
let del = {
let v = x ^ (ONES * 0x7f);
v.wrapping_sub(ONES) & !v & HIGH
};
if (lt_ctl | del) != 0 && chunk.iter().any(|&b| is_forbidden_value_byte(b)) {
return true;
}
}
chunks
.remainder()
.iter()
.any(|&b| is_forbidden_value_byte(b))
}
pub fn is_header_name_byte(b: u8) -> bool {
b.is_ascii_alphanumeric()
|| matches!(
b,
b'!' | b'#'
| b'$'
| b'%'
| b'&'
| b'\''
| b'*'
| b'+'
| b'-'
| b'.'
| b'^'
| b'_'
| b'`'
| b'|'
| b'~'
)
}