Step 1 of 5 · Reading · ~3 min
Read
Connection & Parsing
Parsing Headers
After the request line come the headers — the request's metadata, one Name: value per line, ended by one blank line. The format looks trivial, and the ways it isn't trivial are precisely the parts exercises (and attackers) test. This lesson builds a header parser with the three normalization rules every real server applies.
The shape on the wire
GET /api/users HTTP/1.1\r\n
Host: example.com\r\n
Content-Type: application/json\r\n
Content-Length: 27\r\n
\r\n ← blank line: headers end here
Per line: a field name, a colon, optional surrounding whitespace, the value, CRLF. The blank line (\r\n alone) is load-bearing — it's the only signal that headers are over and the body (if any) begins. A parser loops: read line; blank → done; otherwise split at the first colon.
Rule 1: names are case-insensitive; values are not
Content-Length, content-length, and CONTENT-LENGTH are the same header — the spec says so, and clients exercise the freedom. The standard implementation move is to normalize names to lowercase at parse time and store them that way, so every later lookup is one exact-match. Values keep their case untouched — Content-Type: TEXT/HTML normalized to lowercase would corrupt values where case matters (ETags, base64 credentials).
Rule 2: trim the value, split at the FIRST colon
Host: example.com → name host, value example.com — optional whitespace around the value is the sender's whim, trimmed by you. And first colon only:
Referer: http://example.com/page
Split at every colon and this shatters. Name is everything before the first colon; value is everything after it (trimmed). One more validation with security teeth: no whitespace allowed before the colon — Content-Length : 5 is malformed (400), because parsers disagreeing about that space is an actual request-smuggling vector. Strictness at boundaries, again.
Rule 3: duplicates happen — have a policy
The same header can legally appear twice. The general rule: equivalent to one header with comma-joined values (Accept: a + Accept: b ≡ Accept: a, b). But Set-Cookie breaks the rule (cookies can contain commas — it must stay a list), and a duplicated Content-Length with different values is an attack signature (smuggling again) that real servers reject outright. Your exercise specs its policy — comma-join, keep-list, or reject — and the meta-lesson is that you need a policy: the parser that silently keeps "the last one" has made a security decision by accident.
The headers that run the show
Parsing is generic; a few names steer the whole server, worth knowing as you store them: Host (mandatory in HTTP/1.1 — its absence is a 400; virtual hosting hangs off it), Content-Length (how many body bytes follow — next lesson's whole subject), Connection (keep-alive vs close — chapter 3), Content-Type, and Transfer-Encoding (the Content-Length alternative with its own lesson). Your parsed, normalized header map is the input to every remaining chapter — build it boringly correct.
Your exercise: Parse and Normalize Headers
Raw header lines in; one normalized name: value per line out, with ERR malformed: <line> for a line carrying no colon at all. The exercise makes you build the three rules this lesson opened with: split at the first colon, lowercase the name, trim the value — and its ladder is exactly those, one rung at a time. A plain pair, then a name in the wrong case, then a value padded with whitespace on both sides (note that interior spaces survive — you are trimming the value, not squeezing it), then a value containing a comma, then a malformed line that must not stop the ones after it, and finally a line whose name is empty.
The rest of this lesson — duplicate policy, rejecting a space before the colon, treating a missing blank line as an error — is real server behaviour that the exercise deliberately leaves out, because each one needs a policy decision that belongs to the server you are designing rather than to the parser. Build the parser here; carry the policies into the full server in chapter 3.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…