Skip to main content

tuwunel_core/utils/
url.rs

1//! Hostname and URL matching utilities.
2//!
3//! These helpers provide reusable matching rules that the URL parser does not
4//! expose directly.
5
6/// Reports whether a hostname is equal to or beneath a domain name.
7///
8/// Matching is ASCII case-insensitive and accepts a domain with an optional
9/// leading dot. A suffix only matches at a DNS label boundary. A single dot
10/// matches only a hostname with a trailing dot.
11#[must_use]
12pub fn hostname_matches_domain(hostname: &str, domain: &str) -> bool {
13	if domain == "." {
14		return hostname.ends_with('.');
15	}
16
17	let domain = domain.strip_prefix('.').unwrap_or(domain);
18
19	if domain.is_empty() {
20		return false;
21	}
22
23	if hostname.eq_ignore_ascii_case(domain) {
24		return true;
25	}
26
27	let Some(separator) = hostname
28		.len()
29		.checked_sub(domain.len())
30		.and_then(|index| index.checked_sub(1))
31	else {
32		return false;
33	};
34
35	let Some(suffix_start) = separator.checked_add(1) else {
36		return false;
37	};
38
39	hostname.as_bytes().get(separator) == Some(&b'.')
40		&& hostname
41			.get(suffix_start..)
42			.is_some_and(|suffix| suffix.eq_ignore_ascii_case(domain))
43}