rama_http/layer/dns/dns_resolve/
username_parser.rs

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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use super::DnsResolveMode;
use rama_core::username::{UsernameLabelParser, UsernameLabelState};
use rama_core::{
    context::Extensions,
    error::{error, ErrorContext, OpaqueError},
};
use rama_utils::macros::str::eq_ignore_ascii_case;

#[derive(Debug, Clone, Default)]
#[non_exhaustive]
/// A parser which parses [`DnsResolveMode`]s from username labels
/// and adds it to the [`Context`]'s [`Extensions`].
///
/// [`Context`]: rama_core::Context
/// [`Extensions`]: rama_core::context::Extensions
pub struct DnsResolveModeUsernameParser {
    key_found: bool,
    mode: DnsResolveMode,
}

impl DnsResolveModeUsernameParser {
    /// Create a new [`DnsResolveModeUsernameParser`].
    pub fn new() -> Self {
        Self::default()
    }
}

impl UsernameLabelParser for DnsResolveModeUsernameParser {
    type Error = OpaqueError;

    fn parse_label(&mut self, label: &str) -> UsernameLabelState {
        if self.key_found {
            self.mode = match label
                .parse()
                .context("parse dns resolve mode username label")
            {
                Ok(mode) => mode,
                Err(err) => {
                    tracing::trace!(err = %err, "abort username label parsing: invalid parse label");
                    return UsernameLabelState::Abort;
                }
            };
            self.key_found = false;
            UsernameLabelState::Used
        } else if eq_ignore_ascii_case!("dns", label) {
            self.key_found = true;
            UsernameLabelState::Used
        } else {
            UsernameLabelState::Ignored
        }
    }

    fn build(self, ext: &mut Extensions) -> Result<(), Self::Error> {
        if self.key_found {
            return Err(error!("unused dns resolve mode username key: dns"));
        }
        ext.insert(self.mode);
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use rama_core::username::parse_username;

    #[test]
    fn test_username_dns_resolve_mod_config() {
        let test_cases = [
            ("john", String::from("john"), DnsResolveMode::default()),
            (
                "john-dns-eager",
                String::from("john"),
                DnsResolveMode::eager(),
            ),
            (
                "john-dns-lazy",
                String::from("john"),
                DnsResolveMode::lazy(),
            ),
            (
                "john-dns-eager-dns-lazy",
                String::from("john"),
                DnsResolveMode::lazy(),
            ),
            (
                "john-dns-lazy-dns-eager",
                String::from("john"),
                DnsResolveMode::eager(),
            ),
        ];

        for (username, expected_username, expected_mode) in test_cases.into_iter() {
            let mut ext = Extensions::default();

            let parser = DnsResolveModeUsernameParser::default();

            let username = parse_username(&mut ext, parser, username).unwrap();
            let mode = *ext.get::<DnsResolveMode>().unwrap();
            assert_eq!(
                username, expected_username,
                "username = '{}' ; expected_username = '{}'",
                username, expected_username
            );
            assert_eq!(
                mode, expected_mode,
                "username = '{}' ; expected_mode = '{}'",
                username, expected_mode
            );
        }
    }

    #[test]
    fn test_username_dns_resolve_mode_error() {
        for username in [
            "john-",
            "john-dns",
            "john-dns-eager-",
            "john-dns-eager-dns",
            "john-dns-foo",
        ] {
            let mut ext = Extensions::default();

            let parser = DnsResolveModeUsernameParser::default();

            assert!(
                parse_username(&mut ext, parser, username).is_err(),
                "username = {}",
                username
            );
        }
    }
}