taxy_api/
vhost.rs

1use crate::{error::Error, subject_name::SubjectName};
2use regex::Regex;
3use serde::{Deserialize, Serialize};
4use std::fmt;
5use std::str::FromStr;
6
7#[derive(Debug, Clone)]
8pub enum VirtualHost {
9    SubjectName(SubjectName),
10    Regex(Regex),
11}
12
13impl VirtualHost {
14    pub fn test(&self, name: &str) -> bool {
15        match self {
16            VirtualHost::SubjectName(n) => n.test(name),
17            VirtualHost::Regex(r) => r.is_match(name),
18        }
19    }
20}
21
22impl PartialEq for VirtualHost {
23    fn eq(&self, other: &Self) -> bool {
24        match (self, other) {
25            (VirtualHost::SubjectName(a), VirtualHost::SubjectName(b)) => a == b,
26            (VirtualHost::Regex(a), VirtualHost::Regex(b)) => a.as_str() == b.as_str(),
27            _ => false,
28        }
29    }
30}
31
32impl Eq for VirtualHost {}
33
34impl fmt::Display for VirtualHost {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        match self {
37            VirtualHost::SubjectName(name) => write!(f, "{}", name),
38            VirtualHost::Regex(r) => write!(f, "{}", r),
39        }
40    }
41}
42
43impl FromStr for VirtualHost {
44    type Err = Error;
45
46    fn from_str(s: &str) -> Result<Self, Self::Err> {
47        if let Ok(n) = SubjectName::from_str(s) {
48            Ok(VirtualHost::SubjectName(n))
49        } else if let Ok(r) = Regex::new(s) {
50            Ok(VirtualHost::Regex(r))
51        } else {
52            Err(Error::InvalidVirtualHost { host: s.into() })
53        }
54    }
55}
56
57impl Serialize for VirtualHost {
58    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
59    where
60        S: serde::Serializer,
61    {
62        serializer.serialize_str(&self.to_string())
63    }
64}
65
66impl<'de> Deserialize<'de> for VirtualHost {
67    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
68    where
69        D: serde::Deserializer<'de>,
70    {
71        let s = String::deserialize(deserializer)?;
72        Self::from_str(&s).map_err(serde::de::Error::custom)
73    }
74}
75
76#[cfg(test)]
77mod test {
78    #[test]
79    fn test_virtual_host() {
80        use super::VirtualHost;
81        use std::str::FromStr;
82
83        let host = VirtualHost::from_str("localhost").unwrap();
84        assert_eq!(host.to_string(), "localhost");
85        assert!(host.test("localhost"));
86        assert!(!host.test("example.com"));
87
88        let host = VirtualHost::from_str("^.*\\.example\\.com$").unwrap();
89        assert_eq!(host.to_string(), "^.*\\.example\\.com$");
90        assert!(!host.test("localhost"));
91        assert!(host.test("www.example.com"));
92
93        let host = VirtualHost::from_str("^([a-z]+\\.)+my\\.vow$").unwrap();
94        assert_eq!(host.to_string(), "^([a-z]+\\.)+my\\.vow$");
95        assert!(!host.test("localhost"));
96        assert!(host.test("sphinx.of.black.quartz.judge.my.vow"));
97    }
98}