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.

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) -> Vec<u8> Render a :-prefixed keepalive line. Available in interp + compiled.
encode_event fn encode_event(event: String, data: String, id: String) -> Vec<u8> Render one event block as a string: (event, data, id) -> String. Available in interp + compiled.
encode_retry fn encode_retry(ms: i64) -> Vec<u8> Render a retry: reconnect-hint directive in milliseconds. Available in interp + compiled.
AppState type AppState TypeMap of Arc values shared across handlers.
State type State Newtype wrapper Arc 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.