Skip to content

std::http

Status: experimental

HTTP/1.1 and HTTP/2 client and server. HTTP/2 negotiates via ALPN over TLS automatically (Go-style); h2c entry points are explicit. Write a handler as a cohort and an arena: cohort { } joins or cancels every goroutine the request spawned before the response is written, and its first child failure becomes the block's Err for the handler to turn into a status; arena { } bump-allocates what the request builds and frees it wholesale on every exit path, with escape checked at compile time. Dependency injection is closure capture - build the router from closures capturing the pool and the configuration.

API details and source

The implementation source contains the complete declarations and implementation notes. The table below lists canonical Gossamer call signatures; every item name links directly to its implementation file.

Item Canonical signature or declaration Description
Client type Client HTTP client; configure redirects and timeout via Client::builder().
Headers type Headers Case-insensitive header map.
Http2Config type Http2Config Per-connection HTTP/2 tuning (window sizes, max concurrent streams, frame caps).
Http2Error type Http2Error HTTP/2 server error: Io, Protocol, Handler.
Http2Handler trait Http2Handler Bounded-body HTTP/2 handler: serve(Request) -> Response.
Http2ServerHandle type Http2ServerHandle Handle to a running HTTP/2 connection for shutdown / in-flight counts.
Http2StreamingHandler trait Http2StreamingHandler Chunked-body HTTP/2 handler: serve(Request, StreamingResponseWriter) -> Result.
Method type Method HTTP method enumeration.
PushOptions type PushOptions Prioritization knobs for ResponseWriter::push_promise (weight, depends_on, exclusive).
PushStream type PushStream Server-initiated push stream returned by ResponseWriter::push_promise. Supports send_head / write / write_trailers / end.
Request type Request HTTP request value passed to a handler.
Response type Response HTTP response value returned from a handler.
ResponseStream type ResponseStream Streaming response body from http::stream; next_line / next_chunk, consumed by Response::stream.
Server type Server HTTP server bound to a TCP listener.
StatusCode type StatusCode HTTP status code.
StreamingResponseWriter type StreamingResponseWriter Streaming HTTP/2 response writer; set_status / header / write_chunk / finish.
Trailers type Trailers HTTP/2 trailing HEADERS (alias for Headers) - used by ResponseWriter::write_trailers and Request::trailers.
Reader type Reader Decodes a chunked body from any Read source (Rust-side; streaming).
Writer type Writer Encodes raw bytes into chunked frames over any Write sink (Rust-side; streaming).
decode fn decode(body: String) -> String One-shot: concatenates data chunks from a complete chunked body. Available in interp + compiled.
encode fn encode(body: String) -> String One-shot: wraps a buffer in chunked transfer-encoding with terminator. Available in interp + compiled.
Cookie type Cookie Parsed cookie with name, value, and Set-Cookie attributes.
CookieBuilder type CookieBuilder Fluent builder for Set-Cookie response headers.
SameSite type SameSite SameSite attribute: Strict / Lax / None.
parse_cookie_header fn parse_cookie_header(header: String) -> Vec<http::cookie::Cookie> Parse a Cookie request header into (name, value) pairs.
serialize fn serialize(name: String, value: String) -> String Render a Cookie as a Set-Cookie header value.
Config type Config Signing key, cookie / header names, and origin allowlist.
RouteAuth type RouteAuth Per-route policy: Required, Optional, or Skipped.
attach_cookie fn attach_cookie(request: http::Request, secret: String) -> Result<http::Request, errors::Error> Set the CSRF cookie on a Response.
check fn check(request: http::Request, secret: String) -> Result<http::Request, errors::Error> Combined origin + token gate; returns Err on failure.
extract_token fn extract_token(request: http::Request, secret: String) -> Result<http::Request, errors::Error> Pull a token from the configured header or form field.
issue_token fn issue_token(secret: Vec<u8>) -> Result<String, errors::Error> Mint a fresh CSRF token bound to the configured signing key.
origin_allowed fn origin_allowed(request: http::Request, secret: String) -> Result<http::Request, errors::Error> Origin / Referer allowlist check for unsafe methods.
verify_token fn verify_token(cookie_token: String, supplied_token: String, secret: Vec<u8>) -> Result<(), errors::Error> Constant-time verify of a presented token against the cookie value.
delete fn delete(url: String, body: String, headers: Vec<(String, String)>) -> Result<http::Response, errors::Error> One-shot DELETE: (url, body, headers) -> Result<Response, Error>.
Form type Form Parsed url-encoded body, queryable by field name.
FormBuilder type FormBuilder Builder for url-encoded request bodies.
get fn get(url: String, headers: Vec<(String, String)>) -> Result<http::Response, errors::Error> One-shot GET: (url, headers) -> Result<Response, Error>.
head fn head(url: String, headers: Vec<(String, String)>) -> Result<http::Response, errors::Error> One-shot HEAD: (url, headers) -> Result<Response, Error>.
Health type Health Aggregates a set of named probes into a single status.
Probe trait Probe One health check returning Ok or Err with a short message.
Chain type Chain Helper for composing middleware in a single value.
Handler trait Handler Anything serving (Request, Params) -> Response.
accepts_gzip fn accepts_gzip(request: http::Request) -> bool Check an Accept-Encoding header for a gzip token. Available in interp + compiled.
bearer_ok fn bearer_ok(request: http::Request, verify: Fn(String) -> bool) -> bool Run a verify closure on the request's Bearer token; false (without calling verify) when no Bearer header is present. Available in interp + compiled.
decode_basic_auth fn decode_basic_auth(request: http::Request) -> Option<(String, String)> Decode a Basic-auth Authorization header into (user, password). Interp tier.
new_request_id fn new_request_id() -> String Generate a process-monotonic request id string. Available in interp + compiled.
tag fn tag(handler: http::Handler) -> http::Handler Wrap a handler (tag(inner) -> Handler), prepending mw: to each response body. Deterministic composition primitive; available in interp + compiled.
Config type Config Per-form size, part-count, and disk-spill limits.
Form type Form Parsed multipart envelope: fields + file parts.
Part type Part One field or file entry from a multipart body.
PartData type PartData In-memory bytes or spilled-to-disk path for a part.
parse fn parse(request: http::Request) -> Result<http::multipart::Form, errors::Error> Stream-parse from any Read source into a Form.
Client type Client Native h1 client (Rust-side; full builder surface).
Error type Error Connect / Tls / Http / Redirect / Timeout / Io.
delete fn delete(url: String) -> Result<http::Response, errors::Error> One-shot DELETE → Result. Interp tier.
get fn get(url: String) -> Result<http::Response, errors::Error> One-shot GET → Result. Interp tier (compiled tier shares http::get).
post fn post(url: String, body: Vec<u8>, content_type: String) -> Result<http::Response, errors::Error> One-shot POST: (url, body, content_type). Interp tier.
put fn put(url: String, body: Vec<u8>, content_type: String) -> Result<http::Response, errors::Error> One-shot PUT: (url, body, content_type). Interp tier.
options fn options(url: String, headers: Vec<(String, String)>) -> Result<http::Response, errors::Error> One-shot OPTIONS: (url, headers) -> Result<Response, Error>.
post fn post(url: String, body: String, content_type: String) -> Result<http::Response, errors::Error> One-shot POST: (url, body, content_type) -> Result<Response, Error>.
Director type Director Fn(&mut Request) request mutator (Rust-side).
Proxy type Proxy Reverse-proxy handler (Rust-side).
forward fn forward(url: String, method: String, body: Vec<u8>) -> Result<http::Response, errors::Error> One-shot upstream forward: (url, method, body) -> Result<Response, Error>. Interp tier.
put fn put(url: String, body: String, content_type: String) -> Result<http::Response, errors::Error> One-shot PUT: (url, body, content_type) -> Result<Response, Error>.
Query type Query Parsed query string with typed get / get_all / contains.
request fn request(method: String, url: String, body: String, headers: Vec<(String, String)>) -> Result<http::Response, errors::Error> One-shot request with a string body: (method, url, body, headers) -> Result<Response, Error>.
request_bytes fn request_bytes(method: String, url: String, body: Vec<u8>, headers: Vec<(String, String)>) -> Result<http::Response, errors::Error> One-shot request with a byte body: (method, url, body: [u8], headers) -> Result<Response, Error>.
Handler trait Handler Anything callable as Fn(Request, Params) -> Response.
Params type Params Captured path parameters. Read inside a handler with r.path_value(name) -> String; returns "" for an undeclared name. All tiers.
Router type Router Routing table. Build with Router::new(), register routes via the verb methods, then pass to http::serve. Verb methods return the router so they chain with |>.
add fn add(router: http::router::Router, method: String, pattern: String) -> Result<(), errors::Error> Register a pattern-only route: (router, method, pattern). Used with lookup for low-level dispatch.
lookup fn lookup(router: http::router::Router, method: String, path: String) -> Option<http::router::Match> Find the index of the first route matching (method, path). Returns Option<i64>.
new fn new() -> http::router::Router Allocate a fresh Router handle.
serve fn serve(addr: String, handler: http::Handler) -> Result<(), errors::Error> Convenience: bind and serve an HTTP handler. Result<(), Error> - a bind failure is an Err value.
serve_h2c fn serve_h2c(addr: String, handler: http::Handler) -> Result<(), errors::Error> Bind a plain-TCP listener and serve h2c (HTTP/2 cleartext).
serve_tls fn serve_tls(addr: String, cert_pem: String, key_pem: String, handler: http::Handler) -> Result<(), errors::Error> TLS-terminating server: serve_tls(addr, cert_pem, key_pem, handler) -> Result<(), Error>. Builds a rustls config from the PEM cert chain + key and serves HTTPS with the same handler contract as serve.
SerializationMode type SerializationMode Session payload encoding: Json or Bincode.
Session type Session Per-request session view; mutations persist on response.
SessionConfig type SessionConfig Cookie name, domain, signing key, serialization mode.
SessionStore trait SessionStore Backend interface: load / save / delete by session id.
SignedCookieStore type SignedCookieStore Cookie-backed store with HMAC signature; no server state.
sign fn sign(value: String, secret: Vec<u8>) -> String Sign session data into a tamper-evident cookie value.
verify fn verify(value: String, secret: Vec<u8>) -> Result<String, errors::Error> Verify and decode a signed session cookie value.
with_session fn with_session(request: http::Request, secret: String) -> Result<http::Request, errors::Error> Run a closure with the session bound; persist any mutations.
Event type Event One SSE event (id, event, data, retry).
Stream type Stream Active SSE stream - handler writes events through it (Rust-side).
encode_comment fn encode_comment(comment: String) -> String Render a :-prefixed keepalive line. Available in interp + compiled.
encode_event fn encode_event(event: String, data: String, id: String) -> String Render one event block as a string: (event, data, id) -> String. Available in interp + compiled.
encode_retry fn encode_retry(ms: i64) -> String Render a retry: reconnect-hint directive in milliseconds. Available in interp + compiled.
AppState type AppState TypeMap of T values shared across handlers.
State type State Newtype wrapper T for ergonomic handler arguments.
FileServer type FileServer Static-file handler rooted at a directory (Rust-side; streaming).
mime_for_path fn mime_for_path(path: String) -> String Guess a MIME type from a file path's extension. Available in interp + compiled.
serve_file fn serve_file(path: String) -> Result<http::Response, errors::Error> Read a single file and return it as a Response struct. Interp tier.
stream fn stream(method: String, url: String, body: String, headers: Vec<(String, String)>) -> Result<http::ResponseStream, errors::Error> One-shot request read incrementally: (method, url, body, headers) -> Result<ResponseStream, Error>.
Error type Error Io / Protocol / BadHandshake.
Message type Message Text / Binary / Ping / Pong / Close.
WebSocket type WebSocket Accepted WebSocket connection (Rust-side framing).
accept fn accept(request: http::Request) -> Result<http::websocket::Conn, errors::Error> Upgrade an incoming Request to a WebSocket (Rust-side).
accept_key fn accept_key(key: String) -> String Compute RFC 6455 Sec-WebSocket-Accept from a client nonce. Available in interp + compiled.
close fn close(conn: http::websocket::Conn) -> Result<(), errors::Error> close(ws) -> Result<(), Error>: send a close frame and release the handle.
connect fn connect(url: String) -> Result<http::websocket::Conn, errors::Error> connect(url) -> Result: client TCP connect + RFC 6455 upgrade; returns a WebSocket handle.
is_websocket_upgrade fn is_websocket_upgrade(request: http::Request) -> bool Test whether an incoming Request carries a WebSocket upgrade handshake. Interp tier.
recv fn recv(conn: http::websocket::Conn) -> Result<http::websocket::Message, errors::Error> recv(ws) -> Result: next text message; Err on close/error.
send_binary fn send_binary(conn: http::websocket::Conn, data: Vec<u8>) -> Result<(), errors::Error> send_binary(ws, data) -> Result<(), Error>: send one binary frame.
send_text fn send_text(conn: http::websocket::Conn, text: String) -> Result<(), errors::Error> send_text(ws, s) -> Result<(), Error>: send one text frame.
serve fn serve(addr: String, handler: Fn(http::websocket::Conn) -> ()) -> Result<(), errors::Error> serve(addr, handler) -> Result<(), Error>: bind, upgrade each connection, dispatch the handler's handle(self, ws) per connection.

Request

The value a handler receives. Identical fields on every tier.

Field Type Meaning
method String Canonical uppercase method ("GET", "POST", ...).
path String Request path with the query string stripped (/users, never /users?page=2).
query String Raw query string without the leading ?; empty when absent.
query_pairs [(String, String)] Percent-decoded (key, value) pairs in query order; repeated keys preserved.
headers [(String, String)] Inbound headers; names lowercased, values trimmed. Repeats of the same name collapse to the last value.
body String Request body as UTF-8 (lossy - invalid sequences become U+FFFD).
raw_body [u8] Exact body bytes; use this for binary uploads or NUL-embedded payloads.
fn serve(&self, r: http::Request) -> http::Response {
    let who = header_of(r.headers, "x-user")     // names arrive lowercased
    let upload: [u8] = r.raw_body                 // byte-exact body
    http::Response::text(200, format("{} {} q={}", r.method, r.path, r.query))
}

Response

Constructors

  • Response::text(status, body) - sets content-type: text/plain; charset=utf-8.
  • Response::json(status, body) - sets content-type: application/json.
  • Response::stream(status, content_type, rs) - streamed body; see below.
  • http::Response { status, body, content_type } - constructs a binary response without a lossy round-trip through String; body may be [u8].
http::Response {
    status: 202,
    body: [65, 0, 66],
    content_type: "application/octet-stream",
}.with_header("x-k", "kv")

The byte array is written verbatim, so handlers can return binary payloads (images, gzip) including embedded NUL bytes.

with_header chaining

with_header(name, value) returns a new Response with the pair applied: any existing pair whose name matches case-insensitively is removed first, then the new pair is appended (replace-then-push). The last write for a given name wins:

let r = http::Response::text(201, "made")
    .with_header("X-Tag", "v1")
    .with_header("x-tag", "v2")     // replaces v1
    .with_header("x-extra", "e")
// r.headers carries ("x-tag", "v2") and ("x-extra", "e")

An explicit content-type entry in headers overrides the content_type field; with neither set the default is text/plain; charset=utf-8.

Client-side Response fields

Responses returned by the client carry:

Field Type Meaning
status i64 Numeric status code.
body String Body as UTF-8 (lossy).
raw_bytes [u8] Exact body bytes - the binary-safe counterpart of body.
content_type String The content-type header, "text/plain" when absent.
location String The location header (useful with redirect-following disabled).
headers [(String, String)] Response headers: lowercase names, wire order, duplicates preserved (set-cookie repeats survive).

Streamed responses - Response::stream

Response::stream(status, content_type, rs) takes a ResponseStream obtained from http::stream and serves it as a chunked response: the server writes the head, then drains the upstream reader to the client in chunked frames with a flush after each one, so bytes flow end-to-end without buffering the body.

Consume semantics: constructing Response::stream consumes the ResponseStream. After construction, next_line / next_chunk on that stream return None, and a stream serves exactly one response - handing the same stream to a second Response::stream produces an empty body.

fn forward_stream(method: String, target: String, body: String,
                  headers: [(String, String)]) -> http::Response {
    match http::stream(method, target, body, headers) {
        Ok(up) => http::Response::stream(up.status, up.content_type, up),
        Err(e) => http::Response::text(502, format("upstream error: {}", e)),
    }
}

HTTP/2 request streaming

Status: experimental.

The Rust-side HTTP/2 module contains a bounded, flow-control-aware RequestStreamingHandler scaffold for incremental request bodies, including chunk reads, trailers, stream deadlines, and receive-capacity release. The public Gossamer handler contract still receives a complete bounded Request on VM and AOT, so request-body streaming is not a shipped cross-tier API yet. Use Request.raw_body for bounded uploads and keep handlers within the configured body cap until the public streaming handler ABI lands.

Handlers and serve

A handler is a struct implementing http::Handler with a serve(self, Request) method. Both return shapes work, on every tier:

impl http::Handler for App {
    fn serve(&self, r: http::Request) -> http::Response { ... }          // bare
}

impl http::Handler for Api {
    fn serve(&self, r: http::Request) -> Result<http::Response, http::Error> {
        Ok(http::Response::text(200, "ok"))                               // Result
    }
}

http::serve(addr, handler) -> Result<(), Error>: a bind failure (port in use, bad address) is an Err value for the caller's match - not a panic - and Ok(()) is returned on graceful shutdown:

if let Err(e) = http::serve("127.0.0.1:8080", app) {
    eprintln("{}", e)
}

Server behavior

  • Body cap. Inbound bodies are capped at 1 MiB by default (Config::max_body_bytes); a request declaring or streaming more is rejected with 413 Payload Too Large and the connection closes. The header block is capped at 8 KiB.
  • Chunked inbound. Transfer-Encoding: chunked request bodies are decoded before the handler runs; trailer headers are merged into request.headers with the same lowercase semantics. A request carrying both Transfer-Encoding: chunked and Content-Length is smuggling-shaped and rejected with 400 Bad Request.
  • Malformed requests (unparseable request line or headers) get 400 Bad Request and the connection closes.
  • Wire casing. Response header names are written lowercase on the wire on every tier, so byte-level assertions are tier-portable.
  • Keep-alive. HTTP/1.1 connections are kept alive by default; the server inserts connection: keep-alive (or close for HTTP/1.0, client-requested close, or a handler-set connection: close). Expect: 100-continue is answered before the body is read.

One-shot request functions

http::request(method: String, url: String, body: String,
              headers: [(String, String)]) -> Result<Response, Error>
http::request_bytes(method: String, url: String, body: [u8],
                    headers: [(String, String)]) -> Result<Response, Error>
http::stream(method: String, url: String, body: String,
             headers: [(String, String)]) -> Result<ResponseStream, Error>

Method strings are case-insensitive ("GET", "post", ...). An unknown method fails before any connection is dialed: Err("http::request: unknown methodBOGUS") (same shape for request_bytes / stream with their own prefixes). Network-level failures render as Err("http: transport: ...") - connection refused, DNS, TLS, timeouts, and exhausted redirect budgets all use that prefix.

An empty body / empty byte array sends no request body.