Skip to content
Lesson 2 of 16

Step 1 of 5 · Reading · ~4 min

Read

Connection & Parsing

Parsing Headers

After the request line come the headers: the request's metadata, one Name: value per line, ended by an empty line. Your program will read that block from raw bytes and print one normalised entry per header name, or the exact reason the block is unacceptable.

The shape on the wire

This is what curl http://localhost:8080/ sends after its request line:

Host: localhost:8080\r\n
User-Agent: curl/8.5.0\r\n
Accept: */*\r\n
\r\n                        <- an empty line: the headers are over

Each line is a field name, a colon, optional whitespace, a value and CRLF (RFC 9112 section 5). The empty line is the only signal that the block has ended. Everything after it is the body, or the next request. A parser that keeps going past the empty line turns body bytes into headers: a body of Fake: header would then "send" a header the client never wrote.

Three rules every server applies

Names are case-insensitive, values are not. Content-Length, content-length and CONTENT-LENGTH are one header. Store the lowercased name so every later lookup is a plain comparison, and leave the value alone: ETag values and base64 credentials are case-sensitive.

Split at the first colon, trim the value. The name is everything before the first colon, the value is everything after it. Optional whitespace (spaces and tabs) around the value is the sender's whim: trim it, but keep interior spaces. Referer: http://a.test/x?y=1:2 has colons in the value, and splitting at every colon shatters it.

The name is a token. Letters, digits and the punctuation !#$%&'*+-.^_|~ and the backtick. No space is allowed before the colon: Content-Length : 5 is malformed, because a front proxy that strips that space and a back end that rejects it will disagree about the body length, and that disagreement is a request-smuggling attack.

A policy for duplicates

The same name may appear twice. RFC 9110 section 5.3 says a recipient may combine them into one value joined by a comma and a space, in the order received, so Accept: text/html followed later by Accept: application/json is accept: text/html, application/json. This course combines every name that way, with one exception: Host must appear exactly once. Without it the server cannot tell which site was meant, and two of them let two layers pick different ones.

Lines you must refuse

The block is read from top to bottom and the first problem wins. The reason codes are part of the output.

BytesReasonWhy
a line with a bare LF, not CRLFline-endingsame smuggling risk as the request line
a line starting with a space or tabfoldobsolete line folding: some parsers glue it to the previous header, others see a new one
a line with no colonno-colonnot a field line
empty name, a space or a non-token byte in the namebad-nameincludes the space before the colon
the stream ends before the empty lineincompletethe client has not finished
after the block: no Host, or more than onehostHTTP/1.1 requires exactly one

Output on failure is one line, 400 <reason>. On success it is one line per distinct name in order of first appearance: name: value. A header whose value is empty prints as name: with nothing after the colon.

Common mistakes

  • Lowercasing the whole line. etag: "AbC" is no longer the value the client sent.
  • Splitting on every colon, or on ": ", which loses Content-Length:5 (no space) and mangles URLs in values.
  • Trimming the value with a call that also removes interior runs of spaces. Only the ends are optional whitespace.
  • Reading until end of input instead of the empty line, so the body leaks into the header map.

Your exercise

The starter reads the bytes and walks the block one CRLF-terminated line at a time. You validate each line, split it, normalise it, apply the duplicate and Host policies, and print the result. The line most likely to catch you is the one the lesson spent a paragraph on: the space before the colon.

Up nextReading the Request BodyConnection & Parsing

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…