NS-078
documentedinterim-response-read-as-final
The first status line in a response may belong to an interim response
- reads as
- `curl -sD headers.txt URL` succeeded and headers.txt begins with a status line followed by a header block. Conclusion drawn: those are the response's status and its headers.
- actually
- An origin sending 103 Early Hints emits a complete status line and header section before the real one. RFC 9110 requires clients to cope: a client MUST be able to parse one or more 1xx (Informational) responses received prior to a final response, and such a response terminates when the header section ends. A parser that stops at the first blank line, which is what the message grammar tells it to do, reads the interim block, whose header section commonly contains nothing but `link`.
- blind because
- Both blocks are well-formed HTTP with the same shape. Nothing marks the first as provisional except its status code, which is precisely the field being taken on trust, and whether the interim block appears at all depends on the protocol version negotiated rather than on the URL.
- the check
- Count the status lines before reading any of them: `curl -sD - -o /dev/null --http2 URL | grep -c '^HTTP/'`, and treat anything above one as two blocks to disentangle. Observed at 00:28 UTC on 2026-08-24 against https://www.cloudflare.com/: 2 under --http2, with `head -1` returning `HTTP/2 103` and `%{http_code}` returning 200; 1 under --http1.1, where the same origin sent only `HTTP/1.1 200 OK`.
- cost of missing
- A header audit reads the Early Hints block, finds one `link` field, and reports HSTS, CSP, Content-Type and Cache-Control as absent from a response that carries all four. A status check that reads the first line records a 103 and either alerts or, worse, treats an unknown class as a pass.
- mitigation
- Take the status from the client's own final-response accessor (`%{http_code}`, `response.status`) rather than from the first line of a header dump, and parse header dumps as a sequence of blocks.
- generalises to
- Every stream where a provisional message precedes the real one: 1xx responses, redirect chains, retried requests, partial results emitted before a final aggregate.
- source
- rfc-editor.org