0%

HTTP Is Text on a Socket · practice

When There Is No Body

fetch now reads exactly the body a reply announces. Before changing anything, send the other request from Lesson 3 with it, HEAD instead of GET, from the Shell tab:

python wire.py HEAD

You should see it wait about two seconds and stop with TimeoutError: the reply announced the length GET would send, and no body follows on a connection that stays open. If it fails at once with ConnectionError instead, the service closed the connection; either way your reader waited for a body that HEAD never sends.

In Lesson 3, when fetch returned only the head, the same command printed the head at once. That head carries the same as the reply to GET, Content-Length: 182 included, the size of the page you decoded in Lesson 2. Your read_body trusted that number and asked for 182 bytes that were never going to come.

What HEAD is for

HEAD asks for exactly what GET would return, minus the body. The server sends the same status line and, as a rule, the same headers, and stops after the empty line. A client uses it to learn about a resource without transferring it: whether it exists, how big it is, what type it has. So in a reply to HEAD, Content-Length describes the body a GET would receive. It says nothing about this response, which has no body at all.

That makes the of the request part of reading the response. read_body already receives it as its method , which Lesson 5 left unused. The rule is one check, placed first: if the method is "HEAD", return b"" before looking at any header. Placing it first matters. A reply to HEAD may also leave Content-Length out entirely, and that is no reason to refuse it: with the check first, the length is never consulted.

HEAD is not the only case of a response without a body. A 204 No Content reply and a 304 Not Modified reply never carry one either; both arrive in later chapters, when your own server sends them.

A reply to a HEAD request says Content-Length: 412. What should read_body return?

Your task

In wire.py, add the rule to the start of read_body: when method is "HEAD", return b"" without reading anything and without checking any header. Leave the rest of read_body as it is, so GET replies are read exactly as before. fetch already passes its method to read_body.

Then send both requests again:

python wire.py HEAD
python wire.py

The HEAD request now prints at once: the status, the headers with content-length still ['182'], and 'body': b''. The GET request prints the same headers and the whole page as its body.

Then press Check my work. Lesson 7 collects the four pieces of fetch and proves them with tests of your own.

Task

Add one rule to the start of read_body in wire.py: when method is "HEAD", return b"" at once, before looking at any header and without receiving anything. Leave the rest of read_body as it is, so a reply to GET is still read exactly by its Content-Length.

In the , run python wire.py HEAD and then python wire.py.

Then press Check my work. The check calls fetch with a stand-in connect for HEAD requests whose replies you have not seen: a head that announces a length and is followed by silence on a connection that stays open, delivered whole, one byte at a time, and cut in two at every position (including inside the empty line), with the length header in unusual casing; and a head with no Content-Length at all. It checks that the body is b"" and that nothing was received after the head. It also calls fetch for GET to check that a GET body is still read, and calls read_body directly with "HEAD". It does not read your terminal or contact practice-api.