0%

Chapter 8

Caching and Conditional Requests

May I Reuse This Response?

Chapter 7 left the reading protected: a session says who is logged in, and only a writer’s token may change a book. Every client still downloads the whole list every time it asks. Picture a reading list app that refreshes its screen by sending GET /books every five seconds. The books change a few times a day, so almost every reply repeats the last one byte for byte. The server builds the same again, and the client receives and parses bytes it already has.

’s answer comes in two halves. The server can say how long a response may be reused, and the client can ask whether the copy it holds is still current. This lesson is the first half: a that says what a client may do with a copy it has kept. The rest of the chapter builds both halves into your server and your client.

The four directives

That header is Cache-Control. Its is a list of directives separated by commas, such as cache-control: max-age=60, private. A directive is a name, sometimes followed by = and a value. Four of them cover most of what servers say:

DirectiveWhat a client may do with a copy it kept
max-age=Nreuse it without asking until it is N seconds old; after that it is stale
no-cachekeep it, but ask the server before every reuse
no-storenot keep it at all
privatea cache that serves one user may keep it; a shared cache that serves many users may not

A cache is anything that keeps responses in order to reuse them. Your client gets one in Lesson 5, and it serves one user: whoever runs it. A shared cache sits between many clients and a server, for example a proxy run by a company, and hands one stored response to everyone who asks for the same . That is why private exists: a reply that holds one person’s data must not be handed to the next person. This course runs no shared cache; you only need to recognize the word.

no-cache is the directive whose name misleads. It does not mean “do not cache”. It means “you may keep it, but check with me before you use it”. Checking costs little, as Lesson 4 shows, because the server can answer “still the same” without sending the body again. no-store is the one that means “do not keep it”, and a server sends it on replies that should never sit in a cache, such as a reply that names who is logged in. Lesson 6 puts it on exactly those replies.

Directive names are case-insensitive (RFC 9111, section 5.2), so Max-Age=60 means the same as max-age=60. A reply may also carry more than one cache-control line, and together they make one list. You will meet other directives in real replies, such as public, must-revalidate and s-maxage; this course does not use them.

Reading the header

Reading a Cache-Control value is a split at commas, the way Chapter 1 split header lines at a colon. Predict what the split alone gives:

What does this print?

print("max-age=60, private".split(","))

The second piece starts with a space, because the space after the comma belongs to no directive. So each piece is stripped before it is compared, and lowercased, because the names ignore case. Run this:

Try it

Change value to "no-store" or to "private,max-age=5" and run it again. The pieces come out the same whether or not a space follows the comma.

Expires and the Date line

Before Cache-Control existed, a server said how long a reply stayed good with the expires header. It holds a date and a time, not a number of seconds, in the HTTP-date format: the same format as the Date line that http.server puts on every reply your server sends. Python’s email.utils writes that format:

import email.utils

print(email.utils.formatdate(0, usegmt=True))  # Thu, 01 Jan 1970 00:00:00 GMT

0 is the first second of time, the count of seconds since 1 January 1970 in UTC that time.time() returns. http.server writes its Date line with this same , given the current time.

A date has a weakness that a count of seconds does not: it only works when the client’s clock agrees with the server’s. So when a reply carries both, max-age wins. RFC 9111 (section 5.3) tells a cache to ignore expires whenever max-age is present. You will still see expires on real replies, usually next to a max-age that says the same thing for newer clients. Your server will send only max-age.

A reply carries cache-control: no-cache. May the client keep the response?

What does cache-control: private allow?

A response has expires one hour ahead and cache-control: max-age=60. How long is it fresh?

Reuse is half the story. When a stored copy goes stale, the client still has to download the whole body again, even if nothing in it changed. The next lessons let a client ask “has it changed?” and receive a short answer, and that question needs a name for one version of a body. Lesson 2 makes that name: a fingerprint computed from the body’s bytes.