oxihttp-server — Pure-Rust HTTP server for the OxiHTTP stack

oxihttp-server is the HTTP server of the OxiHTTP stack. It serves HTTP/1.1 and HTTP/2 (auto-negotiated) with a path-parameter router, virtual hosts, nested routers, typed request extraction, application state injection, graceful shutdown, connection limits, TCP/HTTP-2 tuning, and a built-in middleware pipeline (CORS, body-size limits, token-bucket rate limiting, timeouts). Optional features add response compression, static-file serving, Server-Sent Events, WebSockets, Tower-layer integration, mutual-TLS, and HTTP/3.
The server builds on hyper and hyper-util's auto connection builder; all shared types (OxiHttpError, Body, typed headers, content negotiation) come from oxihttp-core. TLS is Pure Rust via oxitls + rustls/tokio-rustls (no OpenSSL); compression is Pure Rust via oxiarc-deflate; HTTP/3 is Pure Rust via oxiquic-h3. The crate is #![forbid(unsafe_code)].
Installation
[dependencies]
oxihttp-server = "0.1.0"
oxihttp-server = { version = "0.1.0", features = ["tls", "compression", "static-files", "websocket"] }
Quick Start
use oxihttp_server::{Server, Router, response};
# async fn example() -> Result<(), oxihttp_core::OxiHttpError> {
let router = Router::new()
.get("/hello", |_req| async {
response::text_response("Hello, World!")
})
.get("/users/:id", |req| async move {
let id = req.param("id").unwrap_or("?").to_string();
response::text_response(format!("user {id}"))
})
.health("/health");
Server::bind("127.0.0.1:3000")
.serve(router)
.await?;
# Ok(())
# }
Graceful shutdown and a JSON handler
use oxihttp_server::{Server, Router, response};
# async fn example() -> Result<(), oxihttp_core::OxiHttpError> {
let router = Router::new().post("/echo", |req| async move {
let value: serde_json::Value = req.body_json().await?;
response::json_response(&value)
});
Server::bind("127.0.0.1:0")
.with_max_connections(1024)
.shutdown_on_ctrl_c()
.serve(router)
.await?;
# Ok(())
# }
API Overview
Server / ServerBuilder / BoundServer
Server::bind(addr) -> ServerBuilder starts configuration.
ServerBuilder method |
Description |
with_cors(CorsConfig) |
Add CORS middleware |
with_body_limit(u64) |
Reject bodies over n bytes (413) |
with_rate_limiter(RateLimiter) |
Token-bucket rate limiting |
with_timeout(Duration) |
Per-request processing timeout |
with_max_connections(usize) |
Cap concurrent connections (semaphore) |
with_tcp_nodelay(bool) / with_tcp_keepalive(Duration) |
TCP socket tuning |
with_http2_settings(ServerHttp2Settings) |
HTTP/2 connection tuning |
with_graceful_shutdown(Future) / shutdown_on_ctrl_c() |
Stop accepting on a signal |
with_layer(L) (feature tower) |
Add a tower_layer::Layer |
with_tls(TlsConfig) (feature tls) |
Use a pre-built TLS config |
with_tls_from_pem(cert, key) (tls) |
Build TLS from PEM bytes |
with_tls_from_der(certs, key) (tls) |
Build TLS from DER |
with_alpn(protocols) (tls) |
Set ALPN (call before with_tls_from_*) |
listen() -> BoundServer |
Bind eagerly to inspect the address |
serve(Router) |
Run until shutdown / fatal error |
serve_with_addr(Router) |
Return the bound SocketAddr + a JoinHandle |
BoundServer exposes local_addr() -> SocketAddr and serve(Router) — useful when binding port 0 in tests.
ServerHttp2Settings
A Default struct of optional HTTP/2 knobs: initial_stream_window_size, initial_connection_window_size, adaptive_window, max_concurrent_streams, max_frame_size, keep_alive_interval, keep_alive_timeout.
Router (router module)
| Method |
Description |
new() |
Empty router (also Default) |
route(Method, path, handler) |
Register a route for any method |
get / post / put / delete / patch / head (path, handler) |
Method shortcuts |
nest(prefix, Router) |
Mount a sub-router under a prefix |
host(host, Router) |
Virtual-host dispatch (case-insensitive, port-stripped) |
fallback(handler) |
Custom 404 handler |
method_not_allowed(handler) |
Custom 405 handler |
health(path) |
200 OK health-check route |
with_state(T) |
Inject Arc<T> into every request (inherited by nested/vhost routers) |
resolve(&Method, path) |
Match without dispatching (introspection/bench) |
dispatch(req) -> DispatchFuture |
Dispatch a hyper request |
route_count() |
Number of top-level routes |
into_make_service() (feature tower) |
Wrap as a RouterMakeService |
Path patterns support literal segments, :param parameters, and *wildcard (matches the remainder). Router implements Display (route listing) and Debug.
Public type aliases: HandlerFn, DispatchFuture<'a>.
Request (router module)
The handler argument. Path-params + query plus body consumers.
| Method |
Description |
method() / uri() / headers() / path() |
Request line + headers |
param(name) / params() |
Path parameters |
query_params() / query(name) |
Query-string parameters (percent-decoded) |
body_bytes() / body_text() / body_json::<T>() |
Consume the body |
into_inner() |
Recover the raw hyper::Request<Incoming> |
state::<T>() |
Retrieve injected Arc<T> |
extension::<T>() / extensions() / extensions_mut() |
Per-request extensions |
parts() / extract::<T>() |
Typed extraction (see below) |
negotiate(&[ContentType]) |
Content negotiation from Accept |
tls_info() / peer_certificates() / tls_connection_info() (feature tls) |
TLS/mTLS connection info |
Extraction (extractor module)
| Item |
Description |
RequestParts<'a> |
Non-body view (method, uri, headers, path_params) |
FromRequestParts (trait) |
type Rejection: Into<OxiHttpError> + from_request_parts |
TypedHeader<H: Header> |
Extracts and decodes a typed header from oxihttp-core |
Response helpers (response module)
Free functions returning Result<hyper::Response<Full<Bytes>>, OxiHttpError>:
| Function |
Result |
json_response(&T) |
200 + application/json |
json_response_with_status(status, &T) |
Custom status + JSON |
text_response(impl Into<String>) |
200 + text/plain |
html_response(impl Into<String>) |
200 + text/html |
form_response(FormBody) |
200 + application/x-www-form-urlencoded |
redirect_response(location) |
302 Found + Location |
empty_response(status) |
Empty body |
no_content() |
204 No Content |
bad_request(msg) |
400 Bad Request |
internal_error(msg) |
500 Internal Server Error |
Middleware (middleware module)
| Type |
Description |
CorsConfig |
Fields for origins/methods/headers/credentials/max-age; permissive(), with_origins(..), apply_headers, preflight_response |
BodyLimitConfig |
new(max_bytes), check_content_length |
RateLimiter |
Token bucket; new(max_tokens, refill_rate), check(key), too_many_requests() |
TimeoutConfig |
new(Duration), timeout_response() |
These are composed internally via the MiddlewarePipeline configured by the ServerBuilder::with_* methods.
Compression — feature compression (compression module)
| Item |
Description |
CompressionAlgorithm |
Gzip / Deflate; as_str() |
CompressionConfig |
min_size, algorithms, level (Default: 1 KiB, gzip+deflate, level 6) |
Compression |
new(), min_size(n), level(n), algorithms(..), apply(accept_encoding, response) |
Static files — feature static-files (static_files module)
| Item |
Description |
ServeDir |
new(root), with_index, with_fallback, with_cache_control, add_mime_override, serve(method, path, headers). ETag + If-Modified-Since + single-range + path-traversal protection |
ServeFile |
new(path), with_cache_control, with_mime, serve(..) |
Server-Sent Events — feature sse (sse module)
| Item |
Description |
SseEvent |
data(..), with_id, with_event, with_retry, encode(); public fields id/event/data/retry |
SseSender |
send(SseEvent) (async), try_send(SseEvent) |
SseResponse |
channel(buffer) -> (SseSender, SseResponse), with_heartbeat(interval), into_response() -> Response<Body> |
WebSockets — feature websocket (ws module)
| Item |
Description |
upgrade(Request) -> (WebSocketUpgrade, Response<Full<Bytes>>) |
RFC 6455 handshake (101 response) |
WebSocketUpgrade |
accept() → WebSocket once the connection upgrades |
WebSocket<S> |
recv(), send(Message), close(code, reason) |
Message |
Text(String), Binary(Vec<u8>), Ping(Vec<u8>), Pong(Vec<u8>), Close(Option<CloseFrame>) |
CloseFrame |
code: u16, reason: String |
Tower integration — feature tower (tower_compat, tower_middleware modules)
| Item |
Description |
RouterMakeService |
Service factory from a Router (also via Router::into_make_service()) |
LoggingLayer |
tower_layer::Layer logging method/path/status/elapsed |
RequestIdLayer |
Injects an incrementing x-request-id header |
TLS — feature tls (tls module)
| Item |
Description |
TlsConfig |
new(rustls::ServerConfig), from_pem / from_der (+ _with_alpn), with_client_auth(cert, key, client_ca) for mTLS, http2_defaults / http2_defaults_from_der, from_pem_with_key_log / from_der_with_key_log |
PeerCertInfo |
Per-connection TLS facts: peer_certificates, alpn_protocol, protocol_version, typed version, cipher_suite, sni |
HTTP/3 — feature h3 (h3 module)
| Item |
Description |
H3Server |
bind(..), local_addr(), serve(handler) — QUIC/HTTP-3 server via oxiquic-h3 |
Feature Flags
| Feature |
Default |
Description |
compression |
off |
gzip/deflate response compression via oxiarc-deflate |
static-files |
off |
ServeDir/ServeFile with ETag + range support |
sse |
off |
Server-Sent Events |
tls |
off |
HTTPS + mTLS via oxitls + rustls/tokio-rustls (Pure Rust) |
tower |
off |
Tower Layer integration (with_layer, LoggingLayer, RequestIdLayer) |
websocket |
off |
RFC 6455 WebSocket upgrades |
h3 |
off |
HTTP/3 server via oxiquic-h3 (pulls in rustls) |
Error type
Handlers and builder methods return oxihttp_core::OxiHttpError. The server commonly produces Server, Io, Http, Body, Json, Tls, RouteNotFound, and MethodNotAllowed; see the oxihttp-core README for the full variant table and the status_code() mapping.
Related crates
oxihttp — the unified facade re-exporting this server.
oxihttp-core — shared types (OxiHttpError, Body, typed headers, negotiation).
oxihttp-client — the matching HTTP client.
License
Apache-2.0 — COOLJAPAN OU (Team Kitasan)