Expand description
Sans-io HTTP/2 (RFC 9113) connection engine for simoom, with DoS accounting.
A Connection takes received bytes plus the current time and produces Events and
outbound bytes. It never touches sockets, threads or clocks; the event loop feeds it:
use simoom_h2::{Config, Connection, Event};
let mut server = Connection::server(Config::default());
let mut client = Connection::client(Config::default());
let id = client.send_request(b"GET", b"https", b"example.com", b"/", &[], true).unwrap();
let c2s = client.output().to_vec();
client.advance_output(c2s.len());
let mut request = None;
let used = server.recv(&c2s, 0, &mut |ev| {
if let Event::Headers { stream, headers, .. } = ev {
request = Some((stream, headers.path().unwrap().to_vec()));
}
});
assert_eq!(used, c2s.len()); // a caller keeps unconsumed bytes for the next call
let (stream, path) = request.unwrap();
assert_eq!((stream, &path[..]), (id, &b"/"[..]));
server.send_response(stream, 200, &[(b"content-type", b"text/plain")], false).unwrap();
assert_eq!(server.send_data(stream, b"hello", true), Ok(5));
server.stream_finished(stream);
let s2c = server.output().to_vec();
server.advance_output(s2c.len());
let mut body = Vec::new();
client.recv(&s2c, 0, &mut |ev| {
if let Event::Data { data, .. } = ev {
body.extend_from_slice(data);
}
});
assert_eq!(body, b"hello");Received data stays charged to the flow-control windows until the application calls
Connection::release; that bounds what a stream and the connection can buffer. Outbound
data goes through Connection::send_data, which accepts only what the windows and the
output buffer cap allow and reports the rest as backpressure; Connection::poll_writable
names streams that can send again.
DoS accounting (plan §2.7): the concurrency limit counts streams whose handler is still
running (the application calls Connection::stream_finished), not just open streams, so
resets cannot free capacity while work continues (MadeYouReset, CVE-2025-8671; Rapid Reset,
CVE-2023-44487). Sliding-window Budgets cap RST_STREAM (received and caused), PING,
SETTINGS, empty frames, PRIORITY and small WINDOW_UPDATE frames; header blocks are capped in
bytes and in CONTINUATION frames. Exceeding any of them sends GOAWAY(ENHANCE_YOUR_CALM).
Re-exports§
Modules§
- frame
- HTTP/2 frame layout (RFC 9113 §4, §6): constants, the 9-byte header, and writers that append frames to an output buffer.
Structs§
- Budgets
- Limits per window.
u32::MAXdisables a budget. - Config
- Settings and limits for one side of a connection.
- Connection
- One HTTP/2 connection, either end.
- Headers
- A received header block (request or response headers, or trailers).
Enums§
- Error
- Errors from the sending API.
- Event
- Something the peer did, reported by
Connection::recvandConnection::handle_timeout. - Role
- Which end of the connection this is.
Functions§
- base64url_
decode - Decodes base64url, with or without padding. Whitespace around the value is ignored; any other byte outside the alphabet is an error.
- base64url_
encode - Encodes bytes as unpadded base64url.
- http2_
settings_ header - The
HTTP2-Settingsheader value a client sends with an h2c upgrade request.