Frontend Labs
⋯

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-Length vs 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 httptrace lab in Chapter 17.
  • See which versions a site offers and how HTTP/3 is discovered: protoprobe in Chapter 14.
  • What happens when two parsers disagree about framing: request smuggling, in Chapter 20.
  • Go's net/http from 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 — 4xx usually means the request cannot be accepted as sent, while 5xx means the server or upstream path failed to fulfill an otherwise valid request. Misclassified errors are common in real systems.

Generated from real-life-guide-v1.md · 8 Oct 2026 16:36