Reading — step 1 of 5
Read
Building a Response
Parsing was defense; now offense. A response is the same protocol in reverse — status line, headers, blank line, body — and since you're the sender now, every byte-exactness rule you enforced on clients becomes a promise you make to them. Browsers are forgiving; proxies, curl scripts, and graders are not.
The anatomy
HTTP/1.1 200 OK\r\n
Content-Type: text/html\r\n
Content-Length: 13\r\n
\r\n
Hello, World!
- Status line: version, space, status code, space, reason phrase, CRLF. The code is the machine-readable truth; the phrase (
OK,Not Found) is decoration for humans — clients ignore it, but convention pairs codes with canonical phrases and your spec will expect them. - Headers: same
Name: valueCRLF lines you parsed — now composed. - Blank line: the pivot, exactly
\r\n. - Body: the payload — HTML, JSON, bytes of a PNG.
The codes, as a vocabulary
Five families organize everything; a server author needs the families cold and a dozen members by name:
- 2xx success —
200 OK;201 Created(a POST made a resource);204 No Content(success, no body — and must not have one). - 3xx redirection —
301/302(moved: theLocationheader says where);304 Not Modified(the caching lesson's star). - 4xx client errors — they messed up:
400 Bad Request(your parsers' verdict),404 Not Found,405 Method Not Allowed(right path, wrong verb — courteously includes anAllow: GET, POSTheader),403 Forbidden. - 5xx server errors — you messed up:
500 Internal Server Error(your handler threw),501 Not Implemented.
The 4xx/5xx boundary is a blame assignment, and picking correctly matters operationally: 5xx pages ops, 4xx doesn't. A body that fails validation is a 400 (their fault), not a 500 (yours) — miscoding it wakes the wrong person at 3 a.m.
Content-Length: your turn to count
The framing problem from last lesson, now yours: the client needs to know where your body ends, so Content-Length must be the exact byte count of the body you send. The classic sender bugs: counting characters instead of bytes (UTF-8: é is 1 character, 2 bytes — a body with one accent is off by one), counting the body before an edit and sending after, or forgetting that 204 and every response to HEAD carry no body at all (but HEAD's response still states the Content-Length the GET would have — that's its entire purpose: metadata without payload).
A minimal correct server always sends: Content-Type (what the bytes are), Content-Length (how many), and — chapter 3 foreshadowing — Connection. Everything else is enrichment.
Build it as data, render at the end
The implementation shape that stays clean: a response object (code, phrase, header map, body bytes) that handlers fill in, and one serializer that renders it to the wire format — status line, sorted-or-specced headers, blank line, body, every CRLF in place. One rendering function means one place where byte-exactness lives, and every handler you write in the rest of this course inherits correctness from it. (You are, notice, building the exact Response object every web framework hands its users — Flask, Express, Fiber. Frameworks are this lesson with sugar.)
Your exercise: Build HTTP Response
Specs of (code, headers, body) in; exact wire bytes out. The graders check what clients would: canonical reason phrases, CRLF discipline, blank line present exactly once, Content-Length equal to byte length, no-body rules for 204/HEAD if specced. Assemble, render, count — then never think about serialization again, because every remaining lesson just fills in the object.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…