Figures · nine plates
The wire,
drawn to scale.
A protocol is a shape before it is a rule. Each plate below is one of the shapes this library has to get right: a head, a chunk, a frame, a stream, and the arithmetic a cache does over a clock.
An HTTP/1.1 message
RFC 9112 §2What to notice
The head has no length field. It ends at the first empty line, which is why a reader scans for four octets rather than jumping to an offset — and why the octet count it returns matters: everything after it is body, or the next message on a kept-alive connection.
Fields are bytes. Deciding that "v7" is a quoted string is the next layer's problem, and a decision that can fail.
Chunked body
RFC 9112 §7.1What to notice
The size is hex and counts the data, not the CRLF that follows it. A chunk extension may sit after the size behind a semicolon, and a reader that treats it as part of the number reads the wrong body.
The last chunk carries zero octets and is followed by the trailers — fields that belong to the message but arrive after its body.
HTTP/2 frame header
RFC 9113 §4.1What to notice
Every frame starts with the same nine octets, so a reader can skip a type it does not know by trusting the length — which is the point of putting the length first.
Flags mean different things per type: the same bit is END_STREAM on a DATA frame and END_HEADERS on a HEADERS one. The type and the flag are read together or not at all. The reserved bit is not spare: a receiver that sees it set treats the frame as a connection error.
A variable-length integer
RFC 9000 §16| Prefix | Width | Value | Where it is used |
|---|---|---|---|
| 00 | 1 octet | 6 bits · 0–63 | a small frame type or stream type |
| 01 | 2 octets | 14 bits · 0–16 383 | most lengths |
| 10 | 4 octets | 30 bits · 0–2³⁰−1 | a body that does not fit in 16 KiB |
| 11 | 8 octets | 62 bits · 0–2⁶²−1 | the connection's stream count |
What to notice
The first two bits say how many bits the value has, and the value is written in as few octets as its own size allows. The encoding is self-describing, so a reader never needs the field's type to parse it.
QUIC and HTTP/3 use the same integer, which is why it lives in moonvar rather than here.
A WebSocket frame
RFC 6455 §5.281 82 01 02 03 04 69 6b — 81 is FIN and the text opcode, 82 is the mask bit and a length of two, and hi arrives as 69 6b.What to notice
The mask is not encryption and is not meant to be: it exists so that a client cannot be tricked into sending octets a proxy would read as a request. That is also why a server must not mask, and why a client that does not mask is refused.
RSV1 belongs to the extension, which is the next plate.
The stream permessage-deflate shares
RFC 7692 §7.2One DEFLATE stream, stopped and resumed at each message boundary. The receiver puts the four octets back before decompressing, which is what makes the pieces one stream again.
What to notice
The window is not reset between messages unless the terms say server_no_context_takeover or client_no_context_takeover. A match in message 2 may reach into message 1, which is where most of the ratio comes from.
That is also why a message cannot be decompressed on its own: the stream, not the message, is the unit the compressor works in.
How old is a stored response
RFC 9111 §4.2.3
apparent = max(0, response_time − date)
corrected = age + (response_time − request_time)
current = max(apparent, corrected) + (now − response_time)
What to notice
The largest of the two ages wins: what the origin said, and what the trip added. That max is why a response dated in the future is not newborn — the delay still counts.
Freshness is age ≤ lifetime, not <. A response is stale once its age is greater than the lifetime, so the second it turns exactly is still fresh; move the sliders to the boundary and watch the verdict change.
What a redirect does to the method
RFC 9110 §15.4| Status | From | To | Body | Why |
|---|---|---|---|---|
| 301 | POST | GET | dropped | moved permanently; the original said so |
| 302 | POST | GET | dropped | found; what browsers have always done |
| 303 | PUT | GET | dropped | see other; the answer is elsewhere |
| 307 | POST | POST | kept | temporary; the method must not change |
| 308 | PUT | PUT | kept | permanent, and the same prohibition |
What to notice
303 is the only one that rewrites for every method: it exists to turn a submission into a fetch. 307 and 308 exist for the opposite reason, and a client whose body cannot be replayed must refuse them rather than send an empty one.
Credentials are a separate decision from the method: Authorization and Cookie are dropped when the origin changes, compared by scheme, host and the effective port.
An alternative service
RFC 7838 §3What to notice
An alternative is authoritative for the origin, not for itself: a connection to it still presents the origin's name in TLS and its Host. That is what makes it a redirection rather than a different site.
clear as the whole value forgets every alternative the origin ever advertised. A member this reader cannot parse is dropped rather than failing the field: the others are still what the origin said.
Each plate is drawn from the section named in its header. The calculator runs RFC 9111 §4.2.3 with the same comparison the library uses.