Skip to content
Lesson 4 of 16

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!
PartRule
status lineHTTP/1.1, SP, three-digit code, SP, reason phrase, CRLF. Clients act on the code and ignore the phrase, but conventions pair them
header linesName: value CRLF, the same grammar you parsed in lesson 2
empty lineexactly one CRLF. It is the pivot between metadata and payload
bodyraw 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-Length the 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: 5 because 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 \n between 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.

Up nextStatic Path RoutingRouting & Responses

Discussion

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

Sign in to post a comment or reply.

Loading…