Skip to main content

Crate simoom

Crate simoom 

Source
Expand description

simoom: a small, fast, secure embeddable HTTP/1.1, HTTP/2 and HTTP/3 server.

The API is synchronous at its core and needs no async runtime. A Service runs inline on a loop thread (one loop per core, shared-nothing); slow or blocking work goes to a bounded offload pool with CoDel admission.

use simoom::{Outcome, Reply, Request, Server, StaticReply};
use std::sync::Arc;

let hello = Arc::new(StaticReply::new(200, &[("content-type", "text/plain")], b"Hello, World!"));
let server = Server::builder()
    .listen("127.0.0.1:8080")
    .threads(0) // one loop per core
    .service(move |_req: &mut Request<'_>, reply: Reply<'_>| -> Outcome { reply.fixed(&hello) })
    .start()
    .unwrap();
println!("listening on {}", server.local_addr());

§Answering

A Reply ends in exactly one of: an immediate response (Reply::body, Reply::fixed…), a Responder for later (Reply::defer), a streamed body (Reply::stream, Reply::sse with a BodySink), offloaded work (Reply::offload, blocking), or a WebSocket (Reply::websocket).

§Blocking work: which path to use

A service must never block a loop thread. Pick one of:

pathwhen
Reply::defer + your own threadsthe host already has a worker pool, its own naming, limits and backpressure (an integration engine such as Cameleer): copy the request with Request::to_owned_request, answer through the Responder from any thread. Limits::defer_timeout bounds the wait, Responder::is_cancelled tells the worker the client left. simoom’s pool and CoDel are not involved.
blocking, Reply::blocking, Reply::offloadblocking handlers without a pool of their own (database or HTTP calls of up to seconds). The offload pool starts up to Limits::offload_threads workers on demand (32 per CPU by default, 64 to 512) and answers a fast 503 only when its queue keeps growing past what the workers absorb (CoDel with a target of at least the jobs’ mean run time).
inlinemicroseconds of CPU, no I/O. The stall watchdog (feature watchdog) moves a route that turns out slow to the offload pool, as a safety net, not a plan: each call before the move holds the loop.

§Request bodies

Bodies up to Limits::body_buffer are buffered whole (Request::body); longer ones stream through a BodySource (Request::take_body) with pull-based backpressure.

§Protocols and features

featurewhat it adds
http1 (default)HTTP/1.1: keep-alive, pipelining, chunked, 100-continue
http2 (default)h2c prior knowledge, Upgrade: h2c, h2 over TLS
websocket (default), alias wsWebSocket upgrades
tlsTLS 1.3 listeners ([Builder::listen_tls]), ALPN h2 / http/1.1
http3HTTP/3 over QUIC ([Builder::listen_quic]); announced with alt-svc
fullall of them
compressiongzip and deflate responses negotiated from Accept-Encoding (Builder::compression), request body decoding (Request::decoded_body)
websocket-h2WebSocket over HTTP/2 (RFC 8441 extended CONNECT) with the same Reply::websocket
h2-keepaliveHTTP/2 PING keepalive (Limits::h2_keepalive)

The last three are not part of default or full, which keep their size budgets.

§Safety nets

  • Every limit of Limits is enforced (head size, body size, timeouts, minimum body rate, write deadline, connection caps).
  • A handler panic becomes a 500 and the connection closes.
  • The stall watchdog finds inline handlers that use more than Limits::inline_budget of CPU, or block, and moves just their route to the offload pool after Limits::stalls_before_offload stalls within Limits::stall_window; a route comes back after Limits::stall_recovery fast calls there (cargo feature watchdog, on by default).
  • Graceful stop (ServerHandle::stop): GOAWAY on HTTP/2 and HTTP/3, Connection: close on HTTP/1.1.

Structs§

Blocking
The service returned by blocking.
BodySink
The body of a streamed response (crate::Reply::stream, crate::Reply::sse): chunked on HTTP/1.1, DATA frames on HTTP/2 and HTTP/3. Send: write from any thread.
BodySource
A request body that streams (crate::Request::take_body): bodies larger than crate::Limits::body_buffer or of unknown length. Send: read it from any thread.
Builder
Configures and starts a server. See Server::builder.
Completion
One finished request, for access logs and metrics (Builder::on_complete).
FrameBudgets
HTTP/2 frame budgets (Limits::h2_frame_budgets): how many of each frame kind a peer may send (or make us send) within a sliding window before the connection is closed with GOAWAY(ENHANCE_YOUR_CALM). u32::MAX turns one off. They defend against the HTTP/2 floods (CVE-2019-9511..9518, Rapid Reset CVE-2023-44487, MadeYouReset CVE-2025-8671); the defaults leave ordinary clients, browsers and gRPC far below them.
Limits
Server limits. Every field is a hard bound; exceeding one gives a specific status code (or closes the connection) and increments a counter in crate::Stats.
OffloadStats
Counters of an OffloadPool.
OwnedRequest
An owned request, for work on other threads (crate::blocking, crate::Reply::offload).
Ready
The future returned by BodySink::ready.
Reply
How a crate::Service answers one request. Build the response with Reply::status and Reply::header, then finish it with exactly one of:
Request
A request, borrowed from the connection for the duration of crate::Service::call.
Responder
Answers a request later, from any thread (crate::Reply::defer). It completes exactly once: Responder::send or Responder::stream consume it, and dropping it unanswered sends a 500.
Response
An owned response: what a crate::Responder or a crate::blocking handler sends.
Router
Routes requests by method and path.
Server
Entry point: Server::builder.
ServerHandle
A running server. Dropping it stops at once; use ServerHandle::stop and ServerHandle::join for a graceful stop.
StaticReply
A reply serialized once, for the fast path of fixed answers (crate::Reply::fixed). On HTTP/1.1 it is copied out with the current Date spliced in: one copy, no formatting.
Stats
Server counters.
TlsInfo
The TLS session of a connection (Request::tls): what Camel exposes as CamelHttpSslSession and the CamelHttpSslClientCert headers. Captured once, when the handshake completes.
WebSocket
The connection, inside a WebSocketHandler callback.
WsHandle
Sends on a WebSocket from any thread. Messages to a closed connection are dropped.

Enums§

Backend
Which I/O back end a driver uses.
Body
A response body.
Outcome
What Service::call returns: informational. The server tracks what the Reply did; a call that neither answered nor deferred gets a 500.
Version
The HTTP version a request arrived with.
WsMessage
A complete message.

Traits§

Service
Handles requests. It runs inline on a loop thread, so it must not block: answer at once (microseconds), or defer (Reply::defer), or move the work to the offload pool (Reply::offload, blocking).
WebSocketHandler
Handles one WebSocket connection, on its loop thread. Must not block.

Functions§

blocking
A service that runs blocking code on the shared, bounded offload pool: the request is copied (OwnedRequest), f runs on a worker thread, and its Response comes back to the connection. When the pool is full or CoDel reports overload (jobs waiting longer than crate::Limits::offload_target for a whole interval) the request gets a fast 503 with Retry-After instead of queueing.
percent_decode
Decodes %XX escapes; None for a malformed escape.