From 9f470718f7a766d05080420000fbfaaa0589c814 Mon Sep 17 00:00:00 2001 From: david-perez Date: Wed, 22 Jun 2022 14:06:19 +0200 Subject: [PATCH] Fix server routing matching URIs with prefixes (#1484) We are incorrectly matching URIs to the spec when the URI has a prefix that is not in the spec. This is because when generating the regex describing the spec, we're not using the `^` anchor to match from the beginning of the text. Fixes #1483. --- .../src/routing/request_spec.rs | 42 +++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/rust-runtime/aws-smithy-http-server/src/routing/request_spec.rs b/rust-runtime/aws-smithy-http-server/src/routing/request_spec.rs index b6f89446bf..b30be54191 100644 --- a/rust-runtime/aws-smithy-http-server/src/routing/request_spec.rs +++ b/rust-runtime/aws-smithy-http-server/src/routing/request_spec.rs @@ -98,7 +98,7 @@ impl From<&PathSpec> for Regex { fn from(uri_path_spec: &PathSpec) -> Self { let sep = "/"; let re = if uri_path_spec.0.is_empty() { - String::from("/") + String::from(sep) } else { uri_path_spec .0 @@ -113,7 +113,7 @@ impl From<&PathSpec> for Regex { .fold(String::new(), |a, b| a + sep + b) }; - Regex::new(&format!("{}$", re)).unwrap() + Regex::new(&format!("^{}$", re)).expect("invalid `Regex` from `PathSpec`; please file a bug report under https://github.com/awslabs/smithy-rs/issues") } } @@ -250,15 +250,15 @@ mod tests { #[test] fn path_spec_into_regex() { let cases = vec![ - (PathSpec(vec![]), "/$"), - (PathSpec(vec![PathSegment::Literal(String::from("a"))]), "/a$"), + (PathSpec(vec![]), "^/$"), + (PathSpec(vec![PathSegment::Literal(String::from("a"))]), "^/a$"), ( PathSpec(vec![PathSegment::Literal(String::from("a")), PathSegment::Label]), - "/a/[^/]*$", + "^/a/[^/]*$", ), ( PathSpec(vec![PathSegment::Literal(String::from("a")), PathSegment::Greedy]), - "/a/.*$", + "^/a/.*$", ), ( PathSpec(vec![ @@ -266,7 +266,7 @@ mod tests { PathSegment::Greedy, PathSegment::Literal(String::from("suffix")), ]), - "/a/.*/suffix$", + "^/a/.*/suffix$", ), ]; @@ -276,6 +276,34 @@ mod tests { } } + #[test] + fn paths_must_match_spec_from_the_beginning_literal() { + let spec = RequestSpec::from_parts( + Method::GET, + vec![PathSegment::Literal(String::from("path"))], + Vec::new(), + ); + + let misses = vec![(Method::GET, "/beta/path"), (Method::GET, "/multiple/stages/in/path")]; + for (method, uri) in &misses { + assert_eq!(Match::No, spec.matches(&req(method, uri, None))); + } + } + + #[test] + fn paths_must_match_spec_from_the_beginning_label() { + let spec = RequestSpec::from_parts(Method::GET, vec![PathSegment::Label], Vec::new()); + + let misses = vec![ + (Method::GET, "/prefix/label"), + (Method::GET, "/label/suffix"), + (Method::GET, "/prefix/label/suffix"), + ]; + for (method, uri) in &misses { + assert_eq!(Match::No, spec.matches(&req(method, uri, None))); + } + } + #[test] fn greedy_labels_match_greedily() { let spec = RequestSpec::from_parts(