Skip to content

HTTP/HTTPS conformance ​

What Zion does with each shape of request: forward it unchanged, refuse it, or re-frame it. Every row below is asserted on the real TLS listener against a real origin by tests/http_conformance.rs (issue #741), so this page is the HTTP contract and a behaviour change fails the suite. It is the positive counterpart to the request-smuggling corpus (tests/http1_smuggling_corpus.rs, #697), which proves the negative: no desync form reaches the upstream.

The suite boots the binary with a proxy route to a recording origin, a preserve_host route, a static route, a compress-enabled route, a cached route and a WebSocket route, and drives them with a raw TLS client (openssl s_client, byte for byte) and an HTTP/2 client (curl --http2).

Methods (HTTP/1.1) ​

MethodBehaviour
GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONSforwarded to the upstream; the upstream's status is returned
TRACErefused with 405 at the edge, never forwarded
An unknown methodrefused with 405 at the edge, never forwarded

Request body framing ​

RequestUpstream
Content-Length bodyforwarded with Content-Length
Transfer-Encoding: chunked bodyparsed and re-framed by Zion's client (re-chunked); the client's raw framing never passes through

Hop-by-hop headers ​

Connection, Keep-Alive, Upgrade, and any header named in a Connection token are stripped before the upstream. Ordinary end-to-end headers are forwarded.

Request-target forms ​

FormBehaviour
origin-form (/path)forwarded
absolute-form (http://host/path)accepted and re-framed to origin-form upstream; the absolute URI and its authority never reach the upstream
asterisk-form (OPTIONS *)refused (404), never forwarded
authority-form (CONNECT host:port)refused (405), never forwarded

Host and preserve_host ​

RouteHost sent upstream
defaultrewritten to the upstream authority; the client's original Host is carried in X-Forwarded-Host
preserve_host = truethe client's Host is forwarded as-is (HTTP/1.1 only)

Expect: 100-continue ​

A request carrying Expect: 100-continue draws a 100 Continue interim response from Zion, then the request is forwarded.

Conditional requests ​

RequestBehaviour
If-None-Match matching the ETag (weak compare)304 Not Modified
If-None-Match: *304 when a representation exists
If-Modified-Since at or after Last-Modified304 (RFC 9110 date comparison, #744)
If-Modified-Since before Last-Modified200 with the body

If-None-Match takes precedence over If-Modified-Since.

Range requests (static files) ​

RequestBehaviour
Range: bytes=0-9206 Partial Content with Content-Range
an unsatisfiable range416 Range Not Satisfiable
a range on a compressible route206 served as identity (a partial representation is never compressed)

Response compression (compress feature, per-route opt-in) ​

RequestBehaviour
Accept-Encoding: br on a compress routeContent-Encoding: br, Vary: Accept-Encoding, Content-Length dropped
Accept-Encoding: gzipContent-Encoding: gzip
no Accept-Encodingidentity
a secret-bearing response (Set-Cookie / Cache-Control: private)identity unless the route sets allow_cookied (BREACH guard, ADR-0025)

Built without the feature, a compress route serves identity.

HTTP/2 ​

GET, HEAD and POST over HTTP/2 reach the HTTP/1.1 upstream and return its response, served back to the client as HTTP/2 (Zion translates h2 and h1). The upstream's status is passed through unchanged on both HTTP/1.1 and HTTP/2 for 2xx, 3xx, 4xx and 5xx (an origin 5xx is forwarded, not rewritten to 502, which is reserved for a dead upstream).

Caching and Vary ​

A cache_profile route caches a GET 200. When the upstream marks a response Vary: Accept-Encoding, Zion keys the cache by that variant: a repeated request with the same Accept-Encoding is served from the cache (the upstream is not asked again), while a different Accept-Encoding is a separate variant. An upstream's Vary header is forwarded to the client.

WebSocket upgrade ​

A mode = "websocket" route relays the upstream's 101 Switching Protocols to the client, upgrading the connection.

Not yet pinned ​

1xx interim responses other than 100 Continue (for example 103 Early Hints), multi-range requests, and HTTP/3 parity are not yet covered by the suite.

Released under the MIT License. · Privacy & legal