diff --git a/actix-files/src/path_buf.rs b/actix-files/src/path_buf.rs index 03b2cd766..b20743a7d 100644 --- a/actix-files/src/path_buf.rs +++ b/actix-files/src/path_buf.rs @@ -85,7 +85,8 @@ impl FromRequest for PathBufWrap { type Future = Ready>; fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future { - ready(req.match_info().path().parse()) + // preferred over `req.path()` for safe percent decoding + ready(req.match_info().as_str().parse()) } } diff --git a/actix-files/src/service.rs b/actix-files/src/service.rs index 4e8b72311..1a8cedbb9 100644 --- a/actix-files/src/service.rs +++ b/actix-files/src/service.rs @@ -120,8 +120,10 @@ impl Service for FilesService { )); } + // `req.match_info().as_str()` preferred over `req.path()` for safe percent decoding + let real_path = - match PathBufWrap::parse_path(req.match_info().path(), this.hidden_files) { + match PathBufWrap::parse_path(req.match_info().as_str(), this.hidden_files) { Ok(item) => item, Err(err) => return Ok(req.error_response(err)), }; diff --git a/actix-router/src/path.rs b/actix-router/src/path.rs index f8667ad89..ac0591665 100644 --- a/actix-router/src/path.rs +++ b/actix-router/src/path.rs @@ -37,19 +37,39 @@ impl Path { } } - /// Get reference to inner path instance. + /// Returns reference to inner path instance. #[inline] pub fn get_ref(&self) -> &T { &self.path } - /// Get mutable reference to inner path instance. + /// Returns mutable reference to inner path instance. #[inline] pub fn get_mut(&mut self) -> &mut T { &mut self.path } + /// Returns full path as a string. + /// + /// Use this instead of ` + pub fn as_str(&self) -> &str { + self.path.path() + } + /// Returns unprocessed part of the path. + /// + /// # Panics + /// Unlike [`path`](Self::path), this will panic if `skip` indexes further than the path length. + #[inline] + pub fn unprocessed(&self) -> &str { + profile_method!(unprocessed); + let skip = (self.skip as usize).min(self.as_str().len()); + &self.path.path()[skip..] + } + + /// Returns unprocessed part of the path. + #[doc(hidden)] + #[deprecated(since = "0.6.0", note = "Use `.as_str()` or `.unprocessed()`.")] #[inline] pub fn path(&self) -> &str { profile_method!(path); @@ -63,16 +83,6 @@ impl Path { } } - /// Returns unprocessed part of the path. - /// - /// # Panics - /// Unlike [`path`](Self::path), this will panic if `skip` indexes further than the path length. - #[inline] - pub fn unprocessed(&self) -> &str { - profile_method!(unprocessed); - &self.path.path()[(self.skip as usize)..] - } - /// Set new path. #[inline] pub fn set(&mut self, path: T) { diff --git a/actix-router/src/resource.rs b/actix-router/src/resource.rs index d39a6b923..c0b5522af 100644 --- a/actix-router/src/resource.rs +++ b/actix-router/src/resource.rs @@ -692,7 +692,7 @@ impl ResourceDef { let mut segments = <[PathItem; MAX_DYNAMIC_SEGMENTS]>::default(); let path = resource.resource_path(); - let path_str = path.path(); + let path_str = path.unprocessed(); let (matched_len, matched_vars) = match &self.pat_type { PatternType::Static(pattern) => { @@ -710,7 +710,7 @@ impl ResourceDef { let captures = { profile_section!(pattern_dynamic_regex_exec); - match re.captures(path.path()) { + match re.captures(path.unprocessed()) { Some(captures) => captures, _ => return false, } @@ -738,7 +738,7 @@ impl ResourceDef { PatternType::DynamicSet(re, params) => { profile_section!(pattern_dynamic_set); - let path = path.path(); + let path = path.unprocessed(); let (pattern, names) = match re.matches(path).into_iter().next() { Some(idx) => ¶ms[idx], _ => return false, diff --git a/actix-router/src/url.rs b/actix-router/src/url.rs index c5a3508aa..f8d94ae4a 100644 --- a/actix-router/src/url.rs +++ b/actix-router/src/url.rs @@ -121,7 +121,7 @@ mod tests { } #[test] - fn valid_utf8_multibyte() { + fn valid_utf8_multi_byte() { let test = ('\u{FF00}'..='\u{FFFF}').collect::(); let encoded = percent_encode(test.as_bytes()); let path = match_url("/a/{id}/b", format!("/a/{}/b", &encoded)); @@ -135,6 +135,6 @@ mod tests { let path = Path::new(Url::new(uri)); // We should always get a valid utf8 string - assert!(String::from_utf8(path.path().as_bytes().to_owned()).is_ok()); + assert!(String::from_utf8(path.as_str().as_bytes().to_owned()).is_ok()); } } diff --git a/src/service.rs b/src/service.rs index 03ea0b97b..162c90ec8 100644 --- a/src/service.rs +++ b/src/service.rs @@ -198,9 +198,9 @@ impl ServiceRequest { self.req.connection_info() } - /// Get a reference to the Path parameters. + /// Returns a reference to the Path parameters. /// - /// Params is a container for url parameters. + /// Params is a container for URL parameters. /// A variable segment is specified in the form `{identifier}`, /// where the identifier can be used later in a request handler to /// access the matched value for that segment. @@ -209,6 +209,12 @@ impl ServiceRequest { self.req.match_info() } + /// Returns a mutable reference to the Path parameters. + #[inline] + pub fn match_info_mut(&mut self) -> &mut Path { + self.req.match_info_mut() + } + /// Counterpart to [`HttpRequest::match_name`]. #[inline] pub fn match_name(&self) -> Option<&str> { @@ -221,12 +227,6 @@ impl ServiceRequest { self.req.match_pattern() } - /// Get a mutable reference to the Path parameters. - #[inline] - pub fn match_info_mut(&mut self) -> &mut Path { - self.req.match_info_mut() - } - /// Get a reference to a `ResourceMap` of current application. #[inline] pub fn resource_map(&self) -> &ResourceMap {