ntex_router/
resource.rs

1use std::collections::HashMap;
2use std::hash::{Hash, Hasher};
3
4use regex::{escape, Regex};
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(ref p1) => match other {
69                Segment::Static(p2) => p1 == p2,
70                _ => false,
71            },
72            Segment::Dynamic {
73                pattern: ref p1,
74                tail: t1,
75                ..
76            } => match other {
77                Segment::Static { .. } => false,
78                Segment::Dynamic {
79                    pattern: ref 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 = path.clone();
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 = path.clone();
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(|c| c == '{' || c == '/') {
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(|c| c == '{' || c == '/') {
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    fn test_def() {
714        let re = ResourceDef::new("/user/-{id}*");
715        assert_eq!(re, ResourceDef::from("/user/-{id}*"));
716        assert_eq!(re, ResourceDef::from("/user/-{id}*".to_string()));
717
718        let mut h = HashMap::new();
719        h.insert(re.clone(), 1);
720        assert!(h.contains_key(&re));
721
722        let seg = Segment::Static("s".to_string());
723        assert_eq!(seg, Segment::Static("s".to_string()));
724
725        let seg2 = Segment::Dynamic {
726            pattern: Regex::new("test").unwrap(),
727            names: Vec::new(),
728            tail: false,
729        };
730        assert!(seg != seg2);
731        assert_eq!(seg2, seg2);
732    }
733
734    #[test]
735    fn test_parse_tail() {
736        let re = ResourceDef::new("/user/-{id}*");
737        let tree = Tree::new(&re, 1);
738
739        let mut resource = Path::new("/user/-profile");
740        assert_eq!(tree.find(&mut resource), Some(1));
741        assert_eq!(resource.get("id").unwrap(), "profile");
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/");
748        assert_eq!(tree.find(&mut resource), Some(1));
749        assert_eq!(resource.get("id").unwrap(), "2345/");
750
751        let mut resource = Path::new("/user/-2345/sdg");
752        assert_eq!(tree.find(&mut resource), Some(1));
753        assert_eq!(resource.get("id").unwrap(), "2345/sdg");
754    }
755
756    #[test]
757    fn test_static_tail() {
758        let re = ResourceDef::new("/*".to_string());
759        let tree = Tree::new(&re, 1);
760        assert_eq!(
761            tree.find(&mut Path::new(ntex_bytes::ByteString::from_static("/"))),
762            None
763        );
764        assert_eq!(tree.find(&mut Path::new("/profile")), Some(1));
765        assert_eq!(tree.find(&mut Path::new("/user/profile")), Some(1));
766        assert_eq!(tree.find(&mut Path::new("/user/2345")), Some(1));
767        assert_eq!(tree.find(&mut Path::new("/2345/")), Some(1));
768        assert_eq!(tree.find(&mut Path::new("/user/2345/")), Some(1));
769        assert_eq!(tree.find(&mut Path::new("/2345/sdg")), Some(1));
770        assert_eq!(tree.find(&mut Path::new("/user/2345/sdg")), Some(1));
771
772        #[allow(clippy::needless_borrow)]
773        let re = ResourceDef::new(&("/user*".to_string()));
774        let tree = Tree::new(&re, 1);
775        assert_eq!(tree.find(&mut Path::new("/user/profile")), Some(1));
776        assert_eq!(tree.find(&mut Path::new("/user/2345")), Some(1));
777        assert_eq!(tree.find(&mut Path::new("/user/2345/")), Some(1));
778        assert_eq!(tree.find(&mut Path::new("/user/2345/sdg")), Some(1));
779
780        let re = ResourceDef::new("/v/user*");
781        let tree = Tree::new(&re, 1);
782        assert_eq!(tree.find(&mut Path::new("/v/user/profile")), Some(1));
783        assert_eq!(tree.find(&mut Path::new("/v/user/2345")), Some(1));
784        assert_eq!(tree.find(&mut Path::new("/v/user/2345/")), Some(1));
785        assert_eq!(tree.find(&mut Path::new("/v/user/2345/sdg")), Some(1));
786
787        let re = ResourceDef::new("/user/*");
788        let tree = Tree::new(&re, 1);
789        assert_eq!(tree.find(&mut Path::new("/user/profile")), Some(1));
790        assert_eq!(tree.find(&mut Path::new("/user/2345")), Some(1));
791        assert_eq!(tree.find(&mut Path::new("/user/2345/")), Some(1));
792        assert_eq!(tree.find(&mut Path::new("/user/2345/sdg")), Some(1));
793        assert_eq!(tree.find(&mut Path::new("/user/")), None);
794        assert_eq!(tree.find(&mut Path::new("/user")), None);
795
796        let re = ResourceDef::new("/v/user/*");
797        let tree = Tree::new(&re, 1);
798        assert_eq!(tree.find(&mut Path::new("/v/user/profile")), Some(1));
799        assert_eq!(tree.find(&mut Path::new("/v/user/2345")), Some(1));
800        assert_eq!(tree.find(&mut Path::new("/v/user/2345/")), Some(1));
801        assert_eq!(tree.find(&mut Path::new("/v/user/2345/sdg")), Some(1));
802        assert_eq!(tree.find(&mut Path::new("/v/user/")), None);
803        assert_eq!(tree.find(&mut Path::new("/v/user")), None);
804    }
805
806    #[test]
807    fn test_resource_prefix() {
808        let tree = Tree::new(&ResourceDef::prefix("/"), 1);
809        assert_eq!(tree.find(&mut Path::new("/")), Some(1));
810        assert_eq!(tree.find(&mut Path::new("/a")), Some(1));
811        assert_eq!(tree.find(&mut Path::new("/a/test/test")), Some(1));
812
813        let tree = Tree::new(&ResourceDef::prefix("/name"), 1);
814        assert_eq!(tree.find(&mut Path::new("/name")), Some(1));
815        assert_eq!(tree.find(&mut Path::new("/name/")), Some(1));
816        assert_eq!(tree.find(&mut Path::new("/name/test/test")), Some(1));
817        assert_eq!(tree.find(&mut Path::new("/name1")), None);
818        assert_eq!(tree.find(&mut Path::new("/name~")), None);
819
820        let mut resource = Path::new("/name/subpath1/subpath2/index.html");
821        assert_eq!(tree.find(&mut resource), Some(1));
822        assert_eq!(resource.path(), "/subpath1/subpath2/index.html");
823
824        let tree = Tree::new(&ResourceDef::prefix("/name/"), 1);
825        assert_eq!(tree.find(&mut Path::new("/name/")), Some(1));
826        assert_eq!(tree.find(&mut Path::new("/name/test/test")), Some(1));
827        assert_eq!(tree.find(&mut Path::new("/name")), None);
828        assert_eq!(tree.find(&mut Path::new("/name1")), None);
829
830        let tree = Tree::new(&ResourceDef::prefix(vec!["/name/", "/name2/"]), 1);
831        assert_eq!(tree.find(&mut Path::new("/name/")), Some(1));
832        assert_eq!(tree.find(&mut Path::new("/name/test/test")), Some(1));
833        assert_eq!(tree.find(&mut Path::new("/name2/")), Some(1));
834        assert_eq!(tree.find(&mut Path::new("/name2/test/test")), Some(1));
835        assert_eq!(tree.find(&mut Path::new("/name")), None);
836        assert_eq!(tree.find(&mut Path::new("/name1")), None);
837
838        let tree = Tree::new(&ResourceDef::root_prefix("name/"), 1);
839        assert_eq!(tree.find(&mut Path::new("/name/")), Some(1));
840        assert_eq!(tree.find(&mut Path::new("/name/test/test")), Some(1));
841        assert_eq!(tree.find(&mut Path::new("/name")), None);
842        assert_eq!(tree.find(&mut Path::new("/name1")), None);
843
844        let tree = Tree::new(&ResourceDef::root_prefix(vec!["name/", "name2/"]), 1);
845        assert_eq!(tree.find(&mut Path::new("/name/")), Some(1));
846        assert_eq!(tree.find(&mut Path::new("/name/test/test")), Some(1));
847        assert_eq!(tree.find(&mut Path::new("/name2/")), Some(1));
848        assert_eq!(tree.find(&mut Path::new("/name2/test/test")), Some(1));
849        assert_eq!(tree.find(&mut Path::new("/name")), None);
850        assert_eq!(tree.find(&mut Path::new("/name1")), None);
851
852        let mut resource = Path::new("/name/subpath1/subpath2/index.html");
853        assert_eq!(tree.find(&mut resource), Some(1));
854        assert_eq!(resource.path(), "/subpath1/subpath2/index.html");
855    }
856
857    #[test]
858    fn test_reousrce_prefix_dynamic() {
859        let tree = Tree::new(&ResourceDef::prefix("/{name}/"), 1);
860        assert_eq!(tree.find(&mut Path::new("/name/")), Some(1));
861        assert_eq!(tree.find(&mut Path::new("/name/test/test")), Some(1));
862        assert_eq!(tree.find(&mut Path::new("/name")), None);
863        assert_eq!(tree.find(&mut Path::new("/name1")), None);
864        assert_eq!(tree.find(&mut Path::new("/name~")), None);
865
866        let mut resource = Path::new("/test2/");
867        assert_eq!(tree.find(&mut resource), Some(1));
868        assert_eq!(&resource["name"], "test2");
869        assert_eq!(&resource[0], "test2");
870
871        let mut resource = Path::new("/test2/subpath1/subpath2/index.html");
872        assert_eq!(tree.find(&mut resource), Some(1));
873        assert_eq!(&resource["name"], "test2");
874        assert_eq!(&resource[0], "test2");
875        assert_eq!(resource.path(), "/subpath1/subpath2/index.html");
876
877        let tree = Tree::new(&ResourceDef::prefix("/{name}"), 1);
878        assert_eq!(tree.find(&mut Path::new("/name")), Some(1));
879        assert_eq!(tree.find(&mut Path::new("/name/")), Some(1));
880        assert_eq!(tree.find(&mut Path::new("/name/test/test")), Some(1));
881        assert_eq!(tree.find(&mut Path::new("/name1")), Some(1));
882        assert_eq!(tree.find(&mut Path::new("/name~")), Some(1));
883
884        let tree = Tree::new(&ResourceDef::prefix(vec!["/1/{name}/", "/2/{name}/"]), 1);
885        assert_eq!(tree.find(&mut Path::new("/1/name/")), Some(1));
886        assert_eq!(tree.find(&mut Path::new("/1/name/test/test")), Some(1));
887        assert_eq!(tree.find(&mut Path::new("/2/name/")), Some(1));
888        assert_eq!(tree.find(&mut Path::new("/2/name/test/test")), Some(1));
889        assert_eq!(tree.find(&mut Path::new("/1/name")), None);
890        assert_eq!(tree.find(&mut Path::new("/1/name1")), None);
891        assert_eq!(tree.find(&mut Path::new("/1/name~")), None);
892        assert_eq!(tree.find(&mut Path::new("/2/name")), None);
893        assert_eq!(tree.find(&mut Path::new("/2/name1")), None);
894        assert_eq!(tree.find(&mut Path::new("/2/name~")), None);
895
896        let mut resource = Path::new("/1/test2/subpath1/subpath2/index.html");
897        assert_eq!(tree.find(&mut resource), Some(1));
898        assert_eq!(&resource["name"], "test2");
899        assert_eq!(&resource[0], "test2");
900        assert_eq!(resource.path(), "/subpath1/subpath2/index.html");
901
902        let mut resource = Path::new("/2/test3/subpath1/subpath2/index.html");
903        assert_eq!(tree.find(&mut resource), Some(1));
904        assert_eq!(&resource["name"], "test3");
905        assert_eq!(&resource[0], "test3");
906        assert_eq!(resource.path(), "/subpath1/subpath2/index.html");
907
908        // nested
909        let mut tree = Tree::new(&ResourceDef::prefix("/prefix/{v1}/second/{v2}"), 1);
910        tree.insert(&ResourceDef::prefix("/prefix/{v1}"), 2);
911
912        let mut resource = Path::new("/prefix/1/second/2");
913        assert_eq!(tree.find(&mut resource), Some(1));
914        assert_eq!(&resource["v1"], "1");
915        assert_eq!(&resource["v2"], "2");
916
917        let mut resource = Path::new("/prefix/1/second");
918        assert_eq!(tree.find(&mut resource), Some(2));
919        assert_eq!(&resource["v1"], "1");
920        assert_eq!(tree.find(&mut Path::new("/prefix/1")), Some(2));
921
922        // nested
923        let mut tree = Tree::new(
924            &ResourceDef::prefix(vec![
925                "/prefix/{v1}/second/{v2}",
926                "/prefix2/{v1}/second/{v2}",
927            ]),
928            1,
929        );
930        tree.insert(&ResourceDef::prefix("/prefix/{v1}"), 2);
931        tree.insert(&ResourceDef::prefix("/prefix2/{v1}"), 3);
932
933        let mut resource = Path::new("/prefix/1/second/2");
934        assert_eq!(tree.find(&mut resource), Some(1));
935        assert_eq!(&resource["v1"], "1");
936        assert_eq!(&resource["v2"], "2");
937
938        let mut resource = Path::new("/prefix2/1/second/2");
939        assert_eq!(tree.find(&mut resource), Some(1));
940        assert_eq!(&resource["v1"], "1");
941        assert_eq!(&resource["v2"], "2");
942
943        let mut resource = Path::new("/prefix/1/second");
944        assert_eq!(tree.find(&mut resource), Some(2));
945        assert_eq!(&resource["v1"], "1");
946        assert_eq!(tree.find(&mut Path::new("/prefix/1")), Some(2));
947
948        let mut resource = Path::new("/prefix2/1/second");
949        assert_eq!(tree.find(&mut resource), Some(3));
950        assert_eq!(&resource["v1"], "1");
951        assert_eq!(tree.find(&mut Path::new("/prefix2/1")), Some(3));
952    }
953
954    #[test]
955    fn test_resource_path() {
956        let mut s = String::new();
957        let resource = ResourceDef::new("/user/{item1}/test");
958        assert!(resource.resource_path(&mut s, &mut ["user1"].iter()));
959        assert_eq!(s, "/user/user1/test");
960
961        let mut s = String::new();
962        let resource = ResourceDef::new("/user/{item1}/{item2}/test");
963        assert!(resource.resource_path(&mut s, &mut ["item", "item2"].iter()));
964        assert_eq!(s, "/user/item/item2/test");
965
966        let mut s = String::new();
967        let resource = ResourceDef::new("/user/{item1}/{item2}");
968        assert!(resource.resource_path(&mut s, &mut ["item", "item2"].iter()));
969        assert_eq!(s, "/user/item/item2");
970
971        let mut s = String::new();
972        let resource = ResourceDef::new("/user/{item1}/{item2}/");
973        assert!(resource.resource_path(&mut s, &mut ["item", "item2"].iter()));
974        assert_eq!(s, "/user/item/item2/");
975
976        let mut s = String::new();
977        assert!(!resource.resource_path(&mut s, &mut ["item"].iter()));
978
979        let mut s = String::new();
980        assert!(resource.resource_path(&mut s, &mut ["item", "item2"].iter()));
981        assert_eq!(s, "/user/item/item2/");
982        assert!(!resource.resource_path(&mut s, &mut ["item"].iter()));
983
984        let mut s = String::new();
985        assert!(resource.resource_path(&mut s, &mut vec!["item", "item2"].into_iter()));
986        assert_eq!(s, "/user/item/item2/");
987
988        let mut map = HashMap::new();
989        map.insert("item1", "item");
990
991        let mut s = String::new();
992        assert!(!resource.resource_path_named(&mut s, &map));
993
994        let mut s = String::new();
995        map.insert("item2", "item2");
996        assert!(resource.resource_path_named(&mut s, &map));
997        assert_eq!(s, "/user/item/item2/");
998    }
999
1000    #[test]
1001    fn test_non_rooted() {
1002        let tree = Tree::new(&ResourceDef::new("name"), 1);
1003        assert_eq!(tree.find(&mut Path::new("name")), Some(1));
1004        assert_eq!(tree.find(&mut Path::new("/name")), Some(1));
1005        assert_eq!(tree.find(&mut Path::new("/")), None);
1006        assert_eq!(tree.find(&mut Path::new("/name1")), None);
1007        assert_eq!(tree.find(&mut Path::new("/name/")), None);
1008        assert_eq!(tree.find(&mut Path::new("/name~")), None);
1009
1010        let tree = Tree::new(&ResourceDef::new("name/"), 1);
1011        assert_eq!(tree.find(&mut Path::new("name/")), Some(1));
1012        assert_eq!(tree.find(&mut Path::new("/name/")), Some(1));
1013        assert_eq!(tree.find(&mut Path::new("/name")), None);
1014        assert_eq!(tree.find(&mut Path::new("/name/gs")), None);
1015
1016        let tree = Tree::new(&ResourceDef::new("user/profile"), 1);
1017        assert_eq!(tree.find(&mut Path::new("user/profile")), Some(1));
1018        assert_eq!(tree.find(&mut Path::new("/user/profile")), Some(1));
1019        assert_eq!(tree.find(&mut Path::new("/user/profile/profile")), None);
1020
1021        let tree = Tree::new(&ResourceDef::new("{id}"), 1);
1022        assert_eq!(tree.find(&mut Path::new("profile")), Some(1));
1023        assert_eq!(tree.find(&mut Path::new("2345")), Some(1));
1024        assert_eq!(tree.find(&mut Path::new("/2345/")), None);
1025        assert_eq!(tree.find(&mut Path::new("/2345/sdg")), None);
1026
1027        let tree = Tree::new(&ResourceDef::new("{user}/profile/{no}"), 1);
1028        assert_eq!(tree.find(&mut Path::new("user/profile/123")), Some(1));
1029        assert_eq!(tree.find(&mut Path::new("/user/profile/123")), Some(1));
1030        assert_eq!(tree.find(&mut Path::new("/user/profile/p/test/")), None);
1031
1032        let tree = Tree::new(&ResourceDef::new("v{version}/resource/{id}/test"), 1);
1033        assert_eq!(
1034            tree.find(&mut Path::new("v1/resource/320120/test")),
1035            Some(1)
1036        );
1037        assert_eq!(tree.find(&mut Path::new("v/resource/1/test")), None);
1038
1039        let mut resource = Path::new("v151/resource/adahg32/test");
1040        assert_eq!(tree.find(&mut resource), Some(1));
1041        assert_eq!(resource.get("version").unwrap(), "151");
1042        assert_eq!(resource.get("id").unwrap(), "adahg32");
1043
1044        let re = ResourceDef::new("v/{id:[[:digit:]]{6}}");
1045        let tree = Tree::new(&re, 1);
1046        assert_eq!(tree.find(&mut Path::new("v/012345")), Some(1));
1047        assert_eq!(tree.find(&mut Path::new("v/012345/")), None);
1048        assert_eq!(tree.find(&mut Path::new("v/012345/index")), None);
1049        assert_eq!(tree.find(&mut Path::new("v/012")), None);
1050        assert_eq!(tree.find(&mut Path::new("v/01234567")), None);
1051        assert_eq!(tree.find(&mut Path::new("v/XXXXXX")), None);
1052
1053        let mut resource = Path::new("v/012345");
1054        assert_eq!(tree.find(&mut resource), Some(1));
1055        assert_eq!(resource.get("id").unwrap(), "012345");
1056
1057        let re = ResourceDef::new("u/test/v{version}-no-{minor}xx/resource/{id}/{name}");
1058        let tree = Tree::new(&re, 1);
1059        let mut resource = Path::new("u/test/v1-no-3xx/resource/320120/name");
1060        assert_eq!(tree.find(&mut resource), Some(1));
1061        assert_eq!(resource.get("version").unwrap(), "1");
1062        assert_eq!(resource.get("minor").unwrap(), "3");
1063        assert_eq!(resource.get("id").unwrap(), "320120");
1064        assert_eq!(resource.get("name").unwrap(), "name");
1065    }
1066
1067    #[test]
1068    fn test_recursive() {
1069        let mut tree = Tree::new(&ResourceDef::new("/name"), 1);
1070        tree.insert(&ResourceDef::new("/name/"), 2);
1071        tree.insert(&ResourceDef::new("/name/index.html"), 3);
1072        tree.insert(&ResourceDef::prefix("/"), 4);
1073
1074        assert_eq!(tree.find(&mut Path::new("/name")), Some(1));
1075        assert_eq!(tree.find(&mut Path::new("/name/")), Some(2));
1076        assert_eq!(tree.find(&mut Path::new("/name/index.html")), Some(3));
1077        assert_eq!(tree.find(&mut Path::new("/")), Some(4));
1078        assert_eq!(tree.find(&mut Path::new("/test")), Some(4));
1079        assert_eq!(tree.find(&mut Path::new("/test/index.html")), Some(4));
1080    }
1081
1082    #[test]
1083    fn test_with_some_match() {
1084        let mut tree = Tree::new(&ResourceDef::new("/p/{tp}/{id}/{r}"), 1);
1085        tree.insert(&ResourceDef::new("/p/ih/{tp}/d/{id}/sid/{r}/r/{s}"), 3);
1086
1087        let mut p = Path::new("/p/ih/def/d/abc/sid/5bddc58f/r/srv");
1088        assert_eq!(tree.find(&mut p), Some(3));
1089        assert_eq!(p.get("tp"), Some("def"));
1090        assert_eq!(p.get("id"), Some("abc"));
1091        assert_eq!(p.get("r"), Some("5bddc58f"));
1092        assert_eq!(p.get("s"), Some("srv"));
1093        assert_eq!(p.len(), 4);
1094    }
1095}