pharos_corefile/
helpers.rs1use crate::normalize_key;
2
3pub fn normalize_domain(host: &str) -> Vec<String> {
5 normalize_key(host)
7 .unwrap_or_default()
8 .into_iter()
9 .map(|key| key.domain)
10 .collect()
11}
12
13pub fn origins_from_args_or_server_block(args: &[&str], server_block: &[&str]) -> Vec<String> {
15 if args.is_empty() {
16 server_block
17 .iter()
18 .map(|host| {
19 normalize_domain(host)
20 .into_iter()
21 .next()
22 .unwrap_or_else(|| (*host).to_owned())
23 })
24 .collect()
25 } else {
26 args.iter()
27 .flat_map(|host| normalize_domain(host))
28 .collect()
29 }
30}
31
32#[derive(Clone, Debug, Default, Eq, PartialEq)]
34pub struct Fallthrough {
35 pub domains: Vec<String>,
36}
37
38impl Fallthrough {
39 pub fn set_domains_from_args(&mut self, domains: &[&str]) {
41 self.domains = if domains.is_empty() {
42 vec![".".into()]
43 } else {
44 domains
45 .iter()
46 .flat_map(|domain| normalize_domain(domain))
47 .collect()
48 };
49 }
50
51 pub fn through(&self, name: &str) -> bool {
53 self.domains.iter().any(|domain| {
54 if domain == "." {
55 return true;
56 }
57 let Some(prefix) = name.len().checked_sub(domain.len()) else {
58 return false;
59 };
60 if !name.is_char_boundary(prefix) || !name[prefix..].eq_ignore_ascii_case(domain) {
62 return false;
63 }
64 if prefix == 0 {
65 return true;
66 }
67 let bytes = name.as_bytes();
68 if bytes[prefix - 1] != b'.' {
69 return false;
70 }
71 let escapes = bytes[..prefix - 1]
72 .iter()
73 .rev()
74 .take_while(|&&byte| byte == b'\\')
75 .count();
76 escapes % 2 == 0
77 })
78 }
79}