# HTTP Versions and QUIC

HTTP/1.1, HTTP/2 and HTTP/3 solve the same problem — request and response over a network — with different assumptions about latency. Choosing between them is a performance decision with operational consequences.

## The version ladder

| Version | Transport | Key idea | Breaks when |
|---|---|---|---|
| **HTTP/1.0** | TCP, connection per request | Simple | Every request pays a handshake |
| **HTTP/1.1** | TCP, keep-alive, pipelining | Persistent connections | Head-of-line blocking at the HTTP layer |
| **HTTP/2** | TCP, one connection, streams | Multiplexing, header compression (HPACK), server push (dead) | One lost TCP segment stalls every stream |
| **HTTP/3** | QUIC over UDP 443 | Streams independent, 0-RTT resumption, connection survives IP change | UDP blocked, middleboxes, some proxies |

The progression is a progression against latency, not against bandwidth. Each version reduces the number of round trips a page needs before it can render.

## HTTP/2 in practice

- One TCP connection per origin, many concurrent streams.
- Binary framing; headers compressed with HPACK and a shared dynamic table.
- Stream priorities exist and are mostly ignored by servers in favour of good scheduling.
- **TCP head-of-line blocking remains**: loss on one stream stalls all streams, because TCP delivers bytes in order.

That last point is the reason HTTP/3 exists rather than being a nicer HTTP/2.

## QUIC and HTTP/3 in practice

QUIC is a transport protocol built on UDP that reimplements reliability per stream, integrates TLS 1.3, and identifies connections by ID rather than by IP and port.

| Property | Consequence |
|---|---|
| Per-stream loss recovery | A lost packet stalls only its stream |
| 1-RTT handshake, 0-RTT resume | Faster first byte on repeat visits |
| Connection ID | A phone switching Wi-Fi → cellular keeps the session |
| Encryption of transport metadata | Middleboxes see less, and some networks dislike it |
| UDP 443 | Blocked by a surprising number of corporate firewalls |

Everything falls back to HTTP/2 over TCP when UDP is blocked, which is why "HTTP/3 is enabled" and "users are using HTTP/3" are different claims.

## What this means operationally

```bash
curl -I --http2 https://example.com
curl -I --http3 https://example.com        # curl built with HTTP/3 support
curl -w "%{http_version} %{time_appconnect} %{time_starttransfer}\n" -o /dev/null -s https://example.com
```

- **Connection reuse is the biggest win** in any version. A pool of warm connections beats a clever protocol with cold ones.
- **Measure at the 95th percentile.** Medians hide head-of-line blocking, which only appears under loss.
- **Time to first byte and time to last byte are different questions.** Streaming responses have a fast TTFB and a slow TTLB by design.
- **CDNs terminate all three versions**, so your origin may never see QUIC at all.

## Terms worth being precise about

| Term | Precise meaning |
|---|---|
| **Keep-alive** | Reusing a TCP connection for multiple requests |
| **Multiplexing** | Multiple logical streams over one connection |
| **Head-of-line blocking** | One lost or slow unit delays everything behind it |
| **0-RTT** | Sending application data with the first flight, replayable |
| **ALPN** | The TLS extension that negotiates `h2` or `http/1.1` |
| **Origin** | Scheme + host + port; the unit of connection reuse and CORS |

## Where it goes wrong

- **Enabling HTTP/2 without fixing the backend.** Multiplexing 100 requests onto one connection can overwhelm an origin that expected 100 connections.
- **Firewalls that block UDP 443.** Users silently get HTTP/2; nobody notices until a performance project asks why QUIC adoption is zero.
- **Load balancers that do not speak HTTP/3 end to end.** Client → LB is QUIC, LB → origin is HTTP/1.1 with a new connection per request. The client gets faster, the origin gets slower.
- **Measuring one request instead of a page.** A single `curl` says nothing about the 80 subresources where multiplexing pays off.
- **Assuming HTTP/3 fixes bad RTT.** It removes round trips; it does not repeal the speed of light. Put the service closer.

## Teaching hook

**The checkout-lane analogy.** HTTP/1.1 is one till per customer; HTTP/2 is one till with a shared conveyor belt, so a jam blocks everyone; HTTP/3 gives each customer their own belt on a shared floor. The analogy breaks at exactly the right place — the floor (UDP) can be closed by a security guard (firewall).

Demo: `curl -w "%{http_version}"` against a few major sites, then again with `--http1.1`, and compare `time_appconnect`.

## Related Notes

- [[Core-Protocols/TLS-And-HTTPS.md]] — ALPN and the handshake QUIC embeds
- [[Core-Protocols/Ports-And-Services.md]] — why UDP 443 matters
- [[Network-Services/Load-Balancing.md]] — where protocol versions are negotiated
- [[Automation-Observability/Telemetry-And-Monitoring.md]] — measuring latency honestly
