diff --git a/CHANGES.md b/CHANGES.md index c001707e3..bd00cb910 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,12 +4,14 @@ ### Changed * Bumped `rand` to `0.8` * Update `rust-tls` to `0.19.0` +* Rename `Handler` to `HandlerService` and rename `Factory` to `Handler`. [#1852] + ### Fixed * added the actual parsing error to `test::read_body_json` [#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 ### Fixed diff --git a/actix-files/CHANGES.md b/actix-files/CHANGES.md index e3f246488..3bb68e093 100644 --- a/actix-files/CHANGES.md +++ b/actix-files/CHANGES.md @@ -4,6 +4,12 @@ * 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 * Clarify order of parameters in `Files::new` and improve docs. diff --git a/actix-files/Cargo.toml b/actix-files/Cargo.toml index 3cd76215c..456a6f00e 100644 --- a/actix-files/Cargo.toml +++ b/actix-files/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-files" -version = "0.4.1" +version = "0.5.0" authors = ["Nikolay Kim "] description = "Static file serving for Actix Web" readme = "README.md" @@ -23,13 +23,13 @@ bitflags = "1" bytes = "1" futures-core = { version = "0.3.7", default-features = false } futures-util = { version = "0.3.7", default-features = false, features = ["sink"] } -derive_more = "0.99.2" +derive_more = "0.99.5" log = "0.4" mime = "0.3" mime_guess = "2.0.1" percent-encoding = "2.1" -v_htmlescape = "0.11" +v_htmlescape = "0.12" [dev-dependencies] actix-rt = "1.0.0" -actix-web = { version = "3.0.0", features = ["openssl"] } +actix-web = "3.0.0" diff --git a/actix-files/README.md b/actix-files/README.md index 685e5dbe5..2953b4458 100644 --- a/actix-files/README.md +++ b/actix-files/README.md @@ -3,11 +3,11 @@ > Static file serving for Actix Web [![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) ![License](https://img.shields.io/crates/l/actix-files.svg)
-[![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) [![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) diff --git a/actix-files/src/files.rs b/actix-files/src/files.rs index a99b4699e..d0cac6aa4 100644 --- a/actix-files/src/files.rs +++ b/actix-files/src/files.rs @@ -39,6 +39,7 @@ pub struct Files { mime_override: Option>, file_flags: named::Flags, guards: Option>, + hidden_files: bool, } impl fmt::Debug for Files { @@ -60,6 +61,7 @@ impl Clone for Files { path: self.path.clone(), mime_override: self.mime_override.clone(), guards: self.guards.clone(), + hidden_files: self.hidden_files, } } } @@ -103,6 +105,7 @@ impl Files { mime_override: None, file_flags: named::Flags::default(), guards: None, + hidden_files: false, } } @@ -213,6 +216,13 @@ impl Files { 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 { @@ -251,6 +261,7 @@ impl ServiceFactory for Files { mime_override: self.mime_override.clone(), file_flags: self.file_flags, guards: self.guards.clone(), + hidden_files: self.hidden_files, }; if let Some(ref default) = *self.default.borrow() { diff --git a/actix-files/src/path_buf.rs b/actix-files/src/path_buf.rs index 2f3ae84d4..dd8e5b503 100644 --- a/actix-files/src/path_buf.rs +++ b/actix-files/src/path_buf.rs @@ -15,12 +15,19 @@ impl FromStr for PathBufWrap { type Err = UriSegmentError; fn from_str(path: &str) -> Result { + 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 { let mut buf = PathBuf::new(); for segment in path.split('/') { if segment == ".." { buf.pop(); - } else if segment.starts_with('.') { + } else if !hidden_files && segment.starts_with('.') { return Err(UriSegmentError::BadStart('.')); } else if segment.starts_with('*') { return Err(UriSegmentError::BadStart('*')); @@ -96,4 +103,17 @@ mod tests { 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"]) + ); + } } diff --git a/actix-files/src/service.rs b/actix-files/src/service.rs index cbf4c2d3b..dc4f2bd2c 100644 --- a/actix-files/src/service.rs +++ b/actix-files/src/service.rs @@ -31,6 +31,7 @@ pub struct FilesService { pub(crate) mime_override: Option>, pub(crate) file_flags: named::Flags, pub(crate) guards: Option>, + pub(crate) hidden_files: bool, } type FilesServiceFuture = Either< @@ -83,10 +84,11 @@ impl Service for FilesService { ))); } - let real_path: PathBufWrap = match req.match_info().path().parse() { - Ok(item) => item, - Err(e) => return Either::Left(ok(req.error_response(e))), - }; + let real_path = + match PathBufWrap::parse_path(req.match_info().path(), self.hidden_files) { + Ok(item) => item, + Err(e) => return Either::Left(ok(req.error_response(e))), + }; // full file path let path = match self.directory.join(&real_path).canonicalize() { diff --git a/src/handler.rs b/src/handler.rs index 26ec95f8d..a5f65a8d9 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -14,7 +14,12 @@ use crate::request::HttpRequest; use crate::responder::Responder; 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: Clone + 'static where R: Future, @@ -55,7 +60,7 @@ where R::Output: Responder, { pub fn new(hnd: F) -> Self { - HandlerService { + Self { hnd, _t: PhantomData, } @@ -70,7 +75,7 @@ where R::Output: Responder, { fn clone(&self) -> Self { - HandlerService { + Self { hnd: self.hnd.clone(), _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 Service for HandlerService where F: Handler,