Step 1 of 5 · Reading · ~3 min
Read
Routing & Responses
Building a Response
Parsing was defence, now you are the sender. A response is the same protocol in reverse, and every byte rule you enforced on clients becomes a promise you make to them. Browsers forgive a lot. Proxies, curl scripts and test harnesses do not. After this lesson your program turns a handler's decision (status, headers, body) into the exact bytes that go on the wire.
The anatomy
HTTP/1.1 200 OK\r\n
Content-Type: text/plain\r\n
Content-Length: 13\r\n
\r\n
Hello, world!
| Part | Rule |
|---|---|
| status line | HTTP/1.1, SP, three-digit code, SP, reason phrase, CRLF. Clients act on the code and ignore the phrase, but conventions pair them |
| header lines | Name: value CRLF, the same grammar you parsed in lesson 2 |
| empty line | exactly one CRLF. It is the pivot between metadata and payload |
| body | raw bytes, as many as the framing headers promise |
Content-Length is a byte count
The client needs to know where your body ends, so Content-Length must be the exact number of bytes you send. The classic bug is counting characters:
body text : café
characters : c a f é = 4
UTF-8 bytes : 63 61 66 c3 a9 = 5 <- this is the number
A client told 4 reads caf and one byte of é, then treats the last byte as the start of the next response. The same bug appears when the length is computed before the body is edited.
Responses that carry no body
- 1xx, 204 and 304: the status itself says there is no payload. Send no body and no
Content-Length. (A 204 with a length is a protocol violation, and a 304 only confirms a cache entry.) - Any response to HEAD: HEAD is GET without the body, and its whole purpose is to report metadata. The headers, including the
Content-Lengththe GET would have carried, are sent. The body is not.
Who owns the framing?
If a handler can set Content-Length by hand, a handler can get it wrong, and a wrong length hangs or corrupts the connection. Frameworks therefore treat length as the serializer's job: they ignore what the handler claims and compute it from the body they are about to write. This course does the same. Drop any Content-Length the handler supplies (names are case-insensitive) and append your own after the other headers.
Build it as data, render at the end
The shape that stays clean is a response object (code, headers, body bytes) that handlers fill in, and one render function that turns it into wire bytes. One function means one place where CRLF, counting and the no-body rules live, and every handler you write later inherits them. That object is the Response every web framework hands its users.
The contract for this course
The input is a handler's decision, written with LF line ends:
<METHOD> <status>
Header-Name: value
Another: value
(empty line)
<body bytes, everything to the end of input>
Print the wire bytes. Reason phrases come from the table in the starter, and a code that is not in it gets the phrase Unknown. Headers keep their order and spelling. Nothing is added except Content-Length.
Common mistakes
- Counting characters, so one accent corrupts the length.
- Sending
Content-Length: 5because the handler said so while the body is 11 bytes. - Putting a body, or a length, on a 204 or a 304.
- Dropping the length on HEAD, or sending the body with it.
- Writing a bare
\nbetween lines. Strict clients refuse the response.
Your exercise
The starter parses the handler spec into a method, a status, a list of header lines and the body, and gives you the reason table. You write render. The mistake most likely to catch you is the byte count on a body that is not plain ASCII.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…