99 lines
2.9 KiB
Rust
99 lines
2.9 KiB
Rust
use std::collections::HashMap;
|
|
use regex::Regex;
|
|
|
|
/// Match HTTP headers against a set of patterns.
|
|
///
|
|
/// Pattern values can be:
|
|
/// - Exact string: `"application/json"`
|
|
/// - Regex (surrounded by /): `"/^text\/.*/"`
|
|
pub fn headers_match(
|
|
patterns: &HashMap<String, String>,
|
|
headers: &HashMap<String, String>,
|
|
) -> bool {
|
|
for (key, pattern) in patterns {
|
|
let key_lower = key.to_lowercase();
|
|
|
|
// Find the header (case-insensitive)
|
|
let header_value = headers
|
|
.iter()
|
|
.find(|(k, _)| k.to_lowercase() == key_lower)
|
|
.map(|(_, v)| v.as_str());
|
|
|
|
let header_value = match header_value {
|
|
Some(v) => v,
|
|
None => return false, // Required header not present
|
|
};
|
|
|
|
// Check if pattern is a regex (surrounded by /)
|
|
if pattern.starts_with('/') && pattern.ends_with('/') && pattern.len() > 2 {
|
|
let regex_str = &pattern[1..pattern.len() - 1];
|
|
match Regex::new(regex_str) {
|
|
Ok(re) => {
|
|
if !re.is_match(header_value) {
|
|
return false;
|
|
}
|
|
}
|
|
Err(_) => {
|
|
// Invalid regex, fall back to exact match
|
|
if header_value != pattern {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// Exact match
|
|
if header_value != pattern {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
true
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_exact_header_match() {
|
|
let patterns: HashMap<String, String> = {
|
|
let mut m = HashMap::new();
|
|
m.insert("Content-Type".to_string(), "application/json".to_string());
|
|
m
|
|
};
|
|
let headers: HashMap<String, String> = {
|
|
let mut m = HashMap::new();
|
|
m.insert("content-type".to_string(), "application/json".to_string());
|
|
m
|
|
};
|
|
assert!(headers_match(&patterns, &headers));
|
|
}
|
|
|
|
#[test]
|
|
fn test_regex_header_match() {
|
|
let patterns: HashMap<String, String> = {
|
|
let mut m = HashMap::new();
|
|
m.insert("Content-Type".to_string(), "/^text\\/.*/".to_string());
|
|
m
|
|
};
|
|
let headers: HashMap<String, String> = {
|
|
let mut m = HashMap::new();
|
|
m.insert("content-type".to_string(), "text/html".to_string());
|
|
m
|
|
};
|
|
assert!(headers_match(&patterns, &headers));
|
|
}
|
|
|
|
#[test]
|
|
fn test_missing_header() {
|
|
let patterns: HashMap<String, String> = {
|
|
let mut m = HashMap::new();
|
|
m.insert("X-Custom".to_string(), "value".to_string());
|
|
m
|
|
};
|
|
let headers: HashMap<String, String> = HashMap::new();
|
|
assert!(!headers_match(&patterns, &headers));
|
|
}
|
|
}
|