diff --git a/actix-files/CHANGES.md b/actix-files/CHANGES.md index 5999f276..5eb4e9a6 100644 --- a/actix-files/CHANGES.md +++ b/actix-files/CHANGES.md @@ -1,5 +1,9 @@ # Changes +## [0.1.6] - TBD + +* Add option to redirect to a slash-ended path `Files` #1132 + ## [0.1.5] - 2019-10-08 * Bump up `mime_guess` crate version to 2.0.1 @@ -7,18 +11,15 @@ * Bump up `percent-encoding` crate version to 2.1 * Allow user defined request guards for `Files` #1113 - - + ## [0.1.4] - 2019-07-20 * Allow to disable `Content-Disposition` header #686 - ## [0.1.3] - 2019-06-28 * Do not set `Content-Length` header, let actix-http set it #930 - ## [0.1.2] - 2019-06-13 * Content-Length is 0 for NamedFile HEAD request #914 diff --git a/actix-files/src/lib.rs b/actix-files/src/lib.rs index 1cc26629..61674ca3 100644 --- a/actix-files/src/lib.rs +++ b/actix-files/src/lib.rs @@ -233,6 +233,7 @@ pub struct Files { directory: PathBuf, index: Option, show_index: bool, + redirect_to_slash: bool, default: Rc>>>, renderer: Rc, mime_override: Option>, @@ -246,6 +247,7 @@ impl Clone for Files { directory: self.directory.clone(), index: self.index.clone(), show_index: self.show_index, + redirect_to_slash: self.redirect_to_slash, default: self.default.clone(), renderer: self.renderer.clone(), file_flags: self.file_flags, @@ -273,6 +275,7 @@ impl Files { directory: dir, index: None, show_index: false, + redirect_to_slash: false, default: Rc::new(RefCell::new(None)), renderer: Rc::new(directory_listing), mime_override: None, @@ -289,6 +292,14 @@ impl Files { self } + /// Redirects to a slash-ended path when browsing a directory. + /// + /// By default never redirect. + pub fn redirect_to_slash_directory(mut self) -> Self { + self.redirect_to_slash = true; + self + } + /// Set custom directory renderer pub fn files_listing_renderer(mut self, f: F) -> Self where @@ -389,10 +400,10 @@ impl HttpServiceFactory for Files { } impl NewService for Files { - type Config = (); type Request = ServiceRequest; type Response = ServiceResponse; type Error = Error; + type Config = (); type Service = FilesService; type InitError = (); type Future = Box>; @@ -402,6 +413,7 @@ impl NewService for Files { directory: self.directory.clone(), index: self.index.clone(), show_index: self.show_index, + redirect_to_slash: self.redirect_to_slash, default: None, renderer: self.renderer.clone(), mime_override: self.mime_override.clone(), @@ -429,6 +441,7 @@ pub struct FilesService { directory: PathBuf, index: Option, show_index: bool, + redirect_to_slash: bool, default: Option, renderer: Rc, mime_override: Option>, @@ -502,6 +515,16 @@ impl Service for FilesService { if path.is_dir() { if let Some(ref redir_index) = self.index { + if self.redirect_to_slash && !req.path().ends_with('/') { + let redirect_to = format!("{}/", req.path()); + return Either::A(ok(req.into_response( + HttpResponse::Found() + .header(header::LOCATION, redirect_to) + .body("") + .into_body(), + ))); + } + let path = path.join(redir_index); match NamedFile::open(path) { @@ -1169,6 +1192,34 @@ mod tests { assert!(format!("{:?}", bytes).contains("/tests/test.png")); } + #[test] + fn test_redirect_to_slash_directory() { + // should not redirect if no index + let mut srv = test::init_service( + App::new().service(Files::new("/", ".").redirect_to_slash_directory()), + ); + let req = TestRequest::with_uri("/tests").to_request(); + let resp = test::call_service(&mut srv, req); + assert_eq!(resp.status(), StatusCode::NOT_FOUND); + + // should redirect if index present + let mut srv = test::init_service( + App::new().service( + Files::new("/", ".") + .index_file("test.png") + .redirect_to_slash_directory(), + ), + ); + let req = TestRequest::with_uri("/tests").to_request(); + let resp = test::call_service(&mut srv, req); + assert_eq!(resp.status(), StatusCode::FOUND); + + // should not redirect if the path is wrong + let req = TestRequest::with_uri("/not_existing").to_request(); + let resp = test::call_service(&mut srv, req); + assert_eq!(resp.status(), StatusCode::NOT_FOUND); + } + #[test] fn test_static_files_bad_directory() { let _st: Files = Files::new("/", "missing");