Add healthcheck route at /__miniserve_internal/healthcheck

Fixes #1435
This commit is contained in:
Sven-Hendrik Haase 2025-03-07 02:15:43 +01:00
parent a7d658e2da
commit dfdd2456a9
No known key found for this signature in database
GPG Key ID: 39E4B877E62EB915
4 changed files with 38 additions and 7 deletions

View File

@ -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

View File

@ -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,

View File

@ -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()

View File

@ -72,6 +72,25 @@ fn serves_requests_with_non_default_port(server: TestServer) -> Result<(), Error
Ok(())
}
#[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()?;