HTTP overview

Crate hopf-http: stream-first HTTP for bind and dial. Applications program HTTP Streams, not raw sockets. HTTP/1.1, HTTP/2, and HTTP/3 adapt a transport Endpoint into the same ServerHandler / ClientHandler SPI.

Standards

Spec Role in Hopf
RFC 9110 / 9112 HTTP semantics and HTTP/1.1 messaging
RFC 9113 HTTP/2 framing, streams, SETTINGS
RFC 7541 HPACK header compression
RFC 9114 HTTP/3 over QUIC
RFC 9204 QPACK
RFC 7540 §3.2 / prior-knowledge Cleartext h2c (Upgrade + preface sniff)
RFC 8441 Extended CONNECT (H2) — WebSocket / upgrade
RFC 9220 Extended CONNECT (H3)
RFC 7616 (+ Basic) Digest / Basic auth factories
Bearer Authorization: Bearer factory

Chunked transfer encoding and trailers are implemented on the Stream SPI; see Limitations for the HTTP/1.1 trailer gap.

Architecture

TcpListenerConfig / TcpConnectorConfig / Quic hooks
        │
        ▼
  ProtocolHandler adapters
  (H1Endpoint | H2Endpoint | CleartextHttpEndpoint |
   AlpnHttpEndpoint | H3*Connection via listen_h3/connect_h3)
        │
        ▼
     HttpStream  (one request/response)
        │
        ├── ServerHandler  ↔  ServerWriter
        └── ClientHandler  ↔  ClientWriter

Push event order on the server (with a body):

headers → start_request_body → request_body_content* → end_request_body → request_complete

Without a body: headers → request_complete.

Client handlers write in start, then receive response_headers → body* → optional response_trailers → response_complete.

Body chunks are zero-copy for the duration of each callback. Response bodies auto-chunk when applicable. Informational 1xx responses use ServerWriter::send_informational.

Version matrix

Version Server entry Client entry Transport notes
HTTP/1.1 H1Endpoint::server H1Endpoint::client Grammar-driven lexer tokens
HTTP/2 (TLS) AlpnHttpEndpoint or H2Endpoint::server H2Endpoint::client ALPN h2
h2c CleartextHttpEndpoint H2Endpoint::client(..., secure: false) Prior-knowledge preface + Upgrade
HTTP/3 listen_h3 (feature h3) connect_h3 QUIC + ALPN h3

Cargo features: default = [], h3 = ["dep:hopf-quic"], integration = ["h3"].

HttpLimits

Shared parser / connection limits (Gumdrop defaults):

Field Type Default Meaning
max_line_length usize 8192 Max request-line or header field-line length
max_header_count usize 100 Max header fields
max_chunk_size usize 10 MiB Max chunk-size value
max_request_body usize 16 MiB Max aggregate request body
use hopf_http::HttpLimits;

let limits = HttpLimits {
    max_request_body: 64 * 1024 * 1024, // raise for large uploads
    ..HttpLimits::default()
};

Additional framing knobs live on the parsers (not HttpLimits):

Knob Default Where
H2 max frame size 16_384 H2Parser::with_max_frame_size
HPACK dynamic table configurable hopf_http::h2::hpack
H3 max frame 16 MiB H3 parser

Endpoint constructor flags:

Constructor Extra args
H1Endpoint::server(factory, limits, secure) secure: bool
H1Endpoint::client(factory, limits, secure) secure: bool
H2Endpoint::server(factory, limits, send_settings_on_connected) send SETTINGS on connect
H2Endpoint::client(factory, limits, secure) secure: bool
CleartextHttpEndpoint::new(factory, limits) h2c auto-detect
AlpnHttpEndpoint::new(factory, limits) ALPN → H2 / H1

Cleartext, ALPN, and H3 wiring

Cleartext (H1 + h2c)

CleartextHttpEndpoint sniffs the HTTP/2 connection preface for prior-knowledge h2c, supports the h2c Upgrade path (101), and otherwise falls back to HTTP/1.1.

use std::sync::Arc;
use hopf_core::{ProtocolHandler, Runtime, RuntimeConfig, TcpListenerConfig};
use hopf_http::{CleartextHttpEndpoint, HttpLimits, ServerHandlerFactory};

fn listen_cleartext(rt: &Runtime, factory: Arc<dyn ServerHandlerFactory>) -> std::io::Result<()> {
    let limits = HttpLimits::default();
    let f = Arc::clone(&factory);
    rt.add_tcp_listener(TcpListenerConfig::new("127.0.0.1:8080".parse()?, move || {
        Box::new(CleartextHttpEndpoint::new(Arc::clone(&f), limits)) as Box<dyn ProtocolHandler>
    }))?;
    Ok(())
}

TLS + ALPN (H1 / H2)

Wire TLS on TcpListenerConfig / TcpConnectorConfig via hopf-core's in-tree TLS (acceptor_from_pem et al.), and use AlpnHttpEndpoint as the ProtocolHandler. Negotiated ALPN selects H2 or H1. Typical ALPN list: &[b"h2", b"http/1.1"].

use hopf_core::{ProtocolHandler, TcpListenerConfig};
use hopf_http::{AlpnHttpEndpoint, HttpLimits};
use hopf_core::acceptor_from_pem;
use std::path::Path;
use std::sync::Arc;

let acceptor = acceptor_from_pem(
    Path::new("cert.pem"),
    Path::new("key.pem"),
    &[b"h2", b"http/1.1"],
)?;
let factory: Arc<dyn hopf_http::ServerHandlerFactory> = /* ... */;
let limits = HttpLimits::default();
let f = Arc::clone(&factory);
let cfg = TcpListenerConfig::new(addr, move || {
    Box::new(AlpnHttpEndpoint::new(Arc::clone(&f), limits)) as Box<dyn ProtocolHandler>
})
.with_tls(acceptor);

HTTP/3

Enable feature h3. Build a QUIC server/client config with ALPN h3 (hopf_quic::ALPN_H3), then call listen_h3 / connect_h3. See quic-h3.md.

use hopf_http::{listen_h3, HttpLimits};
use hopf_quic::{server_config_self_signed, ALPN_H3};
use std::sync::Arc;

let (server_cfg, _leaf_pem) = server_config_self_signed(&["localhost"], &[ALPN_H3])?;
let handle = listen_h3(
    "127.0.0.1:4433".parse()?,
    server_cfg,
    factory,
    HttpLimits::default(),
)?;
// QuicDriverHandle owns the UDP driver thread — shut down or drop explicitly.

Upgrade seams

ServerWriter::upgrade(headers, handler) hands the connection (H1) or stream (H2/H3) to a ProtocolUpgradeHandler after a successful switch:

Transport Success status Byte delivery
HTTP/1.1 101 Switching Protocols Raw connection bytes → receive
HTTP/2 / HTTP/3 200 Extended CONNECT Stream DATA payloads → receive

Outbound bytes are drained via ProtocolUpgradeHandler::take_outbound. Used by hopf-websocket (RFC 6455 / 8441 / 9220) and similar upgrades. Returns false if the transport cannot upgrade (already responded, wrong version, etc.).

Shared types

Type Purpose
Headers / Header Ordered, case-insensitive; pseudo-header helpers (:method, :path, :scheme, :authority, :status)
HttpStream / HttpRole Stream identity
HttpVersion Http10 / Http11 (H1 messaging)
HttpError / HttpResult Crate errors
reason_phrase(code) Status reason text
Auth factories BasicAuthFactory, DigestAuthFactory, BearerAuthFactory — see server.md

Examples

Example How to run
examples/http-hello cargo run -p http-hello -- 127.0.0.1:8080 (optional --tls)
examples/http-get cargo run -p http-get -- [--http2\|--h2] [--http3\|--h3] [--ca pem] [--server-name name] ADDR PATH
examples/http3-hello cargo run -p http3-hello -- 127.0.0.1:4433

Smoke: cargo test -p hopf-http --features h3 h3_get_hello.

Limitations

See also