mirror of
https://github.com/actix/actix-web.git
synced 2024-12-21 15:46:48 +00:00
add support of filtering guards in Files of actix-files (#2046)
Co-authored-by: Rob Ede <robjtede@icloud.com>
This commit is contained in:
parent
07036b5640
commit
f44a0bc159
6 changed files with 91 additions and 7 deletions
|
@ -11,6 +11,9 @@
|
||||||
## 0.6.0-beta.4 - 2021-04-02
|
## 0.6.0-beta.4 - 2021-04-02
|
||||||
* No notable changes.
|
* No notable changes.
|
||||||
|
|
||||||
|
* Add support for `.guard` in `Files` to selectively filter `Files` services. [#2046]
|
||||||
|
|
||||||
|
[#2046]: https://github.com/actix/actix-web/pull/2046
|
||||||
|
|
||||||
## 0.6.0-beta.3 - 2021-03-09
|
## 0.6.0-beta.3 - 2021-03-09
|
||||||
* No notable changes.
|
* No notable changes.
|
||||||
|
|
|
@ -37,7 +37,8 @@ pub struct Files {
|
||||||
renderer: Rc<DirectoryRenderer>,
|
renderer: Rc<DirectoryRenderer>,
|
||||||
mime_override: Option<Rc<MimeOverride>>,
|
mime_override: Option<Rc<MimeOverride>>,
|
||||||
file_flags: named::Flags,
|
file_flags: named::Flags,
|
||||||
guards: Option<Rc<dyn Guard>>,
|
use_guards: Option<Rc<dyn Guard>>,
|
||||||
|
guards: Vec<Box<Rc<dyn Guard>>>,
|
||||||
hidden_files: bool,
|
hidden_files: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,12 +60,12 @@ 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(),
|
||||||
|
use_guards: self.use_guards.clone(),
|
||||||
guards: self.guards.clone(),
|
guards: self.guards.clone(),
|
||||||
hidden_files: self.hidden_files,
|
hidden_files: self.hidden_files,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Files {
|
impl Files {
|
||||||
/// Create new `Files` instance for a specified base directory.
|
/// Create new `Files` instance for a specified base directory.
|
||||||
///
|
///
|
||||||
|
@ -104,7 +105,8 @@ impl Files {
|
||||||
renderer: Rc::new(directory_listing),
|
renderer: Rc::new(directory_listing),
|
||||||
mime_override: None,
|
mime_override: None,
|
||||||
file_flags: named::Flags::default(),
|
file_flags: named::Flags::default(),
|
||||||
guards: None,
|
use_guards: None,
|
||||||
|
guards: Vec::new(),
|
||||||
hidden_files: false,
|
hidden_files: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,7 +187,28 @@ impl Files {
|
||||||
/// Default behaviour allows GET and HEAD.
|
/// Default behaviour allows GET and HEAD.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn use_guards<G: Guard + 'static>(mut self, guards: G) -> Self {
|
pub fn use_guards<G: Guard + 'static>(mut self, guards: G) -> Self {
|
||||||
self.guards = Some(Rc::new(guards));
|
self.use_guards = Some(Rc::new(guards));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add match guard to use on directory listings and files.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use actix_web::{guard, App};
|
||||||
|
/// use actix_files::Files;
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let app = App::new()
|
||||||
|
/// .service(
|
||||||
|
/// Files::new("/","/my/site/files")
|
||||||
|
/// .guard(guard::Header("Host", "example.com"))
|
||||||
|
/// );
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn guard<G: Guard + 'static>(mut self, guard: G) -> Self {
|
||||||
|
self.guards.push(Box::new(Rc::new(guard)));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,7 +261,19 @@ impl Files {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HttpServiceFactory for Files {
|
impl HttpServiceFactory for Files {
|
||||||
fn register(self, config: &mut AppService) {
|
fn register(mut self, config: &mut AppService) {
|
||||||
|
let guards = if self.guards.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let guards = std::mem::take(&mut self.guards);
|
||||||
|
Some(
|
||||||
|
guards
|
||||||
|
.into_iter()
|
||||||
|
.map(|guard| -> Box<dyn Guard> { guard })
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
if self.default.borrow().is_none() {
|
if self.default.borrow().is_none() {
|
||||||
*self.default.borrow_mut() = Some(config.default_service());
|
*self.default.borrow_mut() = Some(config.default_service());
|
||||||
}
|
}
|
||||||
|
@ -249,7 +284,7 @@ impl HttpServiceFactory for Files {
|
||||||
ResourceDef::prefix(&self.path)
|
ResourceDef::prefix(&self.path)
|
||||||
};
|
};
|
||||||
|
|
||||||
config.register_service(rdef, None, self, None)
|
config.register_service(rdef, guards, self, None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,7 +306,7 @@ impl ServiceFactory<ServiceRequest> for Files {
|
||||||
renderer: self.renderer.clone(),
|
renderer: self.renderer.clone(),
|
||||||
mime_override: self.mime_override.clone(),
|
mime_override: self.mime_override.clone(),
|
||||||
file_flags: self.file_flags,
|
file_flags: self.file_flags,
|
||||||
guards: self.guards.clone(),
|
guards: self.use_guards.clone(),
|
||||||
hidden_files: self.hidden_files,
|
hidden_files: self.hidden_files,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
1
actix-files/tests/fixtures/guards/first/index.txt
vendored
Normal file
1
actix-files/tests/fixtures/guards/first/index.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
first
|
1
actix-files/tests/fixtures/guards/second/index.txt
vendored
Normal file
1
actix-files/tests/fixtures/guards/second/index.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
second
|
36
actix-files/tests/guard.rs
Normal file
36
actix-files/tests/guard.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
use actix_files::Files;
|
||||||
|
use actix_web::{
|
||||||
|
guard::Host,
|
||||||
|
http::StatusCode,
|
||||||
|
test::{self, TestRequest},
|
||||||
|
App,
|
||||||
|
};
|
||||||
|
use bytes::Bytes;
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn test_guard_filter() {
|
||||||
|
let srv = test::init_service(
|
||||||
|
App::new()
|
||||||
|
.service(Files::new("/", "./tests/fixtures/guards/first").guard(Host("first.com")))
|
||||||
|
.service(
|
||||||
|
Files::new("/", "./tests/fixtures/guards/second").guard(Host("second.com")),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/index.txt")
|
||||||
|
.append_header(("Host", "first.com"))
|
||||||
|
.to_request();
|
||||||
|
let res = test::call_service(&srv, req).await;
|
||||||
|
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
assert_eq!(test::read_body(res).await, Bytes::from("first"));
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/index.txt")
|
||||||
|
.append_header(("Host", "second.com"))
|
||||||
|
.to_request();
|
||||||
|
let res = test::call_service(&srv, req).await;
|
||||||
|
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
assert_eq!(test::read_body(res).await, Bytes::from("second"));
|
||||||
|
}
|
|
@ -26,6 +26,8 @@
|
||||||
//! ```
|
//! ```
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use actix_http::http::{self, header, uri::Uri};
|
use actix_http::http::{self, header, uri::Uri};
|
||||||
use actix_http::RequestHead;
|
use actix_http::RequestHead;
|
||||||
|
@ -40,6 +42,12 @@ pub trait Guard {
|
||||||
fn check(&self, request: &RequestHead) -> bool;
|
fn check(&self, request: &RequestHead) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Guard for Rc<dyn Guard> {
|
||||||
|
fn check(&self, request: &RequestHead) -> bool {
|
||||||
|
self.deref().check(request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Create guard object for supplied function.
|
/// Create guard object for supplied function.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
|
Loading…
Reference in a new issue