1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//! 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.
//!
//! ```no_run
//! 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());
//! # server.stop(std::time::Duration::from_secs(1));
//! # server.join();
//! ```
//!
//! # 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:
//!
//! | path | when |
//! |---|---|
//! | [`Reply::defer`] + your own threads | the 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::offload`] | blocking 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). |
//! | inline | microseconds 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
//!
//! | feature | what 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 `ws` | WebSocket upgrades |
//! | `tls` | TLS 1.3 listeners ([`Builder::listen_tls`]), ALPN h2 / http/1.1 |
//! | `http3` | HTTP/3 over QUIC ([`Builder::listen_quic`]); announced with `alt-svc` |
//! | `full` | all of them |
//! | `compression` | gzip and deflate responses negotiated from `Accept-Encoding` (`Builder::compression`), request body decoding (`Request::decoded_body`) |
//! | `websocket-h2` | WebSocket over HTTP/2 (RFC 8441 extended CONNECT) with the same [`Reply::websocket`] |
//! | `h2-keepalive` | HTTP/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.
// A build without any protocol feature serves nothing; it still compiles, quietly.
// Builds without HTTP/1.1 (h2c only, h2 over TLS only, HTTP/3 only) leave the HTTP/1.1 output
// helpers and fields unused; the linker drops them.
pub use ;
pub use ;
pub use ;
pub use Reply;
pub use ;
pub use Router;
pub use ;
pub use ;
pub use WatchRef;
pub use OffloadStats;
pub use Backend;
pub use ;
pub use percent_decode;
pub use ;
/// permessage-deflate settings ([`Builder::websocket_deflate`]).
pub use DeflateConfig as WsDeflate;
/// TLS configuration types (feature `tls`).