mirror of https://github.com/fafhrd91/actix-web
impl
This commit is contained in:
parent
f81d4bdae7
commit
2f340607c0
|
@ -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,
|
||||||
|
|
|
@ -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::{
|
||||||
|
|
|
@ -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('/')
|
||||||
|
|
Loading…
Reference in New Issue