From 5926c9b27c5625398c7588c71588b433cffaff5b Mon Sep 17 00:00:00 2001 From: Jose Quintana Date: Sat, 1 Jan 2022 22:54:53 +0100 Subject: [PATCH] refactor: trailing slash redirection for directories it check for a trailing slash on the current directory uri and redirect permanently (308) if that path doesn't end with the slash char resolves #73 --- src/static_files.rs | 44 +++++++++++++++++++++++--------------------- tests/static_files.rs | 43 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 63 insertions(+), 24 deletions(-) diff --git a/src/static_files.rs b/src/static_files.rs index dbae39c..2433187 100644 --- a/src/static_files.rs +++ b/src/static_files.rs @@ -58,30 +58,32 @@ pub async fn handle( let base = Arc::new(base_path.into()); let (filepath, meta, auto_index) = path_from_tail(base, uri_path).await?; + // NOTE: `auto_index` appends an `index.html` to an `uri_path` of kind directory only. + + // Check for a trailing slash on the current directory path + // and redirect if that path doesn't end with the slash char + if auto_index && !uri_path.ends_with('/') { + let uri = [uri_path, "/"].concat(); + let loc = match HeaderValue::from_str(uri.as_str()) { + Ok(val) => val, + Err(err) => { + tracing::error!("invalid header value from current uri: {:?}", err); + return Err(StatusCode::INTERNAL_SERVER_ERROR); + } + }; + + let mut resp = Response::new(Body::empty()); + resp.headers_mut().insert(hyper::header::LOCATION, loc); + *resp.status_mut() = StatusCode::PERMANENT_REDIRECT; + tracing::trace!("uri doesn't end with a slash so redirecting permanently"); + return Ok(resp); + } + // Directory listing - // 1. Check if "directory listing" feature is enabled, + // 1. Check if "directory listing" feature is enabled // if current path is a valid directory and - // if it does not contain an `index.html` file + // if it does not contain an `index.html` file (if a proper auto index is generated) if dir_listing && auto_index && !filepath.as_ref().exists() { - // Redirect if current path does not end with a slash char - if !uri_path.ends_with('/') { - let uri = [uri_path, "/"].concat(); - let loc = match HeaderValue::from_str(uri.as_str()) { - Ok(val) => val, - Err(err) => { - tracing::error!("invalid header value from current uri: {:?}", err); - return Err(StatusCode::INTERNAL_SERVER_ERROR); - } - }; - - let mut resp = Response::new(Body::empty()); - resp.headers_mut().insert(hyper::header::LOCATION, loc); - *resp.status_mut() = StatusCode::PERMANENT_REDIRECT; - tracing::trace!("uri doesn't end with a slash so redirect permanently"); - - return Ok(resp); - } - return directory_listing( method, uri_path, diff --git a/tests/static_files.rs b/tests/static_files.rs index 9631cd1..9bc8735 100644 --- a/tests/static_files.rs +++ b/tests/static_files.rs @@ -116,6 +116,30 @@ mod tests { } #[tokio::test] + async fn handle_trailing_slash_redirection() { + let mut res = static_files::handle( + &Method::GET, + &HeaderMap::new(), + root_dir(), + "assets", + None, + false, + 0, + ) + .await + .expect("unexpected error response on `handle` function"); + + assert_eq!(res.status(), 308); + assert_eq!(res.headers()["location"], "assets/"); + + let body = hyper::body::to_bytes(res.body_mut()) + .await + .expect("unexpected bytes error during `body` conversion"); + + assert_eq!(body, Bytes::new()); + } + + #[tokio::test] async fn handle_append_index_on_dir() { let buf = fs::read(root_dir().join("index.html")) .expect("unexpected error during index.html reading"); @@ -134,9 +158,22 @@ mod tests { ) .await { - Ok(res) => { - assert_eq!(res.status(), 200); - assert_eq!(res.headers()["content-length"], buf.len().to_string()); + Ok(mut res) => { + if uri.is_empty() { + // it should redirect permanently + assert_eq!(res.status(), 308); + assert_eq!(res.headers()["location"], "/"); + + let body = hyper::body::to_bytes(res.body_mut()) + .await + .expect("unexpected bytes error during `body` conversion"); + + assert_eq!(body, Bytes::new()); + } else { + // otherwise it should response with ok + assert_eq!(res.status(), 200); + assert_eq!(res.headers()["content-length"], buf.len().to_string()); + } } Err(_) => { panic!("expected a status 200 but not a status error") -- libgit2 1.7.2