diff --git a/actix-files/Cargo.toml b/actix-files/Cargo.toml index eccf49a77..e17eb9d9f 100644 --- a/actix-files/Cargo.toml +++ b/actix-files/Cargo.toml @@ -35,3 +35,4 @@ percent-encoding = "2.1" actix-rt = "2.2" actix-web = "4.0.0-beta.9" actix-test = "0.1.0-beta.3" +tempfile = "3.2" diff --git a/actix-files/src/lib.rs b/actix-files/src/lib.rs index 1eb091aaf..895910faf 100644 --- a/actix-files/src/lib.rs +++ b/actix-files/src/lib.rs @@ -787,6 +787,29 @@ mod tests { assert_eq!(res.status(), StatusCode::OK); } + #[actix_rt::test] + async fn test_percent_encoding_2() { + let tmpdir = tempfile::tempdir().unwrap(); + let filename = match cfg!(unix) { + true => "ض:?#[]{}<>()@!$&'`|*+,;= %20.test", + false => "ض#[]{}()@!$&'`+,;= %20.test", + }; + let filename_encoded = filename + .as_bytes() + .iter() + .map(|c| format!("%{:02X}", c)) + .collect::(); + std::fs::File::create(tmpdir.path().join(filename)).unwrap(); + + let srv = test::init_service(App::new().service(Files::new("", tmpdir.path()))).await; + + let req = TestRequest::get() + .uri(&format!("/{}", filename_encoded)) + .to_request(); + let res = test::call_service(&srv, req).await; + assert_eq!(res.status(), StatusCode::OK); + } + #[actix_rt::test] async fn test_serve_named_file() { let srv = diff --git a/actix-files/src/service.rs b/actix-files/src/service.rs index 09122c63e..300937967 100644 --- a/actix-files/src/service.rs +++ b/actix-files/src/service.rs @@ -77,11 +77,13 @@ impl Service for FilesService { ))); } - let real_path = - match PathBufWrap::parse_path(req.match_info().path(), self.hidden_files) { - Ok(item) => item, - Err(e) => return Box::pin(ok(req.error_response(e))), - }; + let path_decoded = + percent_encoding::percent_decode_str(req.match_info().path()).decode_utf8_lossy(); + + let real_path = match PathBufWrap::parse_path(&path_decoded, self.hidden_files) { + Ok(item) => item, + Err(e) => return Box::pin(ok(req.error_response(e))), + }; if let Some(filter) = &self.path_filter { if !filter(real_path.as_ref(), req.head()) {