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(