Files
smartproxy/rust/crates/rustproxy-routing/src/matchers/domain.rs

87 lines
2.6 KiB
Rust

/// Match a domain against a pattern supporting wildcards.
///
/// Supported patterns:
/// - `*` matches any domain
/// - `*.example.com` matches any subdomain of example.com
/// - `example.com` exact match
/// - `**.example.com` matches any depth of subdomain
pub fn domain_matches(pattern: &str, domain: &str) -> bool {
let pattern = pattern.trim().to_lowercase();
let domain = domain.trim().to_lowercase();
if pattern == "*" {
return true;
}
if pattern == domain {
return true;
}
// Wildcard patterns
if pattern.starts_with("*.") {
let suffix = &pattern[2..]; // e.g., "example.com"
// Match exact parent or any single-level subdomain
if domain == suffix {
return true;
}
if domain.ends_with(&format!(".{}", suffix)) {
// Check it's a single level subdomain for `*.`
let prefix = &domain[..domain.len() - suffix.len() - 1];
return !prefix.contains('.');
}
return false;
}
if pattern.starts_with("**.") {
let suffix = &pattern[3..];
// Match exact parent or any depth of subdomain
return domain == suffix || domain.ends_with(&format!(".{}", suffix));
}
// Use glob-match for more complex patterns
glob_match::glob_match(&pattern, &domain)
}
/// Check if a domain matches any of the given patterns.
pub fn domain_matches_any(patterns: &[&str], domain: &str) -> bool {
patterns.iter().any(|p| domain_matches(p, domain))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_exact_match() {
assert!(domain_matches("example.com", "example.com"));
assert!(!domain_matches("example.com", "other.com"));
}
#[test]
fn test_wildcard_all() {
assert!(domain_matches("*", "anything.com"));
assert!(domain_matches("*", "sub.domain.example.com"));
}
#[test]
fn test_wildcard_subdomain() {
assert!(domain_matches("*.example.com", "www.example.com"));
assert!(domain_matches("*.example.com", "api.example.com"));
assert!(domain_matches("*.example.com", "example.com"));
assert!(!domain_matches("*.example.com", "deep.sub.example.com"));
}
#[test]
fn test_double_wildcard() {
assert!(domain_matches("**.example.com", "www.example.com"));
assert!(domain_matches("**.example.com", "deep.sub.example.com"));
assert!(domain_matches("**.example.com", "example.com"));
}
#[test]
fn test_case_insensitive() {
assert!(domain_matches("Example.COM", "example.com"));
assert!(domain_matches("*.EXAMPLE.com", "WWW.example.COM"));
}
}