use std::collections::HashSet;
use url::Url;
pub struct HostValidator {
domains: HashSet<String>,
include_subdomains: bool,
}
impl HostValidator {
pub fn new(domains: &[String], include_subdomains: bool) -> Self {
let normalized_domains: HashSet<String> = domains
.iter()
.map(|domain| domain.trim().to_lowercase())
.collect();
HostValidator {
domains: normalized_domains,
include_subdomains,
}
}
pub fn is_valid_host(&self, url_str: &str) -> bool {
if let Ok(url) = Url::parse(url_str) {
if let Some(host) = url.host_str() {
let normalized_host = host.to_lowercase();
if self.domains.contains(&normalized_host) {
return true;
}
if self.include_subdomains {
for domain in &self.domains {
if normalized_host.ends_with(&format!(".{domain}")) {
return true;
}
}
}
}
}
false
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_host_validation() {
let domains = vec!["example.com".to_string(), "test.org".to_string()];
let validator = HostValidator::new(&domains, false);
assert!(validator.is_valid_host("https://example.com/path"));
assert!(validator.is_valid_host("http://example.com"));
assert!(validator.is_valid_host("https://test.org/page?query=value"));
assert!(!validator.is_valid_host("https://example.com.")); assert!(!validator.is_valid_host("https://.example.com")); assert!(!validator.is_valid_host("https://-example.com")); assert!(!validator.is_valid_host("https://example-.com"));
assert!(!validator.is_valid_host("file:///path/to/file"));
assert!(!validator.is_valid_host("mailto:user@example.com"));
assert!(!validator.is_valid_host("data:text/plain,Hello%20World"));
assert!(!validator.is_valid_host("https://"));
assert!(!validator.is_valid_host("http://"));
assert!(!validator.is_valid_host("not-a-url"));
assert!(!validator.is_valid_host("https://sub.example.com/path"));
}
#[test]
fn test_host_validation_with_subdomains() {
let domains = vec!["example.com".to_string(), "test.org".to_string()];
let validator = HostValidator::new(&domains, true);
assert!(validator.is_valid_host("https://example.com/path"));
assert!(validator.is_valid_host("http://example.com"));
assert!(validator.is_valid_host("https://test.org/page?query=value"));
assert!(validator.is_valid_host("https://sub.example.com/path"));
assert!(validator.is_valid_host("https://deep.sub.example.com/path"));
assert!(validator.is_valid_host("https://api.test.org/v1/endpoint"));
assert!(!validator.is_valid_host("https://example.net/path"));
assert!(!validator.is_valid_host("https://test.com/path"));
}
}