mirror of
https://github.com/fafhrd91/actix-web
synced 2024-11-30 10:42:55 +01:00
feat(files): add possibility to redirect to slash-ended path (#1134)
When accessing to a folder without a final slash, the index file will be loaded ok, but if it has references (like a css or an image in an html file) these resources won't be loaded correctly if they are using relative paths. In order to solve this, this PR adds the possibility to detect folders without a final slash and make a 302 redirect to mitigate this issue. The behavior is off by default. We're adding a new method called `redirect_to_slash_directory` which can be used to enable this behavior.
This commit is contained in:
parent
effa96f5e4
commit
a48e616def
@ -1,5 +1,9 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
|
## [0.1.6] - TBD
|
||||||
|
|
||||||
|
* Add option to redirect to a slash-ended path `Files` #1132
|
||||||
|
|
||||||
## [0.1.5] - 2019-10-08
|
## [0.1.5] - 2019-10-08
|
||||||
|
|
||||||
* Bump up `mime_guess` crate version to 2.0.1
|
* Bump up `mime_guess` crate version to 2.0.1
|
||||||
@ -7,18 +11,15 @@
|
|||||||
* Bump up `percent-encoding` crate version to 2.1
|
* Bump up `percent-encoding` crate version to 2.1
|
||||||
|
|
||||||
* Allow user defined request guards for `Files` #1113
|
* Allow user defined request guards for `Files` #1113
|
||||||
|
|
||||||
|
|
||||||
## [0.1.4] - 2019-07-20
|
## [0.1.4] - 2019-07-20
|
||||||
|
|
||||||
* Allow to disable `Content-Disposition` header #686
|
* Allow to disable `Content-Disposition` header #686
|
||||||
|
|
||||||
|
|
||||||
## [0.1.3] - 2019-06-28
|
## [0.1.3] - 2019-06-28
|
||||||
|
|
||||||
* Do not set `Content-Length` header, let actix-http set it #930
|
* Do not set `Content-Length` header, let actix-http set it #930
|
||||||
|
|
||||||
|
|
||||||
## [0.1.2] - 2019-06-13
|
## [0.1.2] - 2019-06-13
|
||||||
|
|
||||||
* Content-Length is 0 for NamedFile HEAD request #914
|
* Content-Length is 0 for NamedFile HEAD request #914
|
||||||
|
@ -233,6 +233,7 @@ pub struct Files {
|
|||||||
directory: PathBuf,
|
directory: PathBuf,
|
||||||
index: Option<String>,
|
index: Option<String>,
|
||||||
show_index: bool,
|
show_index: bool,
|
||||||
|
redirect_to_slash: bool,
|
||||||
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>>,
|
||||||
@ -246,6 +247,7 @@ impl Clone for Files {
|
|||||||
directory: self.directory.clone(),
|
directory: self.directory.clone(),
|
||||||
index: self.index.clone(),
|
index: self.index.clone(),
|
||||||
show_index: self.show_index,
|
show_index: self.show_index,
|
||||||
|
redirect_to_slash: self.redirect_to_slash,
|
||||||
default: self.default.clone(),
|
default: self.default.clone(),
|
||||||
renderer: self.renderer.clone(),
|
renderer: self.renderer.clone(),
|
||||||
file_flags: self.file_flags,
|
file_flags: self.file_flags,
|
||||||
@ -273,6 +275,7 @@ impl Files {
|
|||||||
directory: dir,
|
directory: dir,
|
||||||
index: None,
|
index: None,
|
||||||
show_index: false,
|
show_index: false,
|
||||||
|
redirect_to_slash: false,
|
||||||
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,
|
||||||
@ -289,6 +292,14 @@ impl Files {
|
|||||||
self
|
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
|
/// Set custom directory renderer
|
||||||
pub fn files_listing_renderer<F>(mut self, f: F) -> Self
|
pub fn files_listing_renderer<F>(mut self, f: F) -> Self
|
||||||
where
|
where
|
||||||
@ -389,10 +400,10 @@ impl HttpServiceFactory for Files {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NewService for Files {
|
impl NewService for Files {
|
||||||
type Config = ();
|
|
||||||
type Request = ServiceRequest;
|
type Request = ServiceRequest;
|
||||||
type Response = ServiceResponse;
|
type Response = ServiceResponse;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
type Config = ();
|
||||||
type Service = FilesService;
|
type Service = FilesService;
|
||||||
type InitError = ();
|
type InitError = ();
|
||||||
type Future = Box<dyn Future<Item = Self::Service, Error = Self::InitError>>;
|
type Future = Box<dyn Future<Item = Self::Service, Error = Self::InitError>>;
|
||||||
@ -402,6 +413,7 @@ impl NewService for Files {
|
|||||||
directory: self.directory.clone(),
|
directory: self.directory.clone(),
|
||||||
index: self.index.clone(),
|
index: self.index.clone(),
|
||||||
show_index: self.show_index,
|
show_index: self.show_index,
|
||||||
|
redirect_to_slash: self.redirect_to_slash,
|
||||||
default: None,
|
default: None,
|
||||||
renderer: self.renderer.clone(),
|
renderer: self.renderer.clone(),
|
||||||
mime_override: self.mime_override.clone(),
|
mime_override: self.mime_override.clone(),
|
||||||
@ -429,6 +441,7 @@ pub struct FilesService {
|
|||||||
directory: PathBuf,
|
directory: PathBuf,
|
||||||
index: Option<String>,
|
index: Option<String>,
|
||||||
show_index: bool,
|
show_index: bool,
|
||||||
|
redirect_to_slash: bool,
|
||||||
default: Option<HttpService>,
|
default: Option<HttpService>,
|
||||||
renderer: Rc<DirectoryRenderer>,
|
renderer: Rc<DirectoryRenderer>,
|
||||||
mime_override: Option<Rc<MimeOverride>>,
|
mime_override: Option<Rc<MimeOverride>>,
|
||||||
@ -502,6 +515,16 @@ impl Service for FilesService {
|
|||||||
|
|
||||||
if path.is_dir() {
|
if path.is_dir() {
|
||||||
if let Some(ref redir_index) = self.index {
|
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);
|
let path = path.join(redir_index);
|
||||||
|
|
||||||
match NamedFile::open(path) {
|
match NamedFile::open(path) {
|
||||||
@ -1169,6 +1192,34 @@ mod tests {
|
|||||||
assert!(format!("{:?}", bytes).contains("/tests/test.png"));
|
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]
|
#[test]
|
||||||
fn test_static_files_bad_directory() {
|
fn test_static_files_bad_directory() {
|
||||||
let _st: Files = Files::new("/", "missing");
|
let _st: Files = Files::new("/", "missing");
|
||||||
|
Loading…
Reference in New Issue
Block a user