aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven-Hendrik Haase <svenstaro@gmail.com>2025-03-07 01:15:43 +0000
committerSven-Hendrik Haase <svenstaro@gmail.com>2025-03-07 01:15:43 +0000
commitdfdd2456a906b177efad17e52fb9fd971764c5c4 (patch)
treef27e0a735ad420e8b83da18c602cc3dc2cba9c32
parentDocument ?raw=true (diff)
downloadminiserve-dfdd2456a906b177efad17e52fb9fd971764c5c4.tar.gz
miniserve-dfdd2456a906b177efad17e52fb9fd971764c5c4.zip
Add healthcheck route at /__miniserve_internal/healthcheck
Fixes #1435
-rw-r--r--README.md1
-rw-r--r--src/config.rs20
-rw-r--r--src/main.rs5
-rw-r--r--tests/serve_request.rs19
4 files changed, 38 insertions, 7 deletions
diff --git a/README.md b/README.md
index b3b5e44..d211065 100644
--- a/README.md
+++ b/README.md
@@ -143,6 +143,7 @@ Some mobile browsers like Firefox on Android will offer to open the camera app w
- Supports README.md rendering like on GitHub
- Range requests
- WebDAV support
+- Healthcheck route (at `/__miniserve_internal/healthcheck`)
## Usage
diff --git a/src/config.rs b/src/config.rs
index 379f7a7..7d491c4 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -63,10 +63,13 @@ pub struct MiniserveConfig {
/// Route prefix; Either empty or prefixed with slash
pub route_prefix: String,
- /// Randomly generated favicon route
+ /// Well-known healthcheck route (prefixed if route_prefix is provided)
+ pub healthcheck_route: String,
+
+ /// Well-known favicon route (prefixed if route_prefix is provided)
pub favicon_route: String,
- /// Randomly generated css route
+ /// Well-known css route (prefixed if route_prefix is provided)
pub css_route: String,
/// Default color scheme
@@ -198,19 +201,21 @@ impl MiniserveConfig {
}
}
- // Generate some random routes for the favicon and css so that they are very unlikely to conflict with
- // real files.
- // If --random-route is enabled , in order to not leak the random generated route, we must not use it
+ // Format some well-known routes at paths that are very unlikely to conflict with real
+ // files.
+ // If --random-route is enabled, in order to not leak the random generated route, we must not use it
// as static files prefix.
// Otherwise, we should apply route_prefix to static files.
- let (favicon_route, css_route) = if args.random_route {
+ let (healthcheck_route, favicon_route, css_route) = if args.random_route {
(
+ "/__miniserve_internal/healthcheck".into(),
"/__miniserve_internal/favicon.svg".into(),
"/__miniserve_internal/style.css".into(),
)
} else {
(
- format!("{}/{}", route_prefix, "__miniserve_internal/favicon.ico"),
+ format!("{}/{}", route_prefix, "__miniserve_internal/healthcheck"),
+ format!("{}/{}", route_prefix, "__miniserve_internal/favicon.svg"),
format!("{}/{}", route_prefix, "__miniserve_internal/style.css"),
)
};
@@ -299,6 +304,7 @@ impl MiniserveConfig {
default_sorting_method: args.default_sorting_method,
default_sorting_order: args.default_sorting_order,
route_prefix,
+ healthcheck_route,
favicon_route,
css_route,
default_color_scheme,
diff --git a/src/main.rs b/src/main.rs
index ccf611c..688aed1 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -219,6 +219,7 @@ async fn run(miniserve_config: MiniserveConfig) -> Result<(), StartupError> {
miniserve_config.compress_response,
middleware::Compress::default(),
))
+ .route(&inside_config.healthcheck_route, web::get().to(healthcheck))
.route(&inside_config.favicon_route, web::get().to(favicon))
.route(&inside_config.css_route, web::get().to(css))
.service(
@@ -429,6 +430,10 @@ async fn error_404(req: HttpRequest) -> Result<HttpResponse, RuntimeError> {
Err(RuntimeError::RouteNotFoundError(req.path().to_string()))
}
+async fn healthcheck() -> impl Responder {
+ HttpResponse::Ok().body("OK")
+}
+
async fn favicon() -> impl Responder {
let logo = include_str!("../data/logo.svg");
HttpResponse::Ok()
diff --git a/tests/serve_request.rs b/tests/serve_request.rs
index f840efd..2910074 100644
--- a/tests/serve_request.rs
+++ b/tests/serve_request.rs
@@ -73,6 +73,25 @@ fn serves_requests_with_non_default_port(server: TestServer) -> Result<(), Error
}
#[rstest]
+#[case("__miniserve_internal/healthcheck", server(None::<&str>))]
+#[case("__miniserve_internal/favicon.svg", server(None::<&str>))]
+#[case("__miniserve_internal/style.css", server(None::<&str>))]
+#[case("testlol/__miniserve_internal/healthcheck", server(&["--route-prefix", "testlol"]))]
+#[case("testlol/__miniserve_internal/favicon.svg", server(&["--route-prefix", "testlol"]))]
+#[case("testlol/__miniserve_internal/style.css", server(&["--route-prefix", "testlol"]))]
+#[case("__miniserve_internal/healthcheck", server(&["--random-route"]))]
+#[case("__miniserve_internal/favicon.svg", server(&["--random-route"]))]
+#[case("__miniserve_internal/style.css", server(&["--random-route"]))]
+fn serves_requests_for_special_routes(
+ #[case] route: &str,
+ #[case] server: TestServer,
+) -> Result<(), Error> {
+ let body = reqwest::blocking::get(format!("{}{}", server.url(), route))?.error_for_status()?;
+
+ Ok(())
+}
+
+#[rstest]
fn serves_requests_hidden_files(#[with(&["--hidden"])] server: TestServer) -> Result<(), Error> {
let body = reqwest::blocking::get(server.url())?.error_for_status()?;
let parsed = Document::from_read(body)?;