1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-08-20 12:45:41 +02:00

files: percent-decode url path (#2398)

Co-authored-by: Rob Ede <robjtede@icloud.com>
This commit is contained in:
Ali MJ Al-Nasrawy
2022-01-04 15:54:11 +03:00
committed by GitHub
parent 93754f307f
commit 374dc9bfc9
6 changed files with 68 additions and 1 deletions

View File

@@ -1,5 +1,5 @@
use std::{
path::{Path, PathBuf},
path::{Component, Path, PathBuf},
str::FromStr,
};
@@ -26,8 +26,23 @@ impl PathBufWrap {
pub fn parse_path(path: &str, hidden_files: bool) -> Result<Self, UriSegmentError> {
let mut buf = PathBuf::new();
// equivalent to `path.split('/').count()`
let mut segment_count = path.matches('/').count() + 1;
// we can decode the whole path here (instead of per-segment decoding)
// because we will reject `%2F` in paths using `segement_count`.
let path = percent_encoding::percent_decode_str(path)
.decode_utf8()
.map_err(|_| UriSegmentError::NotValidUtf8)?;
// disallow decoding `%2F` into `/`
if segment_count != path.matches('/').count() + 1 {
return Err(UriSegmentError::BadChar('/'));
}
for segment in path.split('/') {
if segment == ".." {
segment_count -= 1;
buf.pop();
} else if !hidden_files && segment.starts_with('.') {
return Err(UriSegmentError::BadStart('.'));
@@ -40,6 +55,7 @@ impl PathBufWrap {
} else if segment.ends_with('<') {
return Err(UriSegmentError::BadEnd('<'));
} else if segment.is_empty() {
segment_count -= 1;
continue;
} else if cfg!(windows) && segment.contains('\\') {
return Err(UriSegmentError::BadChar('\\'));
@@ -48,6 +64,12 @@ impl PathBufWrap {
}
}
// make sure we agree with stdlib parser
for (i, component) in buf.components().enumerate() {
assert!(matches!(component, Component::Normal(_)));
assert!(i < segment_count);
}
Ok(PathBufWrap(buf))
}
}