use regex::Regex;
pub fn matches(globs: &[String], url: &str) -> bool {
globs.iter().any(|g| glob_to_regex(g).is_match(url))
}
fn glob_to_regex(glob: &str) -> Regex {
let mut pat = String::with_capacity(glob.len() + 4);
pat.push('^');
for ch in glob.chars() {
if ch == '*' {
pat.push_str(".*");
} else {
pat.push_str(®ex::escape(&ch.to_string()));
}
}
pat.push('$');
Regex::new(&pat).expect("glob_to_regex produces a valid regex")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_list_never_matches() {
assert!(!matches(&[], "https://example.com/"));
}
#[test]
fn bare_star_matches_everything() {
let globs = vec!["*".to_string()];
assert!(matches(&globs, "https://example.com/a/b"));
assert!(matches(&globs, "file:///etc/hosts"));
}
#[test]
fn subdomain_and_path_glob() {
let globs = vec!["https://*.example.com/*".to_string()];
assert!(matches(&globs, "https://docs.example.com/page"));
assert!(matches(&globs, "https://a.b.example.com/x/y"));
assert!(!matches(&globs, "https://example.com/page")); assert!(!matches(&globs, "https://evil.com/example.com")); }
#[test]
fn literal_dot_is_not_a_wildcard() {
let globs = vec!["https://example.com/*".to_string()];
assert!(matches(&globs, "https://example.com/x"));
assert!(!matches(&globs, "https://exampleXcom/x"));
}
#[test]
fn any_glob_in_list_matches() {
let globs = vec!["https://a.com/*".to_string(), "https://b.com/*".to_string()];
assert!(matches(&globs, "https://b.com/page"));
}
}