Part 3 — The conversation and the map
You now have a private, reliable, ordered channel open. Chapter 5 is what actually flows through it — the request/response language of the web, in full header-by-header detail. Chapter 6 then steps back and gives you the 7-layer OSI framework that organizes everything from Part 1 through here into one mental map — deliberately taught last, once you have concrete mechanisms to hang it on rather than abstract boxes to memorize first.
Chapter 5 — HTTP: The Conversation
TLS gave us an encrypted tunnel. Now we use HTTP to actually talk — to ask for pages and get them back.
The Simple Version (5-year-old)
HTTP is the language your browser and Netflix use to talk to each other.
Your browser says: "Please give me the home page." Netflix says: "Here it is! Also, here are some extra notes about it — how long to keep it, if it's secret, etc."
These "extra notes" are called headers. The actual page content is called the body.
HTTP Versions — How We Got Here
| Version | Year | Key Feature | Transport |
|---|---|---|---|
| HTTP/0.9 | 1991 | Only GET, no headers | TCP |
| HTTP/1.0 | 1996 | Headers, status codes, one connection per request | TCP |
| HTTP/1.1 | 1997 | Keep-alive (reuse connections), pipelining, chunked encoding | TCP |
| HTTP/2 | 2015 | Multiplexing, header compression (HPACK), server push, binary | TCP |
| HTTP/3 | 2022 | Built on QUIC (UDP), 0-RTT, no TCP head-of-line blocking | UDP (QUIC) |
Modern large sites commonly support HTTP/2 and increasingly HTTP/3, but the version used by any one request depends on browser support, server support, network policy, and fallback behavior.
HTTP/1.1 — The Foundation
HTTP/1.1 is a text-based protocol. Both request and response are human-readable.
Basic Structure
[Method] [Path] [Version]
[Header]: [Value]
[Header]: [Value]
[blank line]
[Body — optional]
Problem with HTTP/1.1: Head-of-Line Blocking
HTTP/1.1 sends one request at a time per connection (pipelining was specified but rarely worked). Loading a page with 50 resources (CSS, JS, images) sequentially over one connection is slow.
Workaround: Browsers open 6 parallel TCP connections per domain. But each connection has its own TCP and TLS handshake overhead.
HTTP/2 — Multiplexing
HTTP/2 solves head-of-line blocking by multiplexing multiple streams over a single TCP connection.
Key HTTP/2 Concepts
Streams: Each HTTP request/response pair is a stream with a unique stream ID. Multiple streams fly over one TCP connection simultaneously — no waiting.
One TCP connection:
Stream 1: GET /index.html ────────────────────────►
Stream 3: GET /style.css ──────────────────►
Stream 5: GET /app.js ────────────────────────────────►
Stream 7: GET /logo.png ──────────────────────────►
All in parallel, interleaved, over ONE TCP connection.
Binary Protocol: HTTP/2 uses a binary framing layer instead of text. Smaller, faster, less error-prone to parse.
HPACK Header Compression: HTTP headers are often large and repetitive (User-Agent, Cookie, Accept-Encoding are sent with every request). HPACK maintains a shared table of previously seen header values and references them by index instead of repeating the full string.
Request 1: User-Agent: Mozilla/5.0... (full string, 50 bytes)
Request 2: User-Agent: [index=1] (1 byte — just a reference)
Server Push: Server can proactively send resources it knows the browser will need, before the browser asks:
Browser: GET /index.html
Server: PUSH /style.css ← sends this before browser asks
Server: PUSH /app.js ← sends this before browser asks
Server: 200 OK [index.html]
In practice, server push is tricky (may push things already in browser cache) and is being phased out in HTTP/3.
HTTP/2 Limitation: Head-of-line blocking at the TCP level. If one TCP segment is lost, all HTTP/2 streams on that connection stall waiting for retransmission. This is solved by HTTP/3.
HTTP/3 — QUIC
HTTP/3 runs over QUIC — a new transport protocol that runs over UDP instead of TCP.
Why UDP?
QUIC implements its own reliability, ordering, and congestion control on top of UDP. This allows:
HTTP/2 over TCP:
Stream 1, Stream 2, Stream 3 — all over one TCP connection
If TCP packet is lost → ALL streams stall waiting for retransmit
This is TCP head-of-line blocking.
HTTP/3 over QUIC:
Stream 1, Stream 2, Stream 3 — each is independent
If QUIC packet for Stream 1 is lost → only Stream 1 stalls
Streams 2 and 3 continue unaffected
This eliminates head-of-line blocking completely.
QUIC Benefits
- 0-RTT connection establishment (for returning users — TLS 1.3 PSK combined with QUIC handshake in one go)
- Connection migration: Your connection survives IP address changes (switching from Wi-Fi to 4G). The QUIC connection ID remains stable even when your IP changes.
- Better performance on lossy networks (mobile, satellite)
- Multiplexing without head-of-line blocking
QUIC handshake (new connection):
Client → Server: QUIC Initial + ClientHello (QUIC + TLS combined)
Server → Client: QUIC Handshake + ServerHello + Certificate + Finished
Client → Server: Finished + [HTTP/3 request]
= 1 RTT total (TCP + TLS 1.3 = 2 RTTs)
QUIC 0-RTT (returning user):
Client → Server: QUIC Initial + [HTTP/3 request] (0 RTT!)
HTTP Request — Full Anatomy
Request Methods
| Method | Purpose | Body? | Idempotent? | Safe? |
|---|---|---|---|---|
GET |
Fetch a resource | No | Yes | Yes |
POST |
Create / submit data | Yes | No | No |
PUT |
Replace a resource | Yes | Yes | No |
PATCH |
Partially update | Yes | No | No |
DELETE |
Remove a resource | Sometimes | Yes | No |
HEAD |
Get headers only (no body) | No | Yes | Yes |
OPTIONS |
Ask what methods are allowed | No | Yes | Yes |
CONNECT |
Open a tunnel (used by proxies for HTTPS) | No | No | No |
Safe = does not change server state (GET, HEAD, OPTIONS). Idempotent = calling it multiple times has the same result (GET, PUT, DELETE).
Full Annotated Request
GET / HTTP/2
:method: GET ← HTTP/2 pseudo-headers use : prefix
:path: /
:scheme: https
:authority: www.netflix.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)
AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/120.0.0.0 Safari/537.36
↑ Identifies browser and OS. Servers may serve different content per UA.
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,*/*;q=0.8
↑ What content types the browser can handle.
q= is quality factor (preference weight, 0–1).
"I prefer text/html, but I'll accept anything"
Accept-Language: en-US,en;q=0.9,fr;q=0.7
↑ Preferred languages in priority order.
Accept-Encoding: gzip, br, zstd
↑ Compression algorithms supported.
br = Brotli (Google's algorithm, 20% better than gzip)
zstd = Zstandard (Facebook's algorithm, very fast)
Cache-Control: no-cache
↑ Force server to send fresh content.
"no-cache" means "revalidate, don't serve stale"
"no-store" means "don't cache at all"
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-Dest: document
↑ Browser security headers. Prevent CSRF.
Tells server context of this request (navigation, fetch, etc.)
Sec-CH-UA: "Chromium";v="120", "Google Chrome";v="120"
Sec-CH-UA-Mobile: ?0
Sec-CH-UA-Platform: "macOS"
↑ Client Hints — more structured UA info.
Cookie: nfvdid=XYZ123; NetflixId=ABC456; SecureNetflixId=DEF789
↑ Session state. Sent with every request to same domain.
NetflixId = your session token. HttpOnly cookie — JS cannot read it.
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9...
↑ JWT token for API requests. Contains encoded user info.
Referer: https://www.netflix.com/
↑ Which page sent you here (same-origin navigation).
Stripped for cross-origin requests (Referrer-Policy).
Origin: https://www.netflix.com
↑ For CORS (cross-origin resource sharing) checks.
Upgrade-Insecure-Requests: 1
↑ "If you redirect me, please redirect to HTTPS."
Connection: keep-alive
↑ HTTP/1.1 header — keep TCP connection open for reuse.
In HTTP/2, always multiplexed — this header is ignored.
DNT: 1
↑ Do Not Track preference. Mostly ignored by servers.
HTTP Response — Full Anatomy
HTTP/2 200 OK
Content-Type: text/html; charset=UTF-8
↑ What kind of content is in the body.
charset=UTF-8 tells browser how to decode bytes.
Content-Length: 45231
↑ Exact size of body in bytes.
OR use Transfer-Encoding: chunked for streaming responses.
Content-Encoding: br
↑ Body is Brotli-compressed. Browser decompresses before rendering.
# ── CACHING ────────────────────────────────────────────────────────────────
Cache-Control: no-store, no-cache, must-revalidate
↑ Don't cache this response. Netflix's HTML is personalized —
different user gets different content.
Cache-Control: public, max-age=31536000, immutable
↑ (For static assets like /app.abc123.js)
Cache for 1 year. "immutable" = browser never revalidates.
Safe because the filename contains a content hash.
ETag: "abc123def456"
↑ A fingerprint of the response. Browser sends it next request:
If-None-Match: "abc123def456"
Server: 304 Not Modified (no body) if unchanged.
Last-Modified: Tue, 22 Apr 2026 10:00:00 GMT
↑ When this resource last changed.
Browser can send If-Modified-Since header to check.
Vary: Accept-Encoding
↑ "This response differs based on Accept-Encoding."
Caches must store separate copies per encoding.
Age: 0
↑ How many seconds this response has been in a cache.
0 = fresh from origin.
# ── SECURITY ───────────────────────────────────────────────────────────────
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
↑ HSTS. Browser must use HTTPS for this domain
for the next year. Even if you type http://.
preload: this domain is in browsers' hardcoded
HSTS preload list — HTTPS enforced from the
very first request, ever.
Content-Security-Policy: default-src 'self';
script-src 'self' *.nflxvideo.net 'nonce-abc123';
img-src 'self' *.nflximg.net data:;
connect-src 'self' api.netflix.com;
frame-ancestors 'none'
↑ CSP. Whitelist of sources for each resource type.
Prevents XSS: even if attacker injects a <script> tag, browser blocks it
if the source isn't whitelisted.
nonce-abc123: inline scripts must have this nonce attribute.
X-Frame-Options: DENY
↑ This page cannot be embedded in an iframe on another site.
Prevents clickjacking attacks.
Superseded by CSP frame-ancestors, but kept for older browsers.
X-Content-Type-Options: nosniff
↑ Browser must not try to guess content type.
Only interpret response as declared Content-Type.
Prevents MIME confusion attacks.
Referrer-Policy: strict-origin-when-cross-origin
↑ Only send origin (not full URL) as Referer on cross-origin requests.
Full URL sent for same-origin. Nothing sent for downgrade (HTTPS→HTTP).
Permissions-Policy: geolocation=(), camera=(), microphone=(), payment=()
↑ Deny browser APIs to this page and its embedded content.
Even if JS tries navigator.geolocation, browser blocks it.
# ── CORS ────────────────────────────────────────────────────────────────────
Access-Control-Allow-Origin: https://www.netflix.com
↑ Only this origin may read the response cross-origin.
Use * to allow any origin (not for credentialed requests).
Access-Control-Allow-Credentials: true
↑ Cookies/auth headers included in cross-origin requests.
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With
Access-Control-Max-Age: 86400
↑ Preflight result cached for 24 hours.
# ── COOKIES ─────────────────────────────────────────────────────────────────
Set-Cookie: nfvdid=XYZ123;
Max-Age=31536000; ← expires in 1 year
Domain=.netflix.com; ← shared across all netflix.com subdomains
Path=/;
Secure; ← only sent over HTTPS
HttpOnly; ← JavaScript cannot read this cookie
SameSite=None ← sent on cross-site requests (needed for embeds)
↑ SameSite=Strict: only same-site requests (strongest CSRF protection)
SameSite=Lax: sent on top-level navigation (good default)
SameSite=None: sent everywhere (requires Secure)
# ── TRACING & INFRA ─────────────────────────────────────────────────────────
Server: nginx
↑ No version number — don't reveal exact version to attackers.
X-Netflix-Request-Id: abc-123-def-456
↑ Correlation ID. Used to trace this request through
Netflix's internal logs and distributed tracing systems.
Via: 1.1 netflix-edge-pop-1.netflix.com (EGW)
↑ Which proxies forwarded this response.
X-Response-Time: 43ms
↑ How long origin took to process this request.
HTTP Status Codes — The Complete Picture
1xx — Informational
| Code | Name | Meaning |
|---|---|---|
100 |
Continue | Server received headers, send the body |
101 |
Switching Protocols | Upgrading to WebSocket |
2xx — Success
| Code | Name | Meaning |
|---|---|---|
200 |
OK | Standard success |
201 |
Created | Resource was created (POST) |
204 |
No Content | Success but no body (DELETE) |
206 |
Partial Content | Range request served (video seeks) |
3xx — Redirection
| Code | Name | Meaning | Cached? |
|---|---|---|---|
301 |
Moved Permanently | Resource at new URL forever | YES |
302 |
Found | Temporary redirect | NO |
304 |
Not Modified | Use your cached copy | N/A |
307 |
Temporary Redirect | Like 302 but must keep method | NO |
308 |
Permanent Redirect | Like 301 but must keep method | YES |
4xx — Client Errors
| Code | Name | Common Cause |
|---|---|---|
400 |
Bad Request | Malformed request syntax |
401 |
Unauthorized | Not logged in / invalid token |
403 |
Forbidden | Logged in but not allowed (geo-block) |
404 |
Not Found | Wrong URL |
405 |
Method Not Allowed | POSTing to a GET-only endpoint |
408 |
Request Timeout | Client too slow |
409 |
Conflict | Resource state conflict |
410 |
Gone | Resource permanently deleted |
413 |
Payload Too Large | Request body too big |
415 |
Unsupported Media Type | Wrong Content-Type |
422 |
Unprocessable Entity | Syntactically valid but semantically wrong |
429 |
Too Many Requests | Rate limited |
5xx — Server Errors
| Code | Name | Common Cause |
|---|---|---|
500 |
Internal Server Error | Bug in server code |
502 |
Bad Gateway | Upstream (origin) returned invalid response |
503 |
Service Unavailable | Server overloaded or down |
504 |
Gateway Timeout | Upstream didn't respond in time |
CORS — Cross-Origin Resource Sharing
A web page at https://netflix.com wants to make an API call to https://api.netflix.com. These are different origins (different subdomain). The Same-Origin Policy blocks this by default.
CORS is a mechanism that lets servers explicitly permit cross-origin requests.
Browser is on: https://www.netflix.com
Browser wants to fetch: https://api.netflix.com/users/me
Step 1: Browser sends a Preflight request (OPTIONS):
OPTIONS /users/me HTTP/2
Origin: https://www.netflix.com
Access-Control-Request-Method: GET
Access-Control-Request-Headers: Authorization
Step 2: api.netflix.com responds:
Access-Control-Allow-Origin: https://www.netflix.com ← "yes, I allow this origin"
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Authorization
Access-Control-Max-Age: 86400 ← cache this preflight result for 24h
Step 3: Browser sends the actual GET request.
Step 4: Response returned to JavaScript.
If Step 2 fails (origin not allowed):
Browser blocks the response. Network tab shows CORS error.
Server DID receive the request — CORS is enforced by the browser, not the server.
Simple requests (GET/POST with basic headers) skip the preflight. Complex requests (PUT, DELETE, custom headers) require it.
Across the series
- Speak HTTP/1.1 by hand and decode
Content-Lengthvs chunked framing:rawhttp, TCP/IP guide, Chapter 28. - Time every phase of a real request (DNS, TCP, TLS, TTFB) and watch
connection reuse: this guide's
httptracelab in Chapter 17. - See which versions a site offers and how HTTP/3 is discovered:
protoprobein Chapter 14. - What happens when two parsers disagree about framing: request smuggling, in Chapter 20.
- Go's
net/httpfrom the ground up: Go guide §24 and the Go plan's Week 9 (raw HTTP server, middleware, reverse proxy, HTTP/2).
Key Takeaways
- HTTP is the language of the web. Request = method + headers + body. Response = status + headers + body.
- HTTP/2 solves HTTP/1.1 head-of-line blocking with multiplexed streams over one TCP connection.
- HTTP/3 (QUIC) runs over UDP, eliminates TCP head-of-line blocking, and supports 0-RTT.
- Request headers carry metadata: who the client is, what format it accepts, cookies, auth tokens.
- Response headers carry: content type, caching rules, security policies (HSTS, CSP, CORS), cookies.
- Cache-Control headers dictate whether and how long clients and caches store responses.
- Security headers (HSTS, CSP, X-Frame-Options, SameSite cookies) are your browser-side attack surface.
- CORS is browser-enforced — prevents malicious sites from making credentialed requests to your banking API.
- Status codes are contracts —
4xxusually means the request cannot be accepted as sent, while5xxmeans the server or upstream path failed to fulfill an otherwise valid request. Misclassified errors are common in real systems.