1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use super::Result;
use regex::Regex;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct DestinationRule {
pub identifier: String,
pub host: String,
}
impl DestinationRule {
const DNS_LABEL_MAX_LENGTH: u8 = 63;
const DNS_LABEL_PATTERN: &'static str = "^(?:[A-Za-z0-9][-A-Za-z0-9_\\.]*)?[A-Za-z0-9]$";
fn is_dns_label(value: &str) -> bool {
value.len() <= (DestinationRule::DNS_LABEL_MAX_LENGTH as usize)
&& Regex::new(DestinationRule::DNS_LABEL_PATTERN)
.unwrap()
.is_match(value)
}
pub fn verify(&self, identifierPattern: &Regex) -> Result<bool> {
let mut erroneous = false;
if !identifierPattern.is_match(&self.identifier) {
erroneous = true;
error!("Identifier \"{}\" is invalid.", &self.identifier);
}
if !DestinationRule::is_dns_label(&self.host[..]) {
erroneous = true;
error!("Host \"{}\" is not a valid DNS label.", &self.host);
}
if erroneous {
bail!("Fatal errors detected.")
} else {
Ok(true)
}
}
}
#[cfg(test)]
mod tests {
use super::DestinationRule;
use regex::Regex;
const MATCH_ALL_PATTERN: &'static str = ".*";
const MATCH_NONE_PATTERN: &'static str = ".^";
const HOST_VALID: &'static str = "hostname.local";
const HOST_INVALID: &'static str = ">:(";
const IDENTIFIER: &'static str = "IDENTIFIER";
fn withIdentifierAndHost(host: &str) -> DestinationRule {
let identifier = IDENTIFIER.into();
let host = host.into();
DestinationRule { identifier, host }
}
#[test]
fn verifies_if_all_fields_valid() {
assert!(withIdentifierAndHost(HOST_VALID)
.verify(&Regex::new(MATCH_ALL_PATTERN).unwrap())
.unwrap());
}
#[test]
fn verification_fails_if_identifier_invalid() {
withIdentifierAndHost(HOST_VALID)
.verify(&Regex::new(MATCH_NONE_PATTERN).unwrap())
.unwrap_err();
}
#[test]
fn verification_fails_if_host_invalid() {
withIdentifierAndHost(HOST_INVALID)
.verify(&Regex::new(MATCH_ALL_PATTERN).unwrap())
.unwrap_err();
}
#[test]
fn verification_fails_if_all_fields_invalid() {
withIdentifierAndHost(HOST_INVALID)
.verify(&Regex::new(MATCH_NONE_PATTERN).unwrap())
.unwrap_err();
}
}