tower_request_guard/
headers.rs1use http::HeaderMap;
2
3pub fn find_missing_header(headers: &HeaderMap, required: &[String]) -> Option<String> {
7 for name in required {
8 if headers.get(name.as_str()).is_none() {
9 return Some(name.clone());
10 }
11 }
12 None
13}
14
15#[cfg(test)]
16mod tests {
17 use super::*;
18 use http::HeaderMap;
19
20 #[test]
21 fn all_headers_present() {
22 let mut headers = HeaderMap::new();
23 headers.insert("authorization", "Bearer token".parse().unwrap());
24 headers.insert("x-request-id", "abc-123".parse().unwrap());
25 let required = vec!["Authorization".to_string(), "X-Request-Id".to_string()];
26 assert_eq!(find_missing_header(&headers, &required), None);
27 }
28
29 #[test]
30 fn missing_header_detected() {
31 let headers = HeaderMap::new();
32 let required = vec!["Authorization".to_string()];
33 assert_eq!(
34 find_missing_header(&headers, &required),
35 Some("Authorization".to_string())
36 );
37 }
38
39 #[test]
40 fn case_insensitive_lookup() {
41 let mut headers = HeaderMap::new();
42 headers.insert("authorization", "Bearer token".parse().unwrap());
43 let required = vec!["Authorization".to_string()];
44 assert_eq!(find_missing_header(&headers, &required), None);
45 }
46
47 #[test]
48 fn returns_first_missing() {
49 let mut headers = HeaderMap::new();
50 headers.insert("x-request-id", "abc".parse().unwrap());
51 let required = vec![
52 "Authorization".to_string(),
53 "X-Request-Id".to_string(),
54 "X-Tenant-Id".to_string(),
55 ];
56 assert_eq!(
57 find_missing_header(&headers, &required),
58 Some("Authorization".to_string())
59 );
60 }
61
62 #[test]
63 fn empty_required_always_passes() {
64 let headers = HeaderMap::new();
65 let required: Vec<String> = vec![];
66 assert_eq!(find_missing_header(&headers, &required), None);
67 }
68}