mini-static 0.38.5

A secure, async static file server with streaming, traversal protection, and connection limits.
Documentation
//! A ceiling measurement: the same response, served from memory, with no filesystem work.
//!
//! Not a proposal — a bound. It answers how much of the gap to nginx is filesystem work
//! (which an open-file cache could recover) and how much is the HTTP stack itself (which it
//! cannot). Serving one preloaded buffer with the same headers `mini-static` sets is the
//! most optimistic version of a perfectly warm cache, so whatever this reaches is the most
//! a cache could ever be worth.

use std::env;
use std::path::Path;

use hyper::header::{HeaderValue, CONTENT_LENGTH, CONTENT_TYPE, ETAG};
use hyper::{Response, StatusCode};
use mini_serve::{body, handler, RouteBuilder, ServeError};

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let port: u16 = env::var("PORT").unwrap_or_else(|_| "8093".into()).parse()?;
    let root = env::var("ROOT").unwrap_or_else(|_| "./bench/www".into());
    let bytes = std::fs::read(Path::new(&root).join("index.html"))?;
    let len = bytes.len();
    let payload = hyper::body::Bytes::from(bytes);

    let app = RouteBuilder::stateless()
        .with_fallback(handler(move |_req, _state| {
            let payload = payload.clone();
            async move {
                let mut resp = Response::new(body(payload));
                *resp.status_mut() = StatusCode::OK;
                let headers = resp.headers_mut();
                headers.insert(CONTENT_TYPE, HeaderValue::from_static("text/html; charset=utf-8"));
                headers.insert(CONTENT_LENGTH, len.into());
                headers.insert(ETAG, HeaderValue::from_static("\"cached\""));
                Ok::<_, ServeError>(resp)
            }
        }))
        .seal();

    let listener = tokio::net::TcpListener::bind(("127.0.0.1", port)).await?;
    eprintln!("in-memory ceiling server on {port}");
    app.run(listener, mini_serve::shutdown_signal()?).await?;
    Ok(())
}