refactor: simplify public dir for docker image & default error pages (#579)

This commit is contained in:
Jose Quintana
2025-11-15 21:48:54 +01:00
committed by GitHub
parent 326abbe7d5
commit d48da4ca06
15 changed files with 115 additions and 98 deletions

View File

@@ -50,7 +50,7 @@ compression-deflate = ["async-compression/deflate"]
compression-gzip = ["async-compression/deflate"]
compression-zstd = ["async-compression/zstd"]
# Directory listing
directory-listing = ["chrono", "maud"]
directory-listing = ["chrono"]
# Directory listing download
directory-listing-download = ["async-tar", "compression-gzip", "directory-listing"]
# Basic HTTP Authorization
@@ -81,7 +81,7 @@ http-serde = "1.1"
hyper = { version = "0.14", features = ["stream", "http1", "http2", "tcp", "server"] }
lazy_static = "1.5"
listenfd = "1.0"
maud = { version = "0.27", optional = true }
maud = { version = "0.27" }
mime_guess = "2.0"
mini-moka = { version = "0.10.3", optional = true }
percent-encoding = "2.3"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -3,13 +3,16 @@
<head>
<meta charset="utf-8">
<title>Static Web Server</title>
<link rel="stylesheet" href="/assets/main.css">
<link rel="shortcut icon" href="/assets/favicon.ico">
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
<style>
html { color-scheme: light dark; }
body { font-family: sans-serif; text-align: center; }
</style>
</head>
<body>
<h1>Static Web Server</h1>
<p>A cross-platform, high-performance and asynchronous web server for static files-serving.</p>
<p><a href="https://github.com/static-web-server/static-web-server/" target="_blank">View on GitHub</a></p>
<script src="/assets/main.js"></script>
<h4>A cross-platform, high-performance and asynchronous web server for static files-serving ⚡</h4>
<p><small>Visit <a href="https://static-web-server.net" target="_blank">static-web-server.net</a> for documentation and support.</small>
</p>
</body>
</html>

View File

@@ -8,6 +8,7 @@
use headers::{AcceptRanges, ContentLength, ContentType, HeaderMapExt};
use hyper::{Body, Method, Response, StatusCode, Uri};
use maud::{DOCTYPE, html};
use mime_guess::mime;
use std::path::Path;
@@ -91,18 +92,29 @@ pub fn error_response(
};
if page_content.is_empty() {
page_content = [
"<html><head><title>",
status_code.as_str(),
" ",
status_code.canonical_reason().unwrap_or_default(),
"</title></head><body><center><h1>",
status_code.as_str(),
" ",
status_code.canonical_reason().unwrap_or_default(),
"</h1></center></body></html>",
]
.concat();
let reason = status_code.canonical_reason().unwrap_or_default();
let title = [status_code.as_str(), " ", reason].concat();
page_content = html! {
(DOCTYPE)
html {
head {
meta charset="utf-8";
meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1";
title {
(title)
}
style {
"html { color-scheme: light dark; } body { font-family: sans-serif; text-align: center; }"
}
}
body {
h1 {
(title)
}
}
}
}.into();
}
let mut body = Body::empty();

View File

@@ -217,7 +217,7 @@ mod tests {
);
*req.method_mut() = method.clone();
*req.headers_mut() = headers;
*req.uri_mut() = "http://localhost/assets/index.html".parse().unwrap();
*req.uri_mut() = "http://localhost/index.html".parse().unwrap();
match req_handler.handle(&mut req, remote_addr).await {
Ok(resp) => {

View File

@@ -43,8 +43,8 @@ mod tests {
match static_files::handle(&HandleOpts {
method: &method,
headers: &HeaderMap::new(),
base_path: &root_dir("docker/public/"),
uri_path: "/assets",
base_path: &root_dir("tests/fixtures/public"),
uri_path: "/symlink",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -64,7 +64,7 @@ mod tests {
Ok(result) => {
let res = result.resp;
assert_eq!(res.status(), 308);
assert_eq!(res.headers()["location"], "/assets/");
assert_eq!(res.headers()["location"], "/symlink/");
}
Err(status) => {
assert!(method != Method::GET && method != Method::HEAD);
@@ -299,7 +299,7 @@ mod tests {
if method == Method::GET {
let entries: Vec<FileEntry> = serde_json::from_str(body_str).unwrap();
assert_eq!(entries.len(), 6);
assert_eq!(entries.len(), 9);
let first_entry = entries.first().unwrap();
assert_eq!(first_entry.name, "symlink");
@@ -308,7 +308,7 @@ mod tests {
assert!(first_entry.size.is_none());
let last_entry = entries.last().unwrap();
assert_eq!(last_entry.name, "404.html.br");
assert_eq!(last_entry.name, "404.html");
assert_eq!(last_entry.typed, "file");
assert!(!last_entry.mtime.is_empty());
assert!(last_entry.size.unwrap() > 60);

View File

@@ -1,6 +1,6 @@
[general]
root = "docker/public"
root = "tests/fixtures/public"
[advanced]

View File

@@ -65,7 +65,7 @@ pub mod tests {
let mut req = Request::default();
*req.method_mut() = hyper::Method::GET;
*req.uri_mut() = "http://localhost/assets/index.html".parse().unwrap();
*req.uri_mut() = "http://localhost/index.html".parse().unwrap();
match req_handler.handle(&mut req, remote_addr).await {
Ok(res) => {
@@ -122,7 +122,7 @@ pub mod tests {
for method in methods {
let mut req = Request::default();
*req.method_mut() = method.clone();
*req.uri_mut() = "http://localhost/assets/index.html".parse().unwrap();
*req.uri_mut() = "http://localhost/index.html".parse().unwrap();
match req_handler.handle(&mut req, remote_addr).await {
Ok(res) => {

View File

@@ -14,7 +14,8 @@ pub mod tests {
#[tokio::test]
async fn rewrites_skipped() {
let opts = fixture_settings("toml/rewrites.toml");
let mut opts = fixture_settings("toml/rewrites.toml");
opts.general.index_files = "index.htm".to_owned();
let req_handler_opts = fixture_req_handler_opts(opts.general, opts.advanced);
let req_handler = fixture_req_handler(req_handler_opts);
let remote_addr = Some(REMOTE_ADDR.parse::<SocketAddr>().unwrap());

View File

@@ -25,7 +25,7 @@ mod tests {
use static_web_server::static_files::{self, HandleOpts};
fn root_dir() -> PathBuf {
PathBuf::from("docker/public/")
PathBuf::from("tests/fixtures/public/")
}
const METHODS: [Method; 8] = [
@@ -45,7 +45,7 @@ mod tests {
method: &Method::GET,
headers: &HeaderMap::new(),
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "index.htm",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -61,13 +61,13 @@ mod tests {
compression_static: false,
ignore_hidden_files: false,
disable_symlinks: false,
index_files: &[],
index_files: &["index.htm"],
})
.await
.expect("unexpected error response on `handle` function");
let mut res = result.resp;
let buf = fs::read(root_dir().join("index.html"))
let buf = fs::read(root_dir().join("index.htm"))
.expect("unexpected error during index.html reading");
let buf = Bytes::from(buf);
@@ -93,7 +93,7 @@ mod tests {
method: &Method::HEAD,
headers: &HeaderMap::new(),
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "index.htm",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -109,13 +109,13 @@ mod tests {
compression_static: false,
ignore_hidden_files: false,
disable_symlinks: false,
index_files: &[],
index_files: &["index.htm"],
})
.await
.expect("unexpected error response on `handle` function");
let mut res = result.resp;
let buf = fs::read(root_dir().join("index.html"))
let buf = fs::read(root_dir().join("index.htm"))
.expect("unexpected error during index.html reading");
let buf = Bytes::from(buf);
@@ -158,7 +158,7 @@ mod tests {
compression_static: false,
ignore_hidden_files: false,
disable_symlinks: false,
index_files: &[],
index_files: &["index.htm"],
})
.await
{
@@ -194,7 +194,7 @@ mod tests {
compression_static: false,
ignore_hidden_files: false,
disable_symlinks: false,
index_files: &[],
index_files: &["index.htm"],
})
.await
.expect("unexpected error response on `handle` function");
@@ -232,7 +232,7 @@ mod tests {
compression_static: false,
ignore_hidden_files: false,
disable_symlinks: false,
index_files: &[],
index_files: &["index.htm"],
})
.await
{
@@ -283,14 +283,15 @@ mod tests {
}
}
// FIX
#[tokio::test]
async fn handle_append_index_on_dir() {
let buf = fs::read(root_dir().join("index.html"))
let buf = fs::read(root_dir().join("assets/index.html"))
.expect("unexpected error during index.html reading");
let buf = Bytes::from(buf);
for method in [Method::HEAD, Method::GET] {
for uri in ["", "/"] {
for uri in ["/assets", "/assets/"] {
match static_files::handle(&HandleOpts {
method: &method,
headers: &HeaderMap::new(),
@@ -317,10 +318,10 @@ mod tests {
{
Ok(result) => {
let mut res = result.resp;
if uri.is_empty() {
if uri == "/assets" {
// it should redirect permanently
assert_eq!(res.status(), 308);
assert_eq!(res.headers()["location"], "/");
assert_eq!(res.headers()["location"], "/assets/");
let body = hyper::body::to_bytes(res.body_mut())
.await
@@ -343,7 +344,7 @@ mod tests {
#[tokio::test]
async fn handle_file_encoded() {
let buf = fs::read(root_dir().join("index.html"))
let buf = fs::read(root_dir().join("assets/index.html"))
.expect("unexpected error during index.html reading");
let buf = Bytes::from(buf);
@@ -352,7 +353,7 @@ mod tests {
method: &method,
headers: &HeaderMap::new(),
base_path: &root_dir(),
uri_path: "/index%2ehtml",
uri_path: "/assets/index%2ehtml",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -407,7 +408,7 @@ mod tests {
compression_static: false,
ignore_hidden_files: false,
disable_symlinks: false,
index_files: &[],
index_files: &["index.htm"],
})
.await
{
@@ -423,7 +424,7 @@ mod tests {
#[tokio::test]
async fn handle_not_modified() {
let buf = fs::read(root_dir().join("index.html"))
let buf = fs::read(root_dir().join("index.htm"))
.expect("unexpected error during index.html reading");
let buf = Bytes::from(buf);
@@ -432,7 +433,7 @@ mod tests {
method: &method,
headers: &HeaderMap::new(),
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "index.htm",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -448,7 +449,7 @@ mod tests {
compression_static: false,
ignore_hidden_files: false,
disable_symlinks: false,
index_files: &[],
index_files: &["index.htm"],
})
.await
{
@@ -474,7 +475,7 @@ mod tests {
method: &method,
headers: &headers,
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "index.htm",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -490,7 +491,7 @@ mod tests {
compression_static: false,
ignore_hidden_files: false,
disable_symlinks: false,
index_files: &[],
index_files: &["index.htm"],
})
.await
{
@@ -519,7 +520,7 @@ mod tests {
method: &method,
headers: &headers,
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "index.htm",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -535,7 +536,7 @@ mod tests {
compression_static: false,
ignore_hidden_files: false,
disable_symlinks: false,
index_files: &[],
index_files: &["index.htm"],
})
.await
{
@@ -562,7 +563,7 @@ mod tests {
method: &method,
headers: &HeaderMap::new(),
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "index.htm",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -578,7 +579,7 @@ mod tests {
compression_static: false,
ignore_hidden_files: false,
disable_symlinks: false,
index_files: &[],
index_files: &["index.htm"],
})
.await
{
@@ -603,7 +604,7 @@ mod tests {
method: &method,
headers: &headers,
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "index.htm",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -619,7 +620,7 @@ mod tests {
compression_static: false,
ignore_hidden_files: false,
disable_symlinks: false,
index_files: &[],
index_files: &["index.htm"],
})
.await
{
@@ -643,7 +644,7 @@ mod tests {
method: &method,
headers: &headers,
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "index.htm",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -659,7 +660,7 @@ mod tests {
compression_static: false,
ignore_hidden_files: false,
disable_symlinks: false,
index_files: &[],
index_files: &["index.htm"],
})
.await
{
@@ -687,7 +688,7 @@ mod tests {
method: &method,
headers: &HeaderMap::new(),
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "index.htm",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -703,7 +704,7 @@ mod tests {
compression_static: false,
ignore_hidden_files: false,
disable_symlinks: false,
index_files: &[],
index_files: &["index.htm"],
})
.await
{
@@ -711,7 +712,7 @@ mod tests {
// The handle only accepts HEAD or GET request methods
Method::GET | Method::HEAD => {
let mut res = result.resp;
let buf = fs::read(root_dir().join("index.html"))
let buf = fs::read(root_dir().join("index.htm"))
.expect("unexpected error during index.html reading");
let buf = Bytes::from(buf);
@@ -774,7 +775,7 @@ mod tests {
method,
headers: &headers,
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "index.htm",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -790,7 +791,7 @@ mod tests {
compression_static: false,
ignore_hidden_files: false,
disable_symlinks: false,
index_files: &[],
index_files: &["index.htm"],
})
.await
{
@@ -804,7 +805,7 @@ mod tests {
)
.expect("unexpected bytes error during body compression");
let buf = fs::read(root_dir().join("index.html"))
let buf = fs::read(root_dir().join("index.htm"))
.expect("unexpected error during index.html reading");
assert_eq!(res.status(), 200);
@@ -840,7 +841,7 @@ mod tests {
let mut headers = HeaderMap::new();
headers.insert("range", "bytes=0-0".parse().unwrap());
let buf = fs::read(root_dir().join("index.html"))
let buf = fs::read(root_dir().join("index.htm"))
.expect("unexpected error during index.html reading");
let buf = Bytes::from(buf);
@@ -849,7 +850,7 @@ mod tests {
method: &method,
headers: &headers,
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "index.htm",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -865,7 +866,7 @@ mod tests {
compression_static: false,
ignore_hidden_files: false,
disable_symlinks: false,
index_files: &[],
index_files: &["index.htm"],
})
.await
{
@@ -894,7 +895,7 @@ mod tests {
let mut headers = HeaderMap::new();
headers.insert("range", "bytes=100-200".parse().unwrap());
let buf = fs::read(root_dir().join("index.html"))
let buf = fs::read(root_dir().join("assets/index.html"))
.expect("unexpected error during index.html reading");
let buf = Bytes::from(buf);
@@ -903,7 +904,7 @@ mod tests {
method: &method,
headers: &headers,
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "assets/index.html",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -948,7 +949,7 @@ mod tests {
let mut headers = HeaderMap::new();
headers.insert("range", "bytes=100-100000".parse().unwrap());
let buf = fs::read(root_dir().join("index.html"))
let buf = fs::read(root_dir().join("assets/index.html"))
.expect("unexpected error during index.html reading");
let buf = Bytes::from(buf);
@@ -957,7 +958,7 @@ mod tests {
method: &method,
headers: &headers,
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "assets/index.html",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -1003,7 +1004,7 @@ mod tests {
headers.insert("range", "bytes=100-200".parse().unwrap());
headers.insert("if-range", "Mon, 18 Nov 1974 00:00:00 GMT".parse().unwrap());
let buf = fs::read(root_dir().join("index.html"))
let buf = fs::read(root_dir().join("index.htm"))
.expect("unexpected error during index.html reading");
let buf = Bytes::from(buf);
@@ -1012,7 +1013,7 @@ mod tests {
method: &method,
headers: &headers,
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "index.htm",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -1028,7 +1029,7 @@ mod tests {
compression_static: false,
ignore_hidden_files: false,
disable_symlinks: false,
index_files: &[],
index_files: &["index.htm"],
})
.await
{
@@ -1050,7 +1051,7 @@ mod tests {
let mut headers = HeaderMap::new();
headers.insert("range", "bytes=100-".parse().unwrap());
let buf = fs::read(root_dir().join("index.html"))
let buf = fs::read(root_dir().join("assets/index.html"))
.expect("unexpected error during index.html reading");
let buf = Bytes::from(buf);
@@ -1059,7 +1060,7 @@ mod tests {
method: &method,
headers: &headers,
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "assets/index.html",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -1107,7 +1108,7 @@ mod tests {
let mut headers = HeaderMap::new();
headers.insert("range", "bytes=-100".parse().unwrap());
let buf = fs::read(root_dir().join("index.html"))
let buf = fs::read(root_dir().join("assets/index.html"))
.expect("unexpected error during index.html reading");
let buf = Bytes::from(buf);
@@ -1116,7 +1117,7 @@ mod tests {
method: &method,
headers: &headers,
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "assets/index.html",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -1161,7 +1162,7 @@ mod tests {
let mut headers = HeaderMap::new();
headers.insert("range", "bytes=100-10".parse().unwrap());
let buf = fs::read(root_dir().join("index.html"))
let buf = fs::read(root_dir().join("index.htm"))
.expect("unexpected error during index.html reading");
let buf = Bytes::from(buf);
@@ -1170,7 +1171,7 @@ mod tests {
method: &method,
headers: &headers,
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "index.htm",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -1186,7 +1187,7 @@ mod tests {
compression_static: false,
ignore_hidden_files: false,
disable_symlinks: false,
index_files: &[],
index_files: &["index.htm"],
})
.await
{
@@ -1215,7 +1216,7 @@ mod tests {
let mut headers = HeaderMap::new();
headers.insert("range", "bytes=xyx-abc".parse().unwrap());
let buf = fs::read(root_dir().join("index.html"))
let buf = fs::read(root_dir().join("index.htm"))
.expect("unexpected error during index.html reading");
let buf = Bytes::from(buf);
@@ -1224,7 +1225,7 @@ mod tests {
method: &method,
headers: &headers,
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "index.htm",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -1240,7 +1241,7 @@ mod tests {
compression_static: false,
ignore_hidden_files: false,
disable_symlinks: false,
index_files: &[],
index_files: &["index.htm"],
})
.await
{
@@ -1266,7 +1267,7 @@ mod tests {
#[tokio::test]
async fn handle_byte_ranges_bad_2() {
let buf = fs::read(root_dir().join("index.html"))
let buf = fs::read(root_dir().join("assets/index.html"))
.expect("unexpected error during index.html reading");
let buf = Bytes::from(buf);
@@ -1281,7 +1282,7 @@ mod tests {
method: &method,
headers: &headers,
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "assets/index.html",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -1297,7 +1298,7 @@ mod tests {
compression_static: false,
ignore_hidden_files: false,
disable_symlinks: false,
index_files: &[],
index_files: &["index.htm"],
})
.await
{
@@ -1328,7 +1329,7 @@ mod tests {
method: &method,
headers: &headers,
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "index.htm",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -1344,7 +1345,7 @@ mod tests {
compression_static: false,
ignore_hidden_files: false,
disable_symlinks: false,
index_files: &[],
index_files: &["index.htm"],
})
.await
{
@@ -1361,7 +1362,7 @@ mod tests {
#[tokio::test]
async fn handle_byte_ranges_exclude_file_size() {
let buf = fs::read(root_dir().join("index.html"))
let buf = fs::read(root_dir().join("assets/index.html"))
.expect("unexpected error during index.html reading");
let buf = Bytes::from(buf);
@@ -1374,7 +1375,7 @@ mod tests {
method: &method,
headers: &headers,
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "assets/index.html",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -1419,7 +1420,7 @@ mod tests {
#[tokio::test]
async fn handle_byte_ranges_exclude_file_size_2() {
let buf = fs::read(root_dir().join("index.html"))
let buf = fs::read(root_dir().join("assets/index.html"))
.expect("unexpected error during index.html reading");
let buf = Bytes::from(buf);
@@ -1435,7 +1436,7 @@ mod tests {
method: &method,
headers: &headers,
base_path: &root_dir(),
uri_path: "index.html",
uri_path: "assets/index.html",
uri_query: None,
#[cfg(feature = "experimental")]
memory_cache: None,
@@ -1504,7 +1505,7 @@ mod tests {
compression_static: true,
ignore_hidden_files: true,
disable_symlinks: false,
index_files: &[],
index_files: &["index.htm"],
})
.await
{
@@ -1548,7 +1549,7 @@ mod tests {
compression_static: true,
ignore_hidden_files: true,
disable_symlinks: false,
index_files: &["index.html", "index.htm"],
index_files: &["index.htm", "index.htm"],
})
.await
{
@@ -1594,7 +1595,7 @@ mod tests {
compression_static: true,
ignore_hidden_files: true,
disable_symlinks: true,
index_files: &["index.html", "index.htm"],
index_files: &["index.htm", "index.htm"],
})
.await
{
@@ -1630,7 +1631,7 @@ mod tests {
compression_static: true,
ignore_hidden_files: true,
disable_symlinks: false,
index_files: &["index.html", "index.htm"],
index_files: &["index.htm", "index.htm"],
})
.await
{