featherbit/plugins/util/
headers.rs1use std::collections::HashMap;
10
11pub fn remove_ci(map: &mut HashMap<String, Vec<String>>, name: &str) -> bool {
16 let target = name.to_ascii_lowercase();
17 let matches: Vec<String> = map
18 .keys()
19 .filter(|k| k.eq_ignore_ascii_case(&target))
20 .cloned()
21 .collect();
22 let removed = !matches.is_empty();
23 for k in matches {
24 map.remove(&k);
25 }
26 removed
27}
28
29#[cfg(test)]
30mod tests {
31 use super::*;
32
33 fn map(pairs: &[(&str, &str)]) -> HashMap<String, Vec<String>> {
34 pairs
35 .iter()
36 .map(|(k, v)| (k.to_string(), vec![v.to_string()]))
37 .collect()
38 }
39
40 #[test]
41 fn test_removes_regardless_of_stored_case() {
42 let mut m = map(&[("X-Powered-By", "php"), ("content-type", "text/html")]);
43 assert!(remove_ci(&mut m, "x-powered-by"));
44 assert!(!m.contains_key("X-Powered-By"));
45 assert!(m.contains_key("content-type"));
46 }
47
48 #[test]
49 fn test_removes_regardless_of_query_case() {
50 let mut m = map(&[("x-trace", "1")]);
51 assert!(remove_ci(&mut m, "X-Trace"));
52 assert!(m.is_empty());
53 }
54
55 #[test]
56 fn test_reports_false_when_absent() {
57 let mut m = map(&[("a", "1")]);
58 assert!(!remove_ci(&mut m, "b"));
59 assert_eq!(m.len(), 1);
60 }
61}