+## Relative paths for entries
+
+SWS uses relative paths for the directory listing entries (file or directory) and is used regardless of the [redirect trailing slash](../features/trailing-slash-redirect.md) feature.
+
+However, when the *"redirect trailing slash"* feature is disabled and a directory request URI doesn't contain a trailing slash then the entries will contain the path `parent-dir/entry-name` as the link value. Otherwise, just an `entry-name` link value is used (default behavior).
+
+Note also that in both cases, SWS will append a trailing slash to the entry if is a directory.
+
+
## Sorting
Sorting by `Name`, `Last modified` and `Size` is enabled as clickable columns when the directory listing is activated via the `--directory-listing=true` option.
diff --git a/src/static_files.rs b/src/static_files.rs
index f612b7b..f0cfae7 100644
--- a/src/static_files.rs
+++ b/src/static_files.rs
@@ -145,8 +145,8 @@ fn path_from_tail(
}
/// Provides directory listing support for the current request.
-/// Note that this function is a highly dependent on `path_from_tail()`
-// function which must be called first. See `handle()` more for details.
+/// Note that this function highly depends on `path_from_tail()` function
+/// which must be called first. See `handle()` for more details.
fn directory_listing<'a>(
method: &'a Method,
current_path: &'a str,
@@ -209,7 +209,8 @@ fn directory_listing<'a>(
})
}
-// It reads current directory entries and create the index page content. Otherwise returns a status error.
+/// It reads the current directory entries and create an index page content.
+/// Otherwise it returns a status error.
async fn read_directory_entries(
mut entries: tokio::fs::ReadDir,
base_path: &str,
@@ -219,7 +220,7 @@ async fn read_directory_entries(
) -> Result, + { + PathBuf::from(dir) } #[tokio::test] - async fn dir_listing_redirect_permanent_uri() { - let methods = [ - Method::CONNECT, - Method::DELETE, - Method::GET, - Method::HEAD, - Method::PATCH, - Method::POST, - Method::PUT, - Method::TRACE, - ]; - for method in methods { + async fn dir_listing_redirect_trailing_slash_dir() { + for method in METHODS { match static_files::handle(&HandleOpts { method: &method, headers: &HeaderMap::new(), - base_path: &root_dir(), + base_path: &root_dir("docker/public/"), uri_path: "/assets", uri_query: None, dir_listing: true, @@ -51,4 +55,105 @@ mod tests { } } } + + #[tokio::test] + async fn dir_listing_redirect_trailing_slash_relative_dir_path() { + for method in METHODS { + match static_files::handle(&HandleOpts { + method: &method, + headers: &HeaderMap::new(), + base_path: &root_dir("docs/"), + uri_path: "/content/", + uri_query: None, + dir_listing: true, + dir_listing_order: 6, + redirect_trailing_slash: true, + }) + .await + { + Ok(mut res) => { + assert_eq!(res.status(), 200); + assert_eq!(res.headers()["content-type"], "text/html; charset=utf-8"); + + let body = hyper::body::to_bytes(res.body_mut()) + .await + .expect("unexpected bytes error during `body` conversion"); + let body_str = std::str::from_utf8(&body).unwrap(); + // directory link should only contain "dir-name/" in a relative way + assert_eq!( + body_str.contains(r#"href="features/""#), + method == Method::GET + ); + } + Err(status) => { + assert!(method != Method::GET && method != Method::HEAD); + assert_eq!(status, StatusCode::METHOD_NOT_ALLOWED); + } + } + } + } + + #[tokio::test] + async fn dir_listing_no_redirect_trailing_slash_relative_dir_path() { + for method in METHODS { + match static_files::handle(&HandleOpts { + method: &method, + headers: &HeaderMap::new(), + base_path: &root_dir("docs/"), + uri_path: "/content", + uri_query: None, + dir_listing: true, + dir_listing_order: 6, + redirect_trailing_slash: false, + }) + .await + { + Ok(mut res) => { + assert_eq!(res.status(), 200); + assert_eq!(res.headers()["content-type"], "text/html; charset=utf-8"); + + let body = hyper::body::to_bytes(res.body_mut()) + .await + .expect("unexpected bytes error during `body` conversion"); + let body_str = std::str::from_utf8(&body).unwrap(); + // directory link should contain "parent/dir-name/" in a relative way + assert_eq!( + body_str.contains(r#"href="content/features/""#), + method == Method::GET + ); + } + Err(status) => { + assert!(method != Method::GET && method != Method::HEAD); + assert_eq!(status, StatusCode::METHOD_NOT_ALLOWED); + } + } + } + } + + #[tokio::test] + async fn dir_listing_no_redirect_trailing_slash_relative_file_path() { + for method in METHODS { + match static_files::handle(&HandleOpts { + method: &method, + headers: &HeaderMap::new(), + base_path: &root_dir("docs/"), + uri_path: "/README.md", + uri_query: None, + dir_listing: true, + dir_listing_order: 6, + redirect_trailing_slash: false, + }) + .await + { + Ok(res) => { + assert_eq!(res.status(), 200); + assert_eq!(res.headers()["content-type"], "text/markdown"); + } + Err(status) => { + assert!(method != Method::GET && method != Method::HEAD); + assert_eq!(status, StatusCode::METHOD_NOT_ALLOWED); + } + } + } + } } -- libgit2 1.7.2