rama_http/matcher/
uri.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
//! provides a [`UriMatcher`] matcher for matching requests based on their URI.

use crate::{Request, Uri};
use rama_core::{context::Extensions, Context};

pub mod dep {
    //! dependencies for the `uri` matcher module

    pub use regex;
}

use dep::regex::Regex;

#[derive(Debug, Clone)]
/// Matcher the request's URI, using a substring or regex pattern.
pub struct UriMatcher {
    re: Regex,
}

impl UriMatcher {
    /// create a new Uri matcher using a regex pattern.
    ///
    /// See docs at <https://docs.rs/regex> for more information on regex patterns.
    /// (e.g. to use flags like (?i) for case-insensitive matching)
    ///
    /// # Panics
    ///
    /// Panics if the regex pattern is invalid.
    pub fn new(re: impl AsRef<str>) -> Self {
        let re = Regex::new(re.as_ref()).expect("valid regex pattern");
        Self { re }
    }

    pub(crate) fn matches_uri(&self, uri: &Uri) -> bool {
        self.re.is_match(uri.to_string().as_str())
    }
}

impl From<Regex> for UriMatcher {
    fn from(re: Regex) -> Self {
        Self { re }
    }
}

impl<State, Body> rama_core::matcher::Matcher<State, Request<Body>> for UriMatcher {
    fn matches(
        &self,
        _ext: Option<&mut Extensions>,
        _ctx: &Context<State>,
        req: &Request<Body>,
    ) -> bool {
        self.matches_uri(req.uri())
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn matchest_uri_match() {
        let test_cases: Vec<(UriMatcher, &str)> = vec![
            (
                UriMatcher::new(r"www\.example\.com"),
                "http://www.example.com",
            ),
            (
                UriMatcher::new(r"(?i)www\.example\.com"),
                "http://WwW.ExamplE.COM",
            ),
            (
                UriMatcher::new(r"(?i)^[^?]+\.(jpeg|png|gif|css)(\?|\z)"),
                "http://www.example.com/assets/style.css?foo=bar",
            ),
            (
                UriMatcher::new(r"(?i)^[^?]+\.(jpeg|png|gif|css)(\?|\z)"),
                "http://www.example.com/image.png",
            ),
        ];
        for (matcher, uri) in test_cases.into_iter() {
            assert!(
                matcher.matches_uri(&(uri.parse().unwrap())),
                "({:?}).matches_uri({})",
                matcher,
                uri
            );
        }
    }

    #[test]
    fn matchest_uri_no_match() {
        let test_cases = vec![
            (UriMatcher::new("www.example.com"), "http://WwW.ExamplE.COM"),
            (
                UriMatcher::new(r"(?i)^[^?]+\.(jpeg|png|gif|css)(\?|\z)"),
                "http://www.example.com/?style.css",
            ),
        ];
        for (matcher, uri) in test_cases.into_iter() {
            assert!(
                !matcher.matches_uri(&(uri.parse().unwrap())),
                "!({:?}).matches_uri({})",
                matcher,
                uri
            );
        }
    }
}