pub(crate) fn parse_header_list(value: &str) -> Vec<String> {
value
.split(',')
.map(|header| header.trim().to_ascii_lowercase())
.filter(|header| !header.is_empty())
.collect()
}
pub(crate) fn cors_value_matches(allowed: &[String], requested: &str) -> bool {
allowed.iter().any(|value| {
value == "*"
|| value.eq_ignore_ascii_case(requested)
|| cors_subdomain_wildcard_matches(value, requested)
})
}
pub(crate) fn cors_response_origin(allowed: &[String], requested: &str) -> Option<String> {
allowed.iter().find_map(|value| {
if value == "*" {
Some("*".to_string())
} else if value.eq_ignore_ascii_case(requested)
|| cors_subdomain_wildcard_matches(value, requested)
{
Some(requested.to_string())
} else {
None
}
})
}
fn cors_subdomain_wildcard_matches(pattern: &str, requested: &str) -> bool {
if pattern == "*" || pattern.matches('*').count() != 1 {
return false;
}
let Some((prefix, suffix)) = pattern.split_once('*') else {
return false;
};
if !requested.starts_with(prefix) || !requested.ends_with(suffix) {
return false;
}
let middle = &requested[prefix.len()..requested.len() - suffix.len()];
!middle.is_empty() && !middle.contains('/')
}