merge master into branch tokio0.3

This commit is contained in:
fakeshadow 2020-12-27 06:53:10 +08:00
commit d42490d5a0
8 changed files with 62 additions and 16 deletions

View File

@ -4,12 +4,14 @@
### Changed ### Changed
* Bumped `rand` to `0.8` * Bumped `rand` to `0.8`
* Update `rust-tls` to `0.19.0` * Update `rust-tls` to `0.19.0`
* Rename `Handler` to `HandlerService` and rename `Factory` to `Handler`. [#1852]
### Fixed ### Fixed
* added the actual parsing error to `test::read_body_json` [#1812] * added the actual parsing error to `test::read_body_json` [#1812]
[#1812]: https://github.com/actix/actix-web/pull/1812 [#1812]: https://github.com/actix/actix-web/pull/1812
[#1852]: https://github.com/actix/actix-web/pull/1852
## 3.3.2 - 2020-12-01 ## 3.3.2 - 2020-12-01
### Fixed ### Fixed

View File

@ -4,6 +4,12 @@
* Update `bytes` to `1`. * Update `bytes` to `1`.
## 0.5.0 - 2020-12-26
* Optionally support hidden files/directories. [#1811]
[#1811]: https://github.com/actix/actix-web/pull/1811
## 0.4.1 - 2020-11-24 ## 0.4.1 - 2020-11-24
* Clarify order of parameters in `Files::new` and improve docs. * Clarify order of parameters in `Files::new` and improve docs.

View File

@ -1,6 +1,6 @@
[package] [package]
name = "actix-files" name = "actix-files"
version = "0.4.1" version = "0.5.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"] authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Static file serving for Actix Web" description = "Static file serving for Actix Web"
readme = "README.md" readme = "README.md"
@ -23,13 +23,13 @@ bitflags = "1"
bytes = "1" bytes = "1"
futures-core = { version = "0.3.7", default-features = false } futures-core = { version = "0.3.7", default-features = false }
futures-util = { version = "0.3.7", default-features = false, features = ["sink"] } futures-util = { version = "0.3.7", default-features = false, features = ["sink"] }
derive_more = "0.99.2" derive_more = "0.99.5"
log = "0.4" log = "0.4"
mime = "0.3" mime = "0.3"
mime_guess = "2.0.1" mime_guess = "2.0.1"
percent-encoding = "2.1" percent-encoding = "2.1"
v_htmlescape = "0.11" v_htmlescape = "0.12"
[dev-dependencies] [dev-dependencies]
actix-rt = "1.0.0" actix-rt = "1.0.0"
actix-web = { version = "3.0.0", features = ["openssl"] } actix-web = "3.0.0"

View File

@ -3,11 +3,11 @@
> Static file serving for Actix Web > Static file serving for Actix Web
[![crates.io](https://img.shields.io/crates/v/actix-files?label=latest)](https://crates.io/crates/actix-files) [![crates.io](https://img.shields.io/crates/v/actix-files?label=latest)](https://crates.io/crates/actix-files)
[![Documentation](https://docs.rs/actix-files/badge.svg?version=0.4.1)](https://docs.rs/actix-files/0.4.1) [![Documentation](https://docs.rs/actix-files/badge.svg?version=0.5.0)](https://docs.rs/actix-files/0.5.0)
[![Version](https://img.shields.io/badge/rustc-1.42+-ab6000.svg)](https://blog.rust-lang.org/2020/03/12/Rust-1.42.html) [![Version](https://img.shields.io/badge/rustc-1.42+-ab6000.svg)](https://blog.rust-lang.org/2020/03/12/Rust-1.42.html)
![License](https://img.shields.io/crates/l/actix-files.svg) ![License](https://img.shields.io/crates/l/actix-files.svg)
<br /> <br />
[![dependency status](https://deps.rs/crate/actix-files/0.4.1/status.svg)](https://deps.rs/crate/actix-files/0.4.1) [![dependency status](https://deps.rs/crate/actix-files/0.5.0/status.svg)](https://deps.rs/crate/actix-files/0.5.0)
[![Download](https://img.shields.io/crates/d/actix-files.svg)](https://crates.io/crates/actix-files) [![Download](https://img.shields.io/crates/d/actix-files.svg)](https://crates.io/crates/actix-files)
[![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

View File

@ -39,6 +39,7 @@ pub struct Files {
mime_override: Option<Rc<MimeOverride>>, mime_override: Option<Rc<MimeOverride>>,
file_flags: named::Flags, file_flags: named::Flags,
guards: Option<Rc<dyn Guard>>, guards: Option<Rc<dyn Guard>>,
hidden_files: bool,
} }
impl fmt::Debug for Files { impl fmt::Debug for Files {
@ -60,6 +61,7 @@ impl Clone for Files {
path: self.path.clone(), path: self.path.clone(),
mime_override: self.mime_override.clone(), mime_override: self.mime_override.clone(),
guards: self.guards.clone(), guards: self.guards.clone(),
hidden_files: self.hidden_files,
} }
} }
} }
@ -103,6 +105,7 @@ impl Files {
mime_override: None, mime_override: None,
file_flags: named::Flags::default(), file_flags: named::Flags::default(),
guards: None, guards: None,
hidden_files: false,
} }
} }
@ -213,6 +216,13 @@ impl Files {
self self
} }
/// Enables serving hidden files and directories, allowing a leading dots in url fragments.
#[inline]
pub fn use_hidden_files(mut self) -> Self {
self.hidden_files = true;
self
}
} }
impl HttpServiceFactory for Files { impl HttpServiceFactory for Files {
@ -251,6 +261,7 @@ impl ServiceFactory for Files {
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.guards.clone(),
hidden_files: self.hidden_files,
}; };
if let Some(ref default) = *self.default.borrow() { if let Some(ref default) = *self.default.borrow() {

View File

@ -15,12 +15,19 @@ impl FromStr for PathBufWrap {
type Err = UriSegmentError; type Err = UriSegmentError;
fn from_str(path: &str) -> Result<Self, Self::Err> { fn from_str(path: &str) -> Result<Self, Self::Err> {
Self::parse_path(path, false)
}
}
impl PathBufWrap {
/// Parse a path, giving the choice of allowing hidden files to be considered valid segments.
pub fn parse_path(path: &str, hidden_files: bool) -> Result<Self, UriSegmentError> {
let mut buf = PathBuf::new(); let mut buf = PathBuf::new();
for segment in path.split('/') { for segment in path.split('/') {
if segment == ".." { if segment == ".." {
buf.pop(); buf.pop();
} else if segment.starts_with('.') { } else if !hidden_files && segment.starts_with('.') {
return Err(UriSegmentError::BadStart('.')); return Err(UriSegmentError::BadStart('.'));
} else if segment.starts_with('*') { } else if segment.starts_with('*') {
return Err(UriSegmentError::BadStart('*')); return Err(UriSegmentError::BadStart('*'));
@ -96,4 +103,17 @@ mod tests {
PathBuf::from_iter(vec!["seg2"]) PathBuf::from_iter(vec!["seg2"])
); );
} }
#[test]
fn test_parse_path() {
assert_eq!(
PathBufWrap::parse_path("/test/.tt", false).map(|t| t.0),
Err(UriSegmentError::BadStart('.'))
);
assert_eq!(
PathBufWrap::parse_path("/test/.tt", true).unwrap().0,
PathBuf::from_iter(vec!["test", ".tt"])
);
}
} }

View File

@ -31,6 +31,7 @@ pub struct FilesService {
pub(crate) mime_override: Option<Rc<MimeOverride>>, pub(crate) mime_override: Option<Rc<MimeOverride>>,
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,
} }
type FilesServiceFuture = Either< type FilesServiceFuture = Either<
@ -83,10 +84,11 @@ impl Service for FilesService {
))); )));
} }
let real_path: PathBufWrap = match req.match_info().path().parse() { let real_path =
Ok(item) => item, match PathBufWrap::parse_path(req.match_info().path(), self.hidden_files) {
Err(e) => return Either::Left(ok(req.error_response(e))), Ok(item) => item,
}; Err(e) => return Either::Left(ok(req.error_response(e))),
};
// full file path // full file path
let path = match self.directory.join(&real_path).canonicalize() { let path = match self.directory.join(&real_path).canonicalize() {

View File

@ -14,7 +14,12 @@ use crate::request::HttpRequest;
use crate::responder::Responder; use crate::responder::Responder;
use crate::service::{ServiceRequest, ServiceResponse}; use crate::service::{ServiceRequest, ServiceResponse};
/// Async handler converter factory /// A request handler is an async function that accepts zero or more parameters that can be
/// extracted from a request (ie, [`impl FromRequest`](crate::FromRequest)) and returns a type that can be converted into
/// an [`HttpResponse`](crate::HttpResponse) (ie, [`impl Responder`](crate::Responder)).
///
/// If you got the error `the trait Handler<_, _, _> is not implemented`, then your function is not
/// a valid handler. See [Request Handlers](https://actix.rs/docs/handlers/) for more information.
pub trait Handler<T, R>: Clone + 'static pub trait Handler<T, R>: Clone + 'static
where where
R: Future, R: Future,
@ -55,7 +60,7 @@ where
R::Output: Responder, R::Output: Responder,
{ {
pub fn new(hnd: F) -> Self { pub fn new(hnd: F) -> Self {
HandlerService { Self {
hnd, hnd,
_t: PhantomData, _t: PhantomData,
} }
@ -70,7 +75,7 @@ where
R::Output: Responder, R::Output: Responder,
{ {
fn clone(&self) -> Self { fn clone(&self) -> Self {
HandlerService { Self {
hnd: self.hnd.clone(), hnd: self.hnd.clone(),
_t: PhantomData, _t: PhantomData,
} }
@ -97,7 +102,7 @@ where
} }
} }
// Handler is both it's ServiceFactory and Service Type. // HandlerService is both it's ServiceFactory and Service Type.
impl<F, T, R> Service for HandlerService<F, T, R> impl<F, T, R> Service for HandlerService<F, T, R>
where where
F: Handler<T, R>, F: Handler<T, R>,