Skip to content

Commit 4303058

Browse files
authored
enforce path / separators on dynamic prefixes (#378)
1 parent 48b2e11 commit 4303058

File tree

1 file changed

+45
-6
lines changed

1 file changed

+45
-6
lines changed

actix-router/src/resource.rs

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,20 @@ impl ResourceDef {
572572
PatternType::Prefix(ref prefix) if prefix == path => true,
573573
PatternType::Prefix(ref prefix) => is_strict_prefix(prefix, path),
574574

575+
// dynamic prefix
576+
PatternType::Dynamic(ref re, _) if !re.as_str().ends_with('$') => {
577+
match re.find(path) {
578+
// prefix matches exactly
579+
Some(m) if m.end() == path.len() => true,
580+
581+
// prefix matches part
582+
Some(m) => is_strict_prefix(m.as_str(), path),
583+
584+
// prefix does not match
585+
None => false,
586+
}
587+
}
588+
575589
PatternType::Dynamic(ref re, _) => re.is_match(path),
576590
PatternType::DynamicSet(ref re, _) => re.is_match(path),
577591
}
@@ -623,6 +637,20 @@ impl ResourceDef {
623637
PatternType::Prefix(prefix) if is_strict_prefix(prefix, path) => Some(prefix.len()),
624638
PatternType::Prefix(_) => None,
625639

640+
// dynamic prefix
641+
PatternType::Dynamic(ref re, _) if !re.as_str().ends_with('$') => {
642+
match re.find(path) {
643+
// prefix matches exactly
644+
Some(m) if m.end() == path.len() => Some(m.end()),
645+
646+
// prefix matches part
647+
Some(m) if is_strict_prefix(m.as_str(), path) => Some(m.end()),
648+
649+
// prefix does not match
650+
_ => None,
651+
}
652+
}
653+
626654
PatternType::Dynamic(re, _) => re.find(path).map(|m| m.end()),
627655

628656
PatternType::DynamicSet(re, params) => {
@@ -654,7 +682,7 @@ impl ResourceDef {
654682
/// assert_eq!(path.unprocessed(), "");
655683
/// ```
656684
pub fn capture_match_info<T: ResourcePath>(&self, path: &mut Path<T>) -> bool {
657-
profile_method!(is_path_match);
685+
profile_method!(capture_match_info);
658686
self.capture_match_info_fn(path, |_, _| true, ())
659687
}
660688

@@ -707,7 +735,7 @@ impl ResourceDef {
707735
T: ResourcePath,
708736
F: FnOnce(&R, U) -> bool,
709737
{
710-
profile_method!(is_path_match_fn);
738+
profile_method!(capture_match_info_fn);
711739

712740
let mut segments = <[PathItem; MAX_DYNAMIC_SEGMENTS]>::default();
713741
let path = resource.resource_path();
@@ -1475,10 +1503,6 @@ mod tests {
14751503
assert_eq!(&path[0], "test2");
14761504
assert_eq!(path.unprocessed(), "subpath1/subpath2/index.html");
14771505

1478-
let resource = ResourceDef::prefix(r"/id/{id:\d{3}}");
1479-
assert!(resource.is_match("/id/1234"));
1480-
assert_eq!(resource.find_match("/id/1234"), Some(7));
1481-
14821506
let resource = ResourceDef::prefix("/user");
14831507
// input string shorter than prefix
14841508
assert!(resource.find_match("/foo").is_none());
@@ -1551,6 +1575,21 @@ mod tests {
15511575
assert!(path.get("uid").is_some());
15521576
}
15531577

1578+
#[test]
1579+
fn dynamic_prefix_proper_segmentation() {
1580+
let resource = ResourceDef::prefix(r"/id/{id:\d{3}}");
1581+
1582+
assert!(resource.is_match("/id/123"));
1583+
assert!(resource.is_match("/id/123/foo"));
1584+
assert!(!resource.is_match("/id/1234"));
1585+
assert!(!resource.is_match("/id/123a"));
1586+
1587+
assert_eq!(resource.find_match("/id/123"), Some(7));
1588+
assert_eq!(resource.find_match("/id/123/foo"), Some(7));
1589+
assert_eq!(resource.find_match("/id/1234"), None);
1590+
assert_eq!(resource.find_match("/id/123a"), None);
1591+
}
1592+
15541593
#[test]
15551594
fn build_path_map() {
15561595
let resource = ResourceDef::new("/user/{item1}/{item2}/");

0 commit comments

Comments
 (0)