relative path and request head

This commit is contained in:
Ali MJ Al-Nasrawy 2021-06-23 00:59:42 +03:00
parent 13ff7759d3
commit 173ea9acf2
3 changed files with 19 additions and 15 deletions

View File

@ -8,7 +8,10 @@ use std::{
use actix_service::{boxed, IntoServiceFactory, ServiceFactory, ServiceFactoryExt}; use actix_service::{boxed, IntoServiceFactory, ServiceFactory, ServiceFactoryExt};
use actix_utils::future::ok; use actix_utils::future::ok;
use actix_web::{ use actix_web::{
dev::{AppService, HttpServiceFactory, ResourceDef, ServiceRequest, ServiceResponse}, dev::{
AppService, HttpServiceFactory, RequestHead, ResourceDef, ServiceRequest,
ServiceResponse,
},
error::Error, error::Error,
guard::Guard, guard::Guard,
http::header::DispositionType, http::header::DispositionType,
@ -163,7 +166,7 @@ impl Files {
/// `404 NotFound` is returned. /// `404 NotFound` is returned.
pub fn path_filter<F>(mut self, f: F) -> Self pub fn path_filter<F>(mut self, f: F) -> Self
where where
F: Fn(&Path) -> bool + 'static, F: Fn(&Path, &RequestHead) -> bool + 'static,
{ {
self.path_filter = Some(Rc::new(f)); self.path_filter = Some(Rc::new(f));
self self

View File

@ -16,7 +16,7 @@
use actix_service::boxed::{BoxService, BoxServiceFactory}; use actix_service::boxed::{BoxService, BoxServiceFactory};
use actix_web::{ use actix_web::{
dev::{ServiceRequest, ServiceResponse}, dev::{RequestHead, ServiceRequest, ServiceResponse},
error::Error, error::Error,
http::header::DispositionType, http::header::DispositionType,
}; };
@ -57,7 +57,7 @@ pub fn file_extension_to_mime(ext: &str) -> mime::Mime {
type MimeOverride = dyn Fn(&mime::Name<'_>) -> DispositionType; type MimeOverride = dyn Fn(&mime::Name<'_>) -> DispositionType;
type PathFilter = dyn Fn(&Path) -> bool; type PathFilter = dyn Fn(&Path, &RequestHead) -> bool;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@ -907,17 +907,18 @@ mod tests {
#[actix_rt::test] #[actix_rt::test]
async fn test_path_filter() { async fn test_path_filter() {
// prevent searching subdirectories
let st = Files::new("/", ".") let st = Files::new("/", ".")
.path_filter(|path| path.extension() == Some("png".as_ref())) .path_filter(|path, _| path.components().count() == 1)
.new_service(()) .new_service(())
.await .await
.unwrap(); .unwrap();
let req = TestRequest::with_uri("/tests/test.png").to_srv_request(); let req = TestRequest::with_uri("/Cargo.toml").to_srv_request();
let resp = test::call_service(&st, req).await; let resp = test::call_service(&st, req).await;
assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.status(), StatusCode::OK);
let req = TestRequest::with_uri("/Cargo.toml").to_srv_request(); let req = TestRequest::with_uri("/tests/test.png").to_srv_request();
let resp = test::call_service(&st, req).await; let resp = test::call_service(&st, req).await;
assert_eq!(resp.status(), StatusCode::NOT_FOUND); assert_eq!(resp.status(), StatusCode::NOT_FOUND);
} }
@ -928,7 +929,7 @@ mod tests {
.default_handler(|req: ServiceRequest| { .default_handler(|req: ServiceRequest| {
ok(req.into_response(HttpResponse::Ok().body("default content"))) ok(req.into_response(HttpResponse::Ok().body("default content")))
}) })
.path_filter(|path| path.extension() == Some("png".as_ref())) .path_filter(|path, _| path.extension() == Some("png".as_ref()))
.new_service(()) .new_service(())
.await .await
.unwrap(); .unwrap();

View File

@ -83,14 +83,8 @@ impl Service<ServiceRequest> for FilesService {
Err(e) => return Box::pin(ok(req.error_response(e))), Err(e) => return Box::pin(ok(req.error_response(e))),
}; };
// full file path
let path = self.directory.join(&real_path);
if let Err(err) = path.canonicalize() {
return Box::pin(self.handle_err(err, req));
}
if let Some(filter) = &self.path_filter { if let Some(filter) = &self.path_filter {
if !filter(real_path.as_ref()) { if !filter(real_path.as_ref(), req.head()) {
if let Some(ref default) = self.default { if let Some(ref default) = self.default {
return Box::pin(default.call(req)); return Box::pin(default.call(req));
} else { } else {
@ -101,6 +95,12 @@ impl Service<ServiceRequest> for FilesService {
} }
} }
// full file path
let path = self.directory.join(&real_path);
if let Err(err) = path.canonicalize() {
return Box::pin(self.handle_err(err, req));
}
if path.is_dir() { if path.is_dir() {
if self.redirect_to_slash if self.redirect_to_slash
&& !req.path().ends_with('/') && !req.path().ends_with('/')