1Show the Level 1 solution
2**A.**
31. `public, max-age=31536000, immutable`.
42. `private, no-store`.
53. `public, max-age=60, s-maxage=300, stale-while-revalidate=60, stale-if-error=600`.
64. `private, no-store`.
75. `public, s-maxage=5` (micro-cache for a few seconds).
89**B.**
101. **False.** Personal responses can't be shared; the CDN only helps the connection.
112. **False.** It creates one cache entry per user and leaks risk; serve personal parts separately.
123. **False.** Browsers keep their copy until their own max-age ends.
134. **True.**
145. **True.** They're ordinary HTTP files.
1Show the Level 2 solution
21. 6 × 60 = **360 ms** to Mumbai; 6 × 8 = **48 ms** to the local PoP.
32. 10,000 × 0.05 = **500** a second at 95%; 10,000 × 0.01 = **100** at 99%.
43. 2,000,000 × 1.5 MB = **3 TB** a day served; origin: 5% of that = **150 GB**.
54. 1,200 ÷ 6 = 200 per quality × 5 = **1,000** files. One 720p segment: 2.8 Mbps × 6 s = 16.8 Mb ÷ 8 = **2.1 MB**.
65. **50** without a shield, **1** with it.
1Show the Level 3 solution
2Tested solution (Python 3), the key parts:
34```python
5def cache_key(url):
6 parts = urlsplit(url)
7 params = [(k, v) for k, v in parse_qsl(parts.query)
8 if not k.startswith(("utm_", "fbclid", "gclid"))]
9 query = urlencode(sorted(params))
10 return f"{parts.netloc.lower()}{parts.path}" + (f"?{query}" if query else "")
111213def cdn_ttl(header):
14 cc = parse_cache_control(header)
15 if cc.get("no-store") or cc.get("private"):
16 return None # never in a shared cache
17 if "s-maxage" in cc:
18 return cc["s-maxage"] # shared caches use this first
19 return cc.get("max-age")
202122class Edge:
23 def get(self, url, now, origin_up=True):
24 key = cache_key(url)
25 hit = self.store.get(key)
26 if hit and now < hit[1]:
27 return hit[0], "HIT"
28 if not origin_up:
29 if hit and now < hit[1] + hit[3]:
30 return hit[0], "STALE" # stale-if-error
31 return None, "ERROR"
32 body, header, tags = self.origin(url)
33 ttl = cdn_ttl(header)
34 if ttl is not None:
35 stale = parse_cache_control(header).get("stale-if-error", 0)
36 self.store[key] = (body, now + ttl, tags, stale)
37 return body, "MISS"
3839 def purge_tag(self, tag):
40 for k in [k for k, v in self.store.items() if tag in v[2]]:
41 del self.store[k]
42```
4344All checks pass: 50 tracking variants collapse to 1 key; s-maxage, private and no-store are respected; the edge hits, expires, serves stale while the origin is down and then errors; a tag purge drops a book page and its cover together; a shield cuts 50 origin fetches to 1; the video ladder picks 720p at 4 Mbps; failover routes to the healthy CDN; and the public account page is served to the wrong user while the private one isn't. The full file is in `code/ch26_cdn.py`.
1Show the Level 4 solution
21. **What happened:** the account page is HTML, so it got `public, max-age=300`. Asha requested `/account`; the CDN cached **her** page under the key `/account` (cookies aren't in the key). Ravi requested `/account` within 5 minutes; the CDN found a fresh copy and served **Asha's page** to Ravi. The tested demo reproduces exactly this.
32. **The fix:** cache only pages that are the same for everyone, and mark personal ones private:
45```python
6PUBLIC_HTML = ("/", "/books/", "/authors/", "/categories/")
78@app.after_request
9def add_caching(response):
10 if response.mimetype != "text/html":
11 return response
12 if request.path.startswith(PUBLIC_HTML) and not current_user.is_authenticated:
13 response.headers["Cache-Control"] = "public, max-age=60, s-maxage=300"
14 else:
15 response.headers["Cache-Control"] = "private, no-store"
16 return response
17```
1819Better still, **default to `private, no-store`** and opt public pages in. Two other places the old rule harms: the **cart and checkout** pages (other users' carts, payment forms), and any page with a **CSRF token or flash message** baked in (one user's token served to others breaks forms and security). Also, logged-in users seeing a "Hi Asha" header on book pages.
203. **Right now:** **purge** `/account` and every personal path (or purge everything if unsure), **disable** the rule in CDN config (most CDNs can override origin headers to bypass caching for paths), then treat it as a **security incident**: work out which users' pages could have been exposed and follow your disclosure process.
1Show the Level 5 (sketch) solution
21. **Caching rules:**
3 - Versioned JS/CSS and covers (`cover-42-v3.jpg`): `public, max-age=31536000, immutable`.
4 - Book and author pages (anonymous view): `public, max-age=60, s-maxage=600, stale-while-revalidate=60, stale-if-error=3600`, tagged `book-{id}`, `author-{id}`.
5 - Homepage: `public, max-age=30, s-maxage=30` normally; micro-cached at `s-maxage=5` during sales.
6 - Account, cart, checkout, APIs under `/me`: `private, no-store`.
7 - Public JSON (`/api/books/42`): like book pages.
82. **Cache keys:** host + path + sorted query parameters, dropping `utm_*`, `fbclid`, `gclid`; `Vary: Accept-Encoding` only; device-specific images handled by separate URLs or edge image resizing, not Vary on User-Agent.
93. **Changes:** price or details change → purge tag `book-{id}`; cover change → new versioned URL (no purge); takedown → purge by tag and URL plus 410 from origin; personal greeting fetched client-side so pages stay shareable.
104. **Big Book Sale:** origin shield in Mumbai with request collapsing; homepage and listing micro-caching; pre-warm top pages; stale-while-revalidate so refreshes never block; edge rate limits and bot protection (Chapter 25).
115. **Video and outages:** HLS with 6-second segments in 5 qualities, stored in object storage behind the CDN, segments cached long, playlists short. For a CDN outage: a second CDN with DNS-based health steering for static assets and video, stale-if-error for origin trouble, CDN config managed as code with staged rollout.