ntex_router/
resource.rs

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