1use crate::{Request, Uri};
4use rama_core::{context::Extensions, Context};
5
6pub mod dep {
7 pub use regex;
10}
11
12use dep::regex::Regex;
13
14#[derive(Debug, Clone)]
15pub struct UriMatcher {
17 re: Regex,
18}
19
20impl UriMatcher {
21 pub fn new(re: impl AsRef<str>) -> Self {
30 let re = Regex::new(re.as_ref()).expect("valid regex pattern");
31 Self { re }
32 }
33
34 pub(crate) fn matches_uri(&self, uri: &Uri) -> bool {
35 self.re.is_match(uri.to_string().as_str())
36 }
37}
38
39impl From<Regex> for UriMatcher {
40 fn from(re: Regex) -> Self {
41 Self { re }
42 }
43}
44
45impl<State, Body> rama_core::matcher::Matcher<State, Request<Body>> for UriMatcher {
46 fn matches(
47 &self,
48 _ext: Option<&mut Extensions>,
49 _ctx: &Context<State>,
50 req: &Request<Body>,
51 ) -> bool {
52 self.matches_uri(req.uri())
53 }
54}
55
56#[cfg(test)]
57mod test {
58 use super::*;
59
60 #[test]
61 fn matchest_uri_match() {
62 let test_cases: Vec<(UriMatcher, &str)> = vec![
63 (
64 UriMatcher::new(r"www\.example\.com"),
65 "http://www.example.com",
66 ),
67 (
68 UriMatcher::new(r"(?i)www\.example\.com"),
69 "http://WwW.ExamplE.COM",
70 ),
71 (
72 UriMatcher::new(r"(?i)^[^?]+\.(jpeg|png|gif|css)(\?|\z)"),
73 "http://www.example.com/assets/style.css?foo=bar",
74 ),
75 (
76 UriMatcher::new(r"(?i)^[^?]+\.(jpeg|png|gif|css)(\?|\z)"),
77 "http://www.example.com/image.png",
78 ),
79 ];
80 for (matcher, uri) in test_cases.into_iter() {
81 assert!(
82 matcher.matches_uri(&(uri.parse().unwrap())),
83 "({:?}).matches_uri({})",
84 matcher,
85 uri
86 );
87 }
88 }
89
90 #[test]
91 fn matchest_uri_no_match() {
92 let test_cases = vec![
93 (UriMatcher::new("www.example.com"), "http://WwW.ExamplE.COM"),
94 (
95 UriMatcher::new(r"(?i)^[^?]+\.(jpeg|png|gif|css)(\?|\z)"),
96 "http://www.example.com/?style.css",
97 ),
98 ];
99 for (matcher, uri) in test_cases.into_iter() {
100 assert!(
101 !matcher.matches_uri(&(uri.parse().unwrap())),
102 "!({:?}).matches_uri({})",
103 matcher,
104 uri
105 );
106 }
107 }
108}