feat(rustproxy): introduce a Rust-powered proxy engine and workspace with core crates for proxy functionality, ACME/TLS support, passthrough and HTTP proxies, metrics, nftables integration, routing/security, management IPC, tests, and README updates
This commit is contained in:
86
rust/crates/rustproxy-routing/src/matchers/domain.rs
Normal file
86
rust/crates/rustproxy-routing/src/matchers/domain.rs
Normal file
@@ -0,0 +1,86 @@
|
||||
/// 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"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user