Skip to main content

ntex_router/
resource.rs

1#![allow(clippy::needless_pass_by_value)]
2use std::collections::HashMap;
3use std::hash::{Hash, Hasher};
4
5use regex::{Regex, escape};
6
7use super::IntoPattern;
8
9#[derive(Clone, Debug)]
10pub(super) struct Segments {
11    pub(super) tp: Vec<Segment>,
12    pub(super) slesh: bool,
13}
14
15/// `ResourceDef` describes an entry in resources table
16///
17/// Resource definition can contain only 16 dynamic segments
18#[derive(Clone, Debug)]
19pub struct ResourceDef {
20    id: u16,
21    pub(super) tp: Vec<Segments>, // set of matching paths
22    name: String,
23    pattern: String,
24    elements: Vec<PathElement>,
25    pub(super) prefix: bool,
26}
27
28#[derive(Debug, Clone, PartialEq)]
29enum PathElement {
30    Str(String),
31    Var(String),
32}
33
34impl PathElement {
35    fn is_str(&self) -> bool {
36        matches!(self, PathElement::Str(_))
37    }
38
39    fn into_str(self) -> String {
40        if let PathElement::Str(s) = self {
41            s
42        } else {
43            panic!()
44        }
45    }
46
47    fn as_str(&self) -> &str {
48        match self {
49            PathElement::Str(s) | PathElement::Var(s) => s.as_str(),
50        }
51    }
52}
53
54#[derive(Clone, Debug)]
55pub(crate) enum Segment {
56    Static(String),
57    Dynamic {
58        pattern: Regex,
59        names: Vec<&'static str>,
60        tail: bool,
61    },
62}
63
64impl Eq for Segment {}
65
66impl PartialEq for Segment {
67    fn eq(&self, other: &Self) -> bool {
68        match self {
69            Segment::Static(p1) => match other {
70                Segment::Static(p2) => p1 == p2,
71                Segment::Dynamic { .. } => false,
72            },
73            Segment::Dynamic {
74                pattern: p1,
75                tail: t1,
76                ..
77            } => match other {
78                Segment::Static { .. } => false,
79                Segment::Dynamic {
80                    pattern: p2,
81                    tail: t2,
82                    ..
83                } => p1.as_str() == p2.as_str() && t1 == t2,
84            },
85        }
86    }
87}
88
89impl ResourceDef {
90    /// Parse path pattern and create new `ResourceDef` instance.
91    ///
92    /// Path segments are separatted by `/`. Pattern must start
93    /// with segment separator. Static segments could be
94    /// case insensitive.
95    ///
96    /// Panics if path pattern is malformed.
97    pub fn new<T: IntoPattern>(path: T) -> Self {
98        let set = path.patterns();
99        let mut p = String::new();
100        let mut tp = Vec::new();
101        let mut elements = Vec::new();
102
103        for path in set {
104            p.clone_from(&path);
105            let (pelems, elems) = ResourceDef::parse(&path);
106            tp.push(pelems);
107            elements = elems;
108        }
109
110        ResourceDef {
111            tp,
112            elements,
113            id: 0,
114            name: String::new(),
115            pattern: p,
116            prefix: false,
117        }
118    }
119
120    /// Parse path pattern and create new `ResourceDef` instance.
121    ///
122    /// Use `prefix` type instead of `static`.
123    ///
124    /// Panics if path regex pattern is malformed.
125    pub fn prefix<T: IntoPattern>(path: T) -> Self {
126        ResourceDef::with_prefix(path)
127    }
128
129    /// Parse path pattern and create new `ResourceDef` instance.
130    /// Inserts `/` to the start of the pattern.
131    ///
132    /// Panics if path regex pattern is malformed.
133    pub fn root_prefix<T: IntoPattern>(path: T) -> Self {
134        let mut patterns = path.patterns();
135        for path in &mut patterns {
136            let p = insert_slash(path.as_str());
137            *path = p;
138        }
139
140        ResourceDef::with_prefix(patterns)
141    }
142
143    /// Resource id
144    pub fn id(&self) -> u16 {
145        self.id
146    }
147
148    /// Set resource id
149    pub fn set_id(&mut self, id: u16) {
150        self.id = id;
151    }
152
153    /// Parse path pattern and create new `Pattern` instance with custom prefix
154    fn with_prefix<T: IntoPattern>(path: T) -> Self {
155        let patterns = path.patterns();
156
157        let mut p = String::new();
158        let mut tp = Vec::new();
159        let mut elements = Vec::new();
160
161        for path in patterns {
162            p.clone_from(&path);
163            let (pelems, elems) = ResourceDef::parse(&path);
164            tp.push(pelems);
165            elements = elems;
166        }
167
168        ResourceDef {
169            tp,
170            elements,
171            id: 0,
172            name: String::new(),
173            pattern: p,
174            prefix: true,
175        }
176    }
177
178    /// Resource pattern name
179    pub fn name(&self) -> &str {
180        &self.name
181    }
182
183    /// Mutable reference to a name of a resource definition.
184    pub fn name_mut(&mut self) -> &mut String {
185        &mut self.name
186    }
187
188    /// Path pattern of the resource
189    pub fn pattern(&self) -> &str {
190        &self.pattern
191    }
192
193    /// Build resource path from elements. Returns `true` on success.
194    pub fn resource_path<U, I>(&self, path: &mut String, elements: &mut U) -> bool
195    where
196        U: Iterator<Item = I>,
197        I: AsRef<str>,
198    {
199        for el in &self.elements {
200            match *el {
201                PathElement::Str(ref s) => path.push_str(s),
202                PathElement::Var(_) => {
203                    if let Some(val) = elements.next() {
204                        path.push_str(val.as_ref());
205                    } else {
206                        return false;
207                    }
208                }
209            }
210        }
211        true
212    }
213
214    /// Build resource path from elements. Returns `true` on success.
215    pub fn resource_path_named<K, V, S>(
216        &self,
217        path: &mut String,
218        elements: &HashMap<K, V, S>,
219    ) -> bool
220    where
221        K: std::borrow::Borrow<str> + Eq + Hash,
222        V: AsRef<str>,
223        S: std::hash::BuildHasher,
224    {
225        for el in &self.elements {
226            match *el {
227                PathElement::Str(ref s) => path.push_str(s),
228                PathElement::Var(ref name) => {
229                    if let Some(val) = elements.get(name) {
230                        path.push_str(val.as_ref());
231                    } else {
232                        return false;
233                    }
234                }
235            }
236        }
237        true
238    }
239
240    fn parse_segment<'a>(
241        pattern: &'a str,
242        elems: &mut Vec<PathElement>,
243    ) -> (String, &'a str, bool) {
244        const DEFAULT_PATTERN: &str = ".+";
245        const DEFAULT_PATTERN_TAIL: &str = ".*";
246
247        let mut re = "^".to_string();
248        let mut end = None;
249        let mut tail = false;
250        let mut rem = pattern;
251        let start = usize::from(pattern.starts_with('/'));
252        let mut pattern = &pattern[start..];
253        elems.push(PathElement::Str('/'.to_string()));
254
255        while let Some(start_idx) = pattern.find('{') {
256            if let Some(end) = end
257                && start_idx > end
258            {
259                break;
260            }
261            let p = pattern.split_at(start_idx);
262            pattern = p.1;
263            re.push_str(&escape(p.0));
264            elems.push(PathElement::Str(p.0.to_string()));
265
266            // find closing }
267            let mut params_nesting = 0usize;
268            let close_idx = pattern
269                .find(|c| match c {
270                    '{' => {
271                        params_nesting += 1;
272                        false
273                    }
274                    '}' => {
275                        params_nesting -= 1;
276                        params_nesting == 0
277                    }
278                    _ => false,
279                })
280                .expect("malformed dynamic segment");
281
282            let p = pattern.split_at(close_idx + 1);
283            rem = p.1;
284            let param = &p.0[1..p.0.len() - 1]; // Remove outer brackets
285            tail = rem == "*"; // tail match (should match regardless of segments)
286
287            let (name, pat) = match param.find(':') {
288                Some(idx) => {
289                    assert!(!tail, "Custom regex is not supported for remainder match");
290                    let (name, pattern) = param.split_at(idx);
291                    (name, &pattern[1..])
292                }
293                None => (
294                    param,
295                    if tail {
296                        rem = &rem[1..];
297                        DEFAULT_PATTERN_TAIL
298                    } else {
299                        DEFAULT_PATTERN
300                    },
301                ),
302            };
303
304            re = format!(r"{}(?P<{}>{})", re, escape(name), pat);
305
306            elems.push(PathElement::Var(name.to_string()));
307
308            if let Some(idx) = rem.find(['{', '/']) {
309                end = Some(idx);
310                pattern = rem;
311            } else {
312                re += rem;
313                rem = "";
314                break;
315            }
316        }
317
318        // find end of segment
319        if let Some(idx) = rem.find('/') {
320            re.push_str(&escape(&rem[..idx]));
321            rem = &rem[idx..];
322        } else {
323            re.push_str(&escape(rem));
324            rem = "";
325        }
326        re.push('$');
327
328        (re, rem, tail)
329    }
330
331    fn parse(mut pattern: &str) -> (Segments, Vec<PathElement>) {
332        let mut elems = Vec::new();
333        let mut pelems = Vec::new();
334
335        if pattern.is_empty() {
336            return (
337                Segments {
338                    tp: Vec::new(),
339                    slesh: false,
340                },
341                Vec::new(),
342            );
343        }
344
345        loop {
346            let start = usize::from(pattern.starts_with('/'));
347            let idx = if let Some(idx) = pattern[start..].find(['{', '/']) {
348                idx + start
349            } else {
350                break;
351            };
352
353            // static segment
354            if let Some(i) = pattern[start..=idx].find('/') {
355                elems.push(PathElement::Str(pattern[..i + start].to_string()));
356                pelems.push(Segment::Static(pattern[start..i + start].to_string()));
357                pattern = &pattern[i + start..];
358                continue;
359            }
360
361            // dynamic segment
362            let (re_part, rem, tail) = Self::parse_segment(pattern, &mut elems);
363            let re = Regex::new(&re_part).unwrap();
364            let names: Vec<_> = re
365                .capture_names()
366                .filter_map(|name| name.map(|name| Box::leak(Box::new(name.to_owned())).as_str()))
367                .collect();
368            pelems.push(Segment::Dynamic {
369                names,
370                tail,
371                pattern: re,
372            });
373
374            pattern = rem;
375            if pattern.is_empty() {
376                break;
377            }
378        }
379
380        // tail
381        let slesh = pattern.ends_with('/');
382        if slesh {
383            pattern = &pattern[..pattern.len() - 1];
384        }
385        elems.push(PathElement::Str(pattern.to_string()));
386        if pattern.starts_with('/') {
387            pattern = &pattern[1..];
388        }
389        if !pattern.is_empty() {
390            // handle tail expression for static segment
391            if let Some(stripped) = pattern.strip_suffix('*') {
392                let pattern = Regex::new(&format!("^{stripped}(.+)")).unwrap();
393                pelems.push(Segment::Dynamic {
394                    pattern,
395                    names: Vec::new(),
396                    tail: true,
397                });
398            } else {
399                pelems.push(Segment::Static(pattern.to_string()));
400            }
401        }
402
403        // insert last slesh
404        if slesh {
405            elems.push(PathElement::Str("/".to_string()));
406        }
407
408        // merge path elements
409        let mut idx = 0;
410        while idx + 1 < elems.len() {
411            if elems[idx + 1].is_str() && elems[idx + 1].as_str().is_empty() {
412                elems.remove(idx + 1);
413                continue;
414            }
415            if elems[idx].is_str() && elems[idx + 1].is_str() {
416                let s2 = elems.remove(idx + 1).into_str();
417                if let PathElement::Str(ref mut s1) = elems[idx] {
418                    s1.push_str(&s2);
419                    continue;
420                }
421            }
422            idx += 1;
423        }
424
425        (Segments { tp: pelems, slesh }, elems)
426    }
427}
428
429impl Eq for ResourceDef {}
430
431impl PartialEq for ResourceDef {
432    fn eq(&self, other: &ResourceDef) -> bool {
433        self.pattern == other.pattern
434    }
435}
436
437impl Hash for ResourceDef {
438    fn hash<H: Hasher>(&self, state: &mut H) {
439        self.pattern.hash(state);
440    }
441}
442
443impl<'a> From<&'a str> for ResourceDef {
444    fn from(path: &'a str) -> ResourceDef {
445        ResourceDef::new(path)
446    }
447}
448
449impl From<String> for ResourceDef {
450    fn from(path: String) -> ResourceDef {
451        ResourceDef::new(path)
452    }
453}
454
455pub(crate) fn insert_slash(path: &str) -> String {
456    let mut path = path.to_owned();
457    if !path.is_empty() && !path.starts_with('/') {
458        path.insert(0, '/');
459    }
460    path
461}
462
463#[cfg(test)]
464mod tests {
465    use super::*;
466    use crate::path::Path;
467    use crate::tree::Tree;
468
469    #[test]
470    fn test_parse_static() {
471        let re = ResourceDef::new("/");
472        let tree = Tree::new(&re, 1);
473        assert_eq!(tree.find(&mut Path::new("/")), Some(1));
474        assert_eq!(tree.find(&mut Path::new("/a")), None);
475
476        let re = ResourceDef::new("/name");
477        let tree = Tree::new(&re, 1);
478        assert_eq!(tree.find(&mut Path::new("/name")), Some(1));
479        assert_eq!(tree.find(&mut Path::new("/")), None);
480        assert_eq!(tree.find(&mut Path::new("/name1")), None);
481        assert_eq!(tree.find(&mut Path::new("/name/")), None);
482        assert_eq!(tree.find(&mut Path::new("/name~")), None);
483
484        let re = ResourceDef::new("/name/");
485        let tree = Tree::new(&re, 1);
486        assert_eq!(tree.find(&mut Path::new("/name/")), Some(1));
487        assert_eq!(tree.find(&mut Path::new("/name")), None);
488        assert_eq!(tree.find(&mut Path::new("/name/gs")), None);
489
490        let re = ResourceDef::new("/user/profile");
491        let tree = Tree::new(&re, 1);
492        assert_eq!(tree.find(&mut Path::new("/user/profile")), Some(1));
493        assert_eq!(tree.find(&mut Path::new("/user/profile/profile")), None);
494
495        let mut tree = Tree::new(&ResourceDef::new("/name"), 1);
496        tree.insert(&ResourceDef::new("/name/"), 2);
497        assert_eq!(tree.find(&mut Path::new("/name")), Some(1));
498        assert_eq!(tree.find(&mut Path::new("/name/")), Some(2));
499
500        let mut tree = Tree::new(&ResourceDef::new(""), 1);
501        tree.insert(&ResourceDef::new("/test/index.html"), 2);
502        assert_eq!(tree.find_checked(&mut Path::new(""), &|_, _| true), Some(1));
503        assert_eq!(
504            tree.find_checked(&mut Path::new("index.html"), &|_, _| true),
505            None
506        );
507        assert_eq!(
508            tree.find_checked(&mut Path::new("test/index.html"), &|_, _| true),
509            Some(2)
510        );
511    }
512
513    #[test]
514    fn test_parse_param() {
515        let tree = Tree::new(&ResourceDef::new("/{id}"), 1);
516        assert_eq!(tree.find(&mut Path::new("/profile")), Some(1));
517        assert_eq!(tree.find(&mut Path::new("/2345")), Some(1));
518        assert_eq!(tree.find(&mut Path::new("/2345/")), None);
519        assert_eq!(tree.find(&mut Path::new("/2345/sdg")), None);
520
521        let re = ResourceDef::new("/user/{id}");
522        let tree = Tree::new(&re, 1);
523        assert_eq!(tree.find(&mut Path::new("/user/profile")), Some(1));
524        assert_eq!(tree.find(&mut Path::new("/user/2345")), Some(1));
525        assert_eq!(tree.find(&mut Path::new("/user/2345/")), None);
526        assert_eq!(tree.find(&mut Path::new("/user/2345/sdg")), None);
527
528        let mut resource = Path::new("/user/profile");
529        let tree = Tree::new(&re, 1);
530        assert_eq!(tree.find(&mut resource), Some(1));
531        assert_eq!(resource.get("id").unwrap(), "profile");
532
533        let mut resource = Path::new("/user/1245125");
534        assert_eq!(tree.find(&mut resource), Some(1));
535        assert_eq!(resource.get("id").unwrap(), "1245125");
536
537        let tree = Tree::new(&ResourceDef::new("/v{version}/resource/{id}"), 1);
538        assert_eq!(tree.find(&mut Path::new("/v1/resource/320120")), Some(1));
539        assert_eq!(tree.find(&mut Path::new("/v1/resource/320120/")), None,);
540        assert_eq!(tree.find(&mut Path::new("/v/resource/1")), None);
541        assert_eq!(tree.find(&mut Path::new("/resource")), None);
542
543        let mut resource = Path::new("/v151/resource/adahg32");
544        assert_eq!(tree.find(&mut resource), Some(1));
545        assert_eq!(resource.get("version").unwrap(), "151");
546        assert_eq!(resource.get("id").unwrap(), "adahg32");
547
548        let re = ResourceDef::new("/{id:[[:digit:]]{6}}");
549        let tree = Tree::new(&re, 1);
550        assert_eq!(tree.find(&mut Path::new("/012345")), Some(1));
551        assert_eq!(tree.find(&mut Path::new("/012345/")), None);
552        assert_eq!(tree.find(&mut Path::new("/012345/index")), None);
553        assert_eq!(tree.find(&mut Path::new("/012")), None);
554        assert_eq!(tree.find(&mut Path::new("/01234567")), None);
555        assert_eq!(tree.find(&mut Path::new("/XXXXXX")), None);
556
557        let mut resource = Path::new("/012345");
558        assert_eq!(tree.find(&mut resource), Some(1));
559        assert_eq!(resource.get("id").unwrap(), "012345");
560
561        let re = ResourceDef::new("/u/test/v{version}-no-{minor}xx/resource/{id}/{name}");
562        let tree = Tree::new(&re, 1);
563        let mut resource = Path::new("/u/test/v1-no-3xx/resource/320120/name");
564        assert_eq!(tree.find(&mut resource), Some(1));
565        assert_eq!(resource.get("version").unwrap(), "1");
566        assert_eq!(resource.get("minor").unwrap(), "3");
567        assert_eq!(resource.get("id").unwrap(), "320120");
568        assert_eq!(resource.get("name").unwrap(), "name");
569    }
570
571    #[test]
572    fn test_dynamic_set() {
573        let re = ResourceDef::new(vec![
574            "/user/{id}",
575            "/v{version}/resource/{id}",
576            "/{id:[[:digit:]]{6}}",
577        ]);
578        let tree = Tree::new(&re, 1);
579        assert_eq!(tree.find(&mut Path::new("/user/profile")), Some(1));
580        assert_eq!(tree.find(&mut Path::new("/user/2345")), Some(1));
581        assert_eq!(tree.find(&mut Path::new("/user/2345/")), None);
582        assert_eq!(tree.find(&mut Path::new("/user/2345/sdg")), None);
583
584        let mut resource = Path::new("/user/profile");
585        assert_eq!(tree.find(&mut resource), Some(1));
586        assert_eq!(resource.get("id").unwrap(), "profile");
587
588        let mut resource = Path::new("/user/1245125");
589        assert_eq!(tree.find(&mut resource), Some(1));
590        assert_eq!(resource.get("id").unwrap(), "1245125");
591
592        assert_eq!(tree.find(&mut Path::new("/v1/resource/320120")), Some(1));
593        assert_eq!(tree.find(&mut Path::new("/v/resource/1")), None);
594        assert_eq!(tree.find(&mut Path::new("/resource")), None);
595
596        let mut resource = Path::new("/v151/resource/adahg32");
597        assert_eq!(tree.find(&mut resource), Some(1));
598        assert_eq!(resource.get("version").unwrap(), "151");
599        assert_eq!(resource.get("id").unwrap(), "adahg32");
600
601        assert_eq!(tree.find(&mut Path::new("/012345")), Some(1));
602        assert_eq!(tree.find(&mut Path::new("/012")), None);
603        assert_eq!(tree.find(&mut Path::new("/01234567")), None);
604        assert_eq!(tree.find(&mut Path::new("/XXXXXX")), None);
605
606        let mut resource = Path::new("/012345");
607        assert_eq!(tree.find(&mut resource), Some(1));
608        assert_eq!(resource.get("id").unwrap(), "012345");
609
610        let re = ResourceDef::new([
611            "/user/{id}",
612            "/v{version}/resource/{id}",
613            "/{id:[[:digit:]]{6}}",
614        ]);
615        let tree = Tree::new(&re, 1);
616        assert_eq!(tree.find(&mut Path::new("/user/profile")), Some(1));
617        assert_eq!(tree.find(&mut Path::new("/user/2345")), Some(1));
618        assert_eq!(tree.find(&mut Path::new("/user/2345/")), None);
619        assert_eq!(tree.find(&mut Path::new("/user/2345/sdg")), None);
620
621        let re = ResourceDef::new([
622            "/user/{id}".to_string(),
623            "/v{version}/resource/{id}".to_string(),
624            "/{id:[[:digit:]]{6}}".to_string(),
625        ]);
626        let tree = Tree::new(&re, 1);
627        assert_eq!(tree.find(&mut Path::new("/user/profile")), Some(1));
628        assert_eq!(tree.find(&mut Path::new("/user/2345")), Some(1));
629        assert_eq!(tree.find(&mut Path::new("/user/2345/")), None);
630        assert_eq!(tree.find(&mut Path::new("/user/2345/sdg")), None);
631    }
632
633    #[cfg(feature = "http")]
634    #[test]
635    fn test_parse_urlencoded() {
636        use http::Uri;
637
638        let tree = Tree::new(&ResourceDef::new("/user/{id}/test"), 1);
639        let uri = Uri::try_from("/user/2345/test").unwrap();
640        let mut resource = Path::new(uri);
641        assert_eq!(tree.find(&mut resource), Some(1));
642        assert_eq!(resource.get("id").unwrap(), "2345");
643
644        let uri = Uri::try_from("/user/qwe%25/test").unwrap();
645        let mut resource = Path::new(uri);
646        assert_eq!(tree.find(&mut resource), Some(1));
647        assert_eq!(resource.get("id").unwrap(), "qwe%");
648
649        let uri = Uri::try_from("/user/qwe%25rty/test").unwrap();
650        let mut resource = Path::new(uri);
651        assert_eq!(tree.find(&mut resource), Some(1));
652        assert_eq!(resource.get("id").unwrap(), "qwe%rty");
653
654        let uri = Uri::try_from("/user/foo-%2f-%252f-bar/test").unwrap();
655        let mut resource = Path::new(uri);
656        assert_eq!(tree.find(&mut resource), Some(1));
657        assert_eq!(resource.get("id").unwrap(), "foo-/-%2f-bar");
658
659        let uri =
660            Uri::try_from("/user/http%3A%2F%2Flocalhost%3A80%2Ffile%2F%2Fvar%2Flog%2Fsyslog/test")
661                .unwrap();
662        let mut resource = Path::new(uri);
663        assert_eq!(tree.find(&mut resource), Some(1));
664        assert_eq!(
665            resource.get("id").unwrap(),
666            "http://localhost:80/file//var/log/syslog"
667        );
668    }
669
670    #[cfg(feature = "http")]
671    #[test]
672    fn test_extract_path_decode() {
673        use http::Uri;
674
675        let tree = Tree::new(&ResourceDef::new("/{id}/"), 1);
676
677        macro_rules! test_single_value {
678            ($value:expr, $expected:expr) => {{
679                let uri = Uri::try_from($value).unwrap();
680                let mut resource = Path::new(uri);
681                assert_eq!(tree.find(&mut resource), Some(1));
682                assert_eq!(resource.get("id").unwrap(), $expected);
683            }};
684        }
685
686        test_single_value!("/%25/", "%");
687        test_single_value!("/%40%C2%A3%24%25%5E%26%2B%3D/", "@£$%^&+=");
688        test_single_value!("/%2B/", "+");
689        test_single_value!("/%252B/", "%2B");
690        test_single_value!("/%2F/", "/");
691        test_single_value!("/test%2Ftest/", "test/test");
692        test_single_value!("/%252F/", "%2F");
693        test_single_value!("/%m/", "%m");
694        test_single_value!("/%mm/", "%mm");
695        test_single_value!("/test%mm/", "test%mm");
696        test_single_value!(
697            "/http%3A%2F%2Flocalhost%3A80%2Ffoo/",
698            "http://localhost:80/foo"
699        );
700        test_single_value!("/%2Fvar%2Flog%2Fsyslog/", "/var/log/syslog");
701        test_single_value!(
702            "/http%3A%2F%2Flocalhost%3A80%2Ffile%2F%252Fvar%252Flog%252Fsyslog/",
703            "http://localhost:80/file/%2Fvar%2Flog%2Fsyslog"
704        );
705    }
706
707    #[test]
708    #[allow(clippy::mutable_key_type)]
709    fn test_def() {
710        let re = ResourceDef::new("/user/-{id}*");
711        assert_eq!(re, ResourceDef::from("/user/-{id}*"));
712        assert_eq!(re, ResourceDef::from("/user/-{id}*".to_string()));
713
714        let mut h = HashMap::new();
715        h.insert(re.clone(), 1);
716        assert!(h.contains_key(&re));
717
718        let seg = Segment::Static("s".to_string());
719        assert_eq!(seg, Segment::Static("s".to_string()));
720
721        let seg2 = Segment::Dynamic {
722            pattern: Regex::new("test").unwrap(),
723            names: Vec::new(),
724            tail: false,
725        };
726        assert_ne!(seg, seg2);
727        assert_eq!(seg2, seg2);
728    }
729
730    #[test]
731    fn test_parse_tail() {
732        let re = ResourceDef::new("/user/-{id}*");
733        let tree = Tree::new(&re, 1);
734
735        let mut resource = Path::new("/user/-profile");
736        assert_eq!(tree.find(&mut resource), Some(1));
737        assert_eq!(resource.get("id").unwrap(), "profile");
738
739        let mut resource = Path::new("/user/-2345");
740        assert_eq!(tree.find(&mut resource), Some(1));
741        assert_eq!(resource.get("id").unwrap(), "2345");
742
743        let mut resource = Path::new("/user/-2345/");
744        assert_eq!(tree.find(&mut resource), Some(1));
745        assert_eq!(resource.get("id").unwrap(), "2345/");
746
747        let mut resource = Path::new("/user/-2345/sdg");
748        assert_eq!(tree.find(&mut resource), Some(1));
749        assert_eq!(resource.get("id").unwrap(), "2345/sdg");
750    }
751
752    #[test]
753    #[allow(clippy::needless_borrows_for_generic_args)]
754    fn test_static_tail() {
755        let re = ResourceDef::new("/*".to_string());
756        let tree = Tree::new(&re, 1);
757        assert_eq!(
758            tree.find(&mut Path::new(ntex_bytes::ByteString::from_static("/"))),
759            None
760        );
761        assert_eq!(tree.find(&mut Path::new("/profile")), Some(1));
762        assert_eq!(tree.find(&mut Path::new("/user/profile")), Some(1));
763        assert_eq!(tree.find(&mut Path::new("/user/2345")), Some(1));
764        assert_eq!(tree.find(&mut Path::new("/2345/")), Some(1));
765        assert_eq!(tree.find(&mut Path::new("/user/2345/")), Some(1));
766        assert_eq!(tree.find(&mut Path::new("/2345/sdg")), Some(1));
767        assert_eq!(tree.find(&mut Path::new("/user/2345/sdg")), Some(1));
768
769        #[allow(clippy::needless_borrow)]
770        let re = ResourceDef::new(&("/user*".to_string()));
771        let tree = Tree::new(&re, 1);
772        assert_eq!(tree.find(&mut Path::new("/user/profile")), Some(1));
773        assert_eq!(tree.find(&mut Path::new("/user/2345")), Some(1));
774        assert_eq!(tree.find(&mut Path::new("/user/2345/")), Some(1));
775        assert_eq!(tree.find(&mut Path::new("/user/2345/sdg")), Some(1));
776
777        let re = ResourceDef::new("/v/user*");
778        let tree = Tree::new(&re, 1);
779        assert_eq!(tree.find(&mut Path::new("/v/user/profile")), Some(1));
780        assert_eq!(tree.find(&mut Path::new("/v/user/2345")), Some(1));
781        assert_eq!(tree.find(&mut Path::new("/v/user/2345/")), Some(1));
782        assert_eq!(tree.find(&mut Path::new("/v/user/2345/sdg")), Some(1));
783
784        let re = ResourceDef::new("/user/*");
785        let tree = Tree::new(&re, 1);
786        assert_eq!(tree.find(&mut Path::new("/user/profile")), Some(1));
787        assert_eq!(tree.find(&mut Path::new("/user/2345")), Some(1));
788        assert_eq!(tree.find(&mut Path::new("/user/2345/")), Some(1));
789        assert_eq!(tree.find(&mut Path::new("/user/2345/sdg")), Some(1));
790        assert_eq!(tree.find(&mut Path::new("/user/")), None);
791        assert_eq!(tree.find(&mut Path::new("/user")), None);
792
793        let re = ResourceDef::new("/v/user/*");
794        let tree = Tree::new(&re, 1);
795        assert_eq!(tree.find(&mut Path::new("/v/user/profile")), Some(1));
796        assert_eq!(tree.find(&mut Path::new("/v/user/2345")), Some(1));
797        assert_eq!(tree.find(&mut Path::new("/v/user/2345/")), Some(1));
798        assert_eq!(tree.find(&mut Path::new("/v/user/2345/sdg")), Some(1));
799        assert_eq!(tree.find(&mut Path::new("/v/user/")), None);
800        assert_eq!(tree.find(&mut Path::new("/v/user")), None);
801    }
802
803    #[test]
804    fn test_resource_prefix() {
805        let tree = Tree::new(&ResourceDef::prefix("/"), 1);
806        assert_eq!(tree.find(&mut Path::new("/")), Some(1));
807        assert_eq!(tree.find(&mut Path::new("/a")), Some(1));
808        assert_eq!(tree.find(&mut Path::new("/a/test/test")), Some(1));
809
810        let tree = Tree::new(&ResourceDef::prefix("/name"), 1);
811        assert_eq!(tree.find(&mut Path::new("/name")), Some(1));
812        assert_eq!(tree.find(&mut Path::new("/name/")), Some(1));
813        assert_eq!(tree.find(&mut Path::new("/name/test/test")), Some(1));
814        assert_eq!(tree.find(&mut Path::new("/name1")), None);
815        assert_eq!(tree.find(&mut Path::new("/name~")), None);
816
817        let mut resource = Path::new("/name/subpath1/subpath2/index.html");
818        assert_eq!(tree.find(&mut resource), Some(1));
819        assert_eq!(resource.path(), "/subpath1/subpath2/index.html");
820
821        let tree = Tree::new(&ResourceDef::prefix("/name/"), 1);
822        assert_eq!(tree.find(&mut Path::new("/name/")), Some(1));
823        assert_eq!(tree.find(&mut Path::new("/name/test/test")), Some(1));
824        assert_eq!(tree.find(&mut Path::new("/name")), None);
825        assert_eq!(tree.find(&mut Path::new("/name1")), None);
826
827        let tree = Tree::new(&ResourceDef::prefix(vec!["/name/", "/name2/"]), 1);
828        assert_eq!(tree.find(&mut Path::new("/name/")), Some(1));
829        assert_eq!(tree.find(&mut Path::new("/name/test/test")), Some(1));
830        assert_eq!(tree.find(&mut Path::new("/name2/")), Some(1));
831        assert_eq!(tree.find(&mut Path::new("/name2/test/test")), Some(1));
832        assert_eq!(tree.find(&mut Path::new("/name")), None);
833        assert_eq!(tree.find(&mut Path::new("/name1")), None);
834
835        let tree = Tree::new(&ResourceDef::root_prefix("name/"), 1);
836        assert_eq!(tree.find(&mut Path::new("/name/")), Some(1));
837        assert_eq!(tree.find(&mut Path::new("/name/test/test")), Some(1));
838        assert_eq!(tree.find(&mut Path::new("/name")), None);
839        assert_eq!(tree.find(&mut Path::new("/name1")), None);
840
841        let tree = Tree::new(&ResourceDef::root_prefix(vec!["name/", "name2/"]), 1);
842        assert_eq!(tree.find(&mut Path::new("/name/")), Some(1));
843        assert_eq!(tree.find(&mut Path::new("/name/test/test")), Some(1));
844        assert_eq!(tree.find(&mut Path::new("/name2/")), Some(1));
845        assert_eq!(tree.find(&mut Path::new("/name2/test/test")), Some(1));
846        assert_eq!(tree.find(&mut Path::new("/name")), None);
847        assert_eq!(tree.find(&mut Path::new("/name1")), None);
848
849        let mut resource = Path::new("/name/subpath1/subpath2/index.html");
850        assert_eq!(tree.find(&mut resource), Some(1));
851        assert_eq!(resource.path(), "/subpath1/subpath2/index.html");
852    }
853
854    #[test]
855    fn test_reousrce_prefix_dynamic() {
856        let tree = Tree::new(&ResourceDef::prefix("/{name}/"), 1);
857        assert_eq!(tree.find(&mut Path::new("/name/")), Some(1));
858        assert_eq!(tree.find(&mut Path::new("/name/test/test")), Some(1));
859        assert_eq!(tree.find(&mut Path::new("/name")), None);
860        assert_eq!(tree.find(&mut Path::new("/name1")), None);
861        assert_eq!(tree.find(&mut Path::new("/name~")), None);
862
863        let mut resource = Path::new("/test2/");
864        assert_eq!(tree.find(&mut resource), Some(1));
865        assert_eq!(&resource["name"], "test2");
866        assert_eq!(&resource[0], "test2");
867
868        let mut resource = Path::new("/test2/subpath1/subpath2/index.html");
869        assert_eq!(tree.find(&mut resource), Some(1));
870        assert_eq!(&resource["name"], "test2");
871        assert_eq!(&resource[0], "test2");
872        assert_eq!(resource.path(), "/subpath1/subpath2/index.html");
873
874        let tree = Tree::new(&ResourceDef::prefix("/{name}"), 1);
875        assert_eq!(tree.find(&mut Path::new("/name")), Some(1));
876        assert_eq!(tree.find(&mut Path::new("/name/")), Some(1));
877        assert_eq!(tree.find(&mut Path::new("/name/test/test")), Some(1));
878        assert_eq!(tree.find(&mut Path::new("/name1")), Some(1));
879        assert_eq!(tree.find(&mut Path::new("/name~")), Some(1));
880
881        let tree = Tree::new(&ResourceDef::prefix(vec!["/1/{name}/", "/2/{name}/"]), 1);
882        assert_eq!(tree.find(&mut Path::new("/1/name/")), Some(1));
883        assert_eq!(tree.find(&mut Path::new("/1/name/test/test")), Some(1));
884        assert_eq!(tree.find(&mut Path::new("/2/name/")), Some(1));
885        assert_eq!(tree.find(&mut Path::new("/2/name/test/test")), Some(1));
886        assert_eq!(tree.find(&mut Path::new("/1/name")), None);
887        assert_eq!(tree.find(&mut Path::new("/1/name1")), None);
888        assert_eq!(tree.find(&mut Path::new("/1/name~")), None);
889        assert_eq!(tree.find(&mut Path::new("/2/name")), None);
890        assert_eq!(tree.find(&mut Path::new("/2/name1")), None);
891        assert_eq!(tree.find(&mut Path::new("/2/name~")), None);
892
893        let mut resource = Path::new("/1/test2/subpath1/subpath2/index.html");
894        assert_eq!(tree.find(&mut resource), Some(1));
895        assert_eq!(&resource["name"], "test2");
896        assert_eq!(&resource[0], "test2");
897        assert_eq!(resource.path(), "/subpath1/subpath2/index.html");
898
899        let mut resource = Path::new("/2/test3/subpath1/subpath2/index.html");
900        assert_eq!(tree.find(&mut resource), Some(1));
901        assert_eq!(&resource["name"], "test3");
902        assert_eq!(&resource[0], "test3");
903        assert_eq!(resource.path(), "/subpath1/subpath2/index.html");
904
905        // nested
906        let mut tree = Tree::new(&ResourceDef::prefix("/prefix/{v1}/second/{v2}"), 1);
907        tree.insert(&ResourceDef::prefix("/prefix/{v1}"), 2);
908
909        let mut resource = Path::new("/prefix/1/second/2");
910        assert_eq!(tree.find(&mut resource), Some(1));
911        assert_eq!(&resource["v1"], "1");
912        assert_eq!(&resource["v2"], "2");
913
914        let mut resource = Path::new("/prefix/1/second");
915        assert_eq!(tree.find(&mut resource), Some(2));
916        assert_eq!(&resource["v1"], "1");
917        assert_eq!(tree.find(&mut Path::new("/prefix/1")), Some(2));
918
919        // nested
920        let mut tree = Tree::new(
921            &ResourceDef::prefix(vec![
922                "/prefix/{v1}/second/{v2}",
923                "/prefix2/{v1}/second/{v2}",
924            ]),
925            1,
926        );
927        tree.insert(&ResourceDef::prefix("/prefix/{v1}"), 2);
928        tree.insert(&ResourceDef::prefix("/prefix2/{v1}"), 3);
929
930        let mut resource = Path::new("/prefix/1/second/2");
931        assert_eq!(tree.find(&mut resource), Some(1));
932        assert_eq!(&resource["v1"], "1");
933        assert_eq!(&resource["v2"], "2");
934
935        let mut resource = Path::new("/prefix2/1/second/2");
936        assert_eq!(tree.find(&mut resource), Some(1));
937        assert_eq!(&resource["v1"], "1");
938        assert_eq!(&resource["v2"], "2");
939
940        let mut resource = Path::new("/prefix/1/second");
941        assert_eq!(tree.find(&mut resource), Some(2));
942        assert_eq!(&resource["v1"], "1");
943        assert_eq!(tree.find(&mut Path::new("/prefix/1")), Some(2));
944
945        let mut resource = Path::new("/prefix2/1/second");
946        assert_eq!(tree.find(&mut resource), Some(3));
947        assert_eq!(&resource["v1"], "1");
948        assert_eq!(tree.find(&mut Path::new("/prefix2/1")), Some(3));
949    }
950
951    #[test]
952    fn test_resource_path() {
953        let mut s = String::new();
954        let resource = ResourceDef::new("/user/{item1}/test");
955        assert!(resource.resource_path(&mut s, &mut ["user1"].iter()));
956        assert_eq!(s, "/user/user1/test");
957
958        let mut s = String::new();
959        let resource = ResourceDef::new("/user/{item1}/{item2}/test");
960        assert!(resource.resource_path(&mut s, &mut ["item", "item2"].iter()));
961        assert_eq!(s, "/user/item/item2/test");
962
963        let mut s = String::new();
964        let resource = ResourceDef::new("/user/{item1}/{item2}");
965        assert!(resource.resource_path(&mut s, &mut ["item", "item2"].iter()));
966        assert_eq!(s, "/user/item/item2");
967
968        let mut s = String::new();
969        let resource = ResourceDef::new("/user/{item1}/{item2}/");
970        assert!(resource.resource_path(&mut s, &mut ["item", "item2"].iter()));
971        assert_eq!(s, "/user/item/item2/");
972
973        let mut s = String::new();
974        assert!(!resource.resource_path(&mut s, &mut ["item"].iter()));
975
976        let mut s = String::new();
977        assert!(resource.resource_path(&mut s, &mut ["item", "item2"].iter()));
978        assert_eq!(s, "/user/item/item2/");
979        assert!(!resource.resource_path(&mut s, &mut ["item"].iter()));
980
981        let mut s = String::new();
982        assert!(resource.resource_path(&mut s, &mut vec!["item", "item2"].into_iter()));
983        assert_eq!(s, "/user/item/item2/");
984
985        let mut map = HashMap::new();
986        map.insert("item1", "item");
987
988        let mut s = String::new();
989        assert!(!resource.resource_path_named(&mut s, &map));
990
991        let mut s = String::new();
992        map.insert("item2", "item2");
993        assert!(resource.resource_path_named(&mut s, &map));
994        assert_eq!(s, "/user/item/item2/");
995    }
996
997    #[test]
998    fn test_non_rooted() {
999        let tree = Tree::new(&ResourceDef::new("name"), 1);
1000        assert_eq!(tree.find(&mut Path::new("name")), Some(1));
1001        assert_eq!(tree.find(&mut Path::new("/name")), Some(1));
1002        assert_eq!(tree.find(&mut Path::new("/")), None);
1003        assert_eq!(tree.find(&mut Path::new("/name1")), None);
1004        assert_eq!(tree.find(&mut Path::new("/name/")), None);
1005        assert_eq!(tree.find(&mut Path::new("/name~")), None);
1006
1007        let tree = Tree::new(&ResourceDef::new("name/"), 1);
1008        assert_eq!(tree.find(&mut Path::new("name/")), Some(1));
1009        assert_eq!(tree.find(&mut Path::new("/name/")), Some(1));
1010        assert_eq!(tree.find(&mut Path::new("/name")), None);
1011        assert_eq!(tree.find(&mut Path::new("/name/gs")), None);
1012
1013        let tree = Tree::new(&ResourceDef::new("user/profile"), 1);
1014        assert_eq!(tree.find(&mut Path::new("user/profile")), Some(1));
1015        assert_eq!(tree.find(&mut Path::new("/user/profile")), Some(1));
1016        assert_eq!(tree.find(&mut Path::new("/user/profile/profile")), None);
1017
1018        let tree = Tree::new(&ResourceDef::new("{id}"), 1);
1019        assert_eq!(tree.find(&mut Path::new("profile")), Some(1));
1020        assert_eq!(tree.find(&mut Path::new("2345")), Some(1));
1021        assert_eq!(tree.find(&mut Path::new("/2345/")), None);
1022        assert_eq!(tree.find(&mut Path::new("/2345/sdg")), None);
1023
1024        let tree = Tree::new(&ResourceDef::new("{user}/profile/{no}"), 1);
1025        assert_eq!(tree.find(&mut Path::new("user/profile/123")), Some(1));
1026        assert_eq!(tree.find(&mut Path::new("/user/profile/123")), Some(1));
1027        assert_eq!(tree.find(&mut Path::new("/user/profile/p/test/")), None);
1028
1029        let tree = Tree::new(&ResourceDef::new("v{version}/resource/{id}/test"), 1);
1030        assert_eq!(
1031            tree.find(&mut Path::new("v1/resource/320120/test")),
1032            Some(1)
1033        );
1034        assert_eq!(tree.find(&mut Path::new("v/resource/1/test")), None);
1035
1036        let mut resource = Path::new("v151/resource/adahg32/test");
1037        assert_eq!(tree.find(&mut resource), Some(1));
1038        assert_eq!(resource.get("version").unwrap(), "151");
1039        assert_eq!(resource.get("id").unwrap(), "adahg32");
1040
1041        let re = ResourceDef::new("v/{id:[[:digit:]]{6}}");
1042        let tree = Tree::new(&re, 1);
1043        assert_eq!(tree.find(&mut Path::new("v/012345")), Some(1));
1044        assert_eq!(tree.find(&mut Path::new("v/012345/")), None);
1045        assert_eq!(tree.find(&mut Path::new("v/012345/index")), None);
1046        assert_eq!(tree.find(&mut Path::new("v/012")), None);
1047        assert_eq!(tree.find(&mut Path::new("v/01234567")), None);
1048        assert_eq!(tree.find(&mut Path::new("v/XXXXXX")), None);
1049
1050        let mut resource = Path::new("v/012345");
1051        assert_eq!(tree.find(&mut resource), Some(1));
1052        assert_eq!(resource.get("id").unwrap(), "012345");
1053
1054        let re = ResourceDef::new("u/test/v{version}-no-{minor}xx/resource/{id}/{name}");
1055        let tree = Tree::new(&re, 1);
1056        let mut resource = Path::new("u/test/v1-no-3xx/resource/320120/name");
1057        assert_eq!(tree.find(&mut resource), Some(1));
1058        assert_eq!(resource.get("version").unwrap(), "1");
1059        assert_eq!(resource.get("minor").unwrap(), "3");
1060        assert_eq!(resource.get("id").unwrap(), "320120");
1061        assert_eq!(resource.get("name").unwrap(), "name");
1062    }
1063
1064    #[test]
1065    fn test_recursive() {
1066        let mut tree = Tree::new(&ResourceDef::new("/name"), 1);
1067        tree.insert(&ResourceDef::new("/name/"), 2);
1068        tree.insert(&ResourceDef::new("/name/index.html"), 3);
1069        tree.insert(&ResourceDef::prefix("/"), 4);
1070
1071        assert_eq!(tree.find(&mut Path::new("/name")), Some(1));
1072        assert_eq!(tree.find(&mut Path::new("/name/")), Some(2));
1073        assert_eq!(tree.find(&mut Path::new("/name/index.html")), Some(3));
1074        assert_eq!(tree.find(&mut Path::new("/")), Some(4));
1075        assert_eq!(tree.find(&mut Path::new("/test")), Some(4));
1076        assert_eq!(tree.find(&mut Path::new("/test/index.html")), Some(4));
1077    }
1078
1079    #[test]
1080    fn test_with_some_match() {
1081        let mut tree = Tree::new(&ResourceDef::new("/p/{tp}/{id}/{r}"), 1);
1082        tree.insert(&ResourceDef::new("/p/ih/{tp}/d/{id}/sid/{r}/r/{s}"), 3);
1083
1084        let mut p = Path::new("/p/ih/def/d/abc/sid/5bddc58f/r/srv");
1085        assert_eq!(tree.find(&mut p), Some(3));
1086        assert_eq!(p.get("tp"), Some("def"));
1087        assert_eq!(p.get("id"), Some("abc"));
1088        assert_eq!(p.get("r"), Some("5bddc58f"));
1089        assert_eq!(p.get("s"), Some("srv"));
1090        assert_eq!(p.len(), 4);
1091    }
1092}