This commit is contained in:
Ali MJ Al-Nasrawy 2021-06-20 20:22:55 +03:00
parent f81d4bdae7
commit 2f340607c0
3 changed files with 40 additions and 3 deletions

View File

@ -1,4 +1,9 @@
use std::{cell::RefCell, fmt, io, path::PathBuf, rc::Rc}; use std::{
cell::RefCell,
fmt, io,
path::{Path, PathBuf},
rc::Rc,
};
use actix_service::{boxed, IntoServiceFactory, ServiceFactory, ServiceFactoryExt}; use actix_service::{boxed, IntoServiceFactory, ServiceFactory, ServiceFactoryExt};
use actix_utils::future::ok; use actix_utils::future::ok;
@ -13,7 +18,7 @@ use futures_core::future::LocalBoxFuture;
use crate::{ use crate::{
directory_listing, named, Directory, DirectoryRenderer, FilesService, HttpNewService, directory_listing, named, Directory, DirectoryRenderer, FilesService, HttpNewService,
MimeOverride, MimeOverride, PathFilter,
}; };
/// Static files handling service. /// Static files handling service.
@ -36,6 +41,7 @@ pub struct Files {
default: Rc<RefCell<Option<Rc<HttpNewService>>>>, default: Rc<RefCell<Option<Rc<HttpNewService>>>>,
renderer: Rc<DirectoryRenderer>, renderer: Rc<DirectoryRenderer>,
mime_override: Option<Rc<MimeOverride>>, mime_override: Option<Rc<MimeOverride>>,
path_filter: Option<Rc<PathFilter>>,
file_flags: named::Flags, file_flags: named::Flags,
use_guards: Option<Rc<dyn Guard>>, use_guards: Option<Rc<dyn Guard>>,
guards: Vec<Rc<dyn Guard>>, guards: Vec<Rc<dyn Guard>>,
@ -60,6 +66,7 @@ impl Clone for Files {
file_flags: self.file_flags, file_flags: self.file_flags,
path: self.path.clone(), path: self.path.clone(),
mime_override: self.mime_override.clone(), mime_override: self.mime_override.clone(),
path_filter: self.path_filter.clone(),
use_guards: self.use_guards.clone(), use_guards: self.use_guards.clone(),
guards: self.guards.clone(), guards: self.guards.clone(),
hidden_files: self.hidden_files, hidden_files: self.hidden_files,
@ -104,6 +111,7 @@ impl Files {
default: Rc::new(RefCell::new(None)), default: Rc::new(RefCell::new(None)),
renderer: Rc::new(directory_listing), renderer: Rc::new(directory_listing),
mime_override: None, mime_override: None,
path_filter: None,
file_flags: named::Flags::default(), file_flags: named::Flags::default(),
use_guards: None, use_guards: None,
guards: Vec::new(), guards: Vec::new(),
@ -149,6 +157,18 @@ impl Files {
self self
} }
/// Sets path filtering closure.
///
/// When a path doen't pass the filter, [`Files::default_handler`] is called if set, otherwise,
/// `404 NotFound` is returned.
pub fn path_filter<F>(mut self, f: F) -> Self
where
F: Fn(&Path) -> bool + 'static,
{
self.path_filter = Some(Rc::new(f));
self
}
/// Set index file /// Set index file
/// ///
/// Shows specific index file for directories instead of /// Shows specific index file for directories instead of
@ -318,6 +338,7 @@ impl ServiceFactory<ServiceRequest> for Files {
default: None, default: None,
renderer: self.renderer.clone(), renderer: self.renderer.clone(),
mime_override: self.mime_override.clone(), mime_override: self.mime_override.clone(),
path_filter: self.path_filter.clone(),
file_flags: self.file_flags, file_flags: self.file_flags,
guards: self.use_guards.clone(), guards: self.use_guards.clone(),
hidden_files: self.hidden_files, hidden_files: self.hidden_files,

View File

@ -21,6 +21,7 @@ use actix_web::{
http::header::DispositionType, http::header::DispositionType,
}; };
use mime_guess::from_ext; use mime_guess::from_ext;
use std::path::Path;
mod chunked; mod chunked;
mod directory; mod directory;
@ -56,6 +57,8 @@ 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;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::{ use std::{

View File

@ -13,7 +13,7 @@ use futures_core::future::LocalBoxFuture;
use crate::{ use crate::{
named, Directory, DirectoryRenderer, FilesError, HttpService, MimeOverride, NamedFile, named, Directory, DirectoryRenderer, FilesError, HttpService, MimeOverride, NamedFile,
PathBufWrap, PathBufWrap, PathFilter,
}; };
/// Assembled file serving service. /// Assembled file serving service.
@ -25,6 +25,7 @@ pub struct FilesService {
pub(crate) default: Option<HttpService>, pub(crate) default: Option<HttpService>,
pub(crate) renderer: Rc<DirectoryRenderer>, pub(crate) renderer: Rc<DirectoryRenderer>,
pub(crate) mime_override: Option<Rc<MimeOverride>>, pub(crate) mime_override: Option<Rc<MimeOverride>>,
pub(crate) path_filter: Option<Rc<PathFilter>>,
pub(crate) file_flags: named::Flags, pub(crate) file_flags: named::Flags,
pub(crate) guards: Option<Rc<dyn Guard>>, pub(crate) guards: Option<Rc<dyn Guard>>,
pub(crate) hidden_files: bool, pub(crate) hidden_files: bool,
@ -88,6 +89,18 @@ impl Service<ServiceRequest> for FilesService {
return Box::pin(self.handle_err(err, req)); return Box::pin(self.handle_err(err, req));
} }
if let Some(filter) = &self.path_filter {
if !filter(real_path.as_ref()) {
if let Some(ref default) = self.default {
return Box::pin(default.call(req));
} else {
return Box::pin(ok(
req.into_response(actix_web::HttpResponse::NotFound().finish())
));
}
}
}
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('/')