2 releases
| new 0.2.1 | Feb 10, 2026 |
|---|---|
| 0.2.0 | Feb 10, 2026 |
#1085 in HTTP server
420KB
3.5K
SLoC
serdir
Rust helpers for serving HTTP GET and HEAD responses with hyper 1.x and tokio.
This crate provides utilities for serving static files in Rust web applications.
Features
- Range requests
- Large file support via chunked streaming
- Live content changes
- ETag header generation and conditional GET requests
- Serving files that have been pre-compressed using gzip, brotli or zstd
- Cached runtime compression of files using brotli
- Content type detection based on filename extensions
- Serving directory paths using
index.htmlpages - Customizing 404 response content
- Support for the Tower
ServiceandLayerAPIs
This crate is derived from http-serve.
Example
Serve files via Hyper:
use hyper::server::conn::http1;
use hyper_util::rt::TokioIo;
use serdir::ServedDir;
use serdir::compression::BrotliLevel;
use std::net::{Ipv4Addr, SocketAddr};
use tokio::net::TcpListener;
#[tokio::main]
async fn main() {
let service = ServedDir::builder("./static")
.unwrap()
.append_index_html(true)
.cached_compression(BrotliLevel::L5)
.build()
.into_hyper_service();
let addr = SocketAddr::from((Ipv4Addr::LOCALHOST, 1337));
let listener = TcpListener::bind(addr).await.unwrap();
loop {
let (tcp, _) = listener.accept().await.unwrap();
let service = service.clone();
tokio::spawn(async move {
let io = TokioIo::new(tcp);
if let Err(err) = http1::Builder::new()
.serve_connection(io, service)
.await
{
eprintln!("connection error: {err}");
}
});
}
}
Serve files via Tower:
use hyper::server::conn::http1;
use hyper_util::rt::TokioIo;
use hyper_util::service::TowerToHyperService;
use serdir::ServedDir;
use std::net::{Ipv4Addr, SocketAddr};
use tokio::net::TcpListener;
#[tokio::main]
async fn main() {
let service = ServedDir::builder("./static")
.unwrap()
.append_index_html(true)
.static_compression(false, true, false) // gzip only
.strip_prefix("/static")
.build()
.into_tower_service();
let addr = SocketAddr::from((Ipv4Addr::LOCALHOST, 1337));
let listener = TcpListener::bind(addr).await.unwrap();
loop {
let (tcp, _) = listener.accept().await.unwrap();
let service = service.clone();
tokio::spawn(async move {
let io = TokioIo::new(tcp);
let hyper_service = TowerToHyperService::new(service);
if let Err(err) = http1::Builder::new()
.serve_connection(io, hyper_service)
.await
{
eprintln!("connection error: {err}");
}
});
}
}
Run the builtin example:
$ cargo run --example hyper --features hyper .
Optional features
This project defines 3 optional build features that can be enabled at compile time:
runtime-compression- enables the cached compression strategy, i.e. runtime compression of served files using Brotlitower- enables integration with Tower-based web frameworks like Axum and Poem by providing APIs to convert aServedDirinto atower::Serviceortower::Layerhyper- enables direct integration with thehyperweb server by providing APIs to convert aServedDirinto ahyper::Service
Authors
See the AUTHORS file for details.
License
Your choice of MIT or Apache; see LICENSE-MIT.txt or LICENSE-APACHE, respectively.
Dependencies
~3–12MB
~258K SLoC