HTTP/1.1 · HTTP/2 · HTTP/3 — Multiplexing Visualizer

How each version handles concurrent requests · HOL blocking · QUIC streams · 0-RTT · Frame anatomy

1 · HTTP/1.1
2 · HTTP/2
3 · HTTP/3 (QUIC)
4 · Side by Side
5 · Frame Anatomy
HTTP/1.1 Timeline
TCP conns: Total: Reqs: 0/3
Request / Response flow
🖥️ Client
Browser
🖩 Server
nginx
Key facts
Multiplexing✗ None — 1 request at a time
HOL blocking✗ Severe — application layer
Header compression✗ Full headers every request
Connection setupTCP (1.5 RTT) + TLS 1.3 (1 RTT) = 2.5 RTT before first byte
Browser workaroundOpens up to 6 parallel TCP connections per origin
Keep-AliveReuses TCP socket, still sequential per connection
PipeliningSpec existed, but broken in practice — almost no servers support it
Still used?Yes — legacy servers, some proxies, HTTP/2 is the modern default
HOL Blocking — why the second request waits
Request 1
REQ
···server time···
◀ RESP
Request 2
BLOCKED — waiting for req 1
REQ
◀ RESP
Request 3
.
REQ
◀ RESP
Even if the server finishes request 2 instantly, it can't send the response — the connection pipe is occupied. HTTP/2 solves this by sending frames from multiple requests simultaneously.
HTTP/2 Timeline
TCP conns: 1 Total: Streams: 0/3
Multiplexed frame flow
🖥️ Client
🖩 Server
Key facts
Multiplexing✓ Full — streams interleaved as frames
App HOL blocking✓ Eliminated — streams are independent
TCP HOL blocking✗ Still exists — one lost packet = all streams stall
Header compression✓ HPACK — shared table, send only diffs
Server Push✓ Server can pre-send resources
Stream priority✓ Weights and dependencies per stream
Max streams100 concurrent default (SETTINGS_MAX_CONCURRENT_STREAMS)
Frame unit9-byte header + payload. Type, Stream ID, Flags.
TCP HOL — HTTP/2's remaining problem
Stream 1
frames →
✗ STALLED
done ✓
Stream 3
frames →
✗ STALLED
done ✓
Stream 5
frames →
✗ STALLED
done ✓
TCP packet lost → TCP retransmit → all 3 streams freeze until retransmit arrives. QUIC makes streams independent so this cannot happen.
HTTP/3 (QUIC) Timeline
Transport: QUIC/UDP Total: Streams: 0/3
QUIC stream flow
🖥️ Client
🖩 Server
Key facts
TransportQUIC over UDP — not TCP
Multiplexing✓ Streams independent at transport layer
TCP HOL blocking✓ Eliminated — each stream retransmits independently
Encryption✓ TLS 1.3 built into QUIC — always on
Connection setup1 RTT first connection · 0-RTT on resumption
Connection migration✓ Connection ID survives IP change (WiFi → 4G)
Header compression✓ QPACK (redesigned HPACK for QUIC)
Adoption~25% of web. Cloudflare default. Chrome/Firefox/Safari support.
Packet loss — QUIC streams are independent
QUIC s/1
GET /html ▶
◀ 200 OK
✓ unaffected
QUIC s/3
GET /css ▶
✗ lost
retransmit
◀ 200 OK
⚠ delayed only
QUIC s/5
GET /js ▶
◀ 200 OK
✓ unaffected
S/3 packet loss delays only S/3. S/1 and S/5 continue without interruption. Compare with HTTP/2 where all streams freeze.

Loading 3 resources (HTML, CSS, JS) — same server, same network. Watch how each HTTP version handles concurrent requests fundamentally differently.

⚡ Live Multiplexing Race Watch all 3 protocols load the same 3 resources simultaneously
HTTP/1.1
sequential
C
S
HTTP/2
multiplexed
C
S
HTTP/3
QUIC streams
C
S
HTTP/1.1
HTTP/2
HTTP/3
Request → Response ← Blocked / Lost Packet loss on HTTP/3 stream 3 injected to show independent recovery
HTTP/1.1
Sequential · Keep-Alive
TCP connections3 (browser workaround)
Concurrent streams1 per connection
Setup overhead3× TCP+TLS
HeadersFull, every request ~400B
HOL blockingApp layer
Total time~580ms
HTTP/2
Multiplexed · HPACK
TCP connections1
Concurrent streams100 default
Setup overhead1× TCP+TLS (shared)
HeadersHPACK compressed ~50B diff
HOL blockingTCP layer only
Total time~230ms
HTTP/3
QUIC · 0-RTT · Independent streams
QUIC connections1
Concurrent streamsUnlimited, independent
Setup overhead0-RTT on resume
HeadersQPACK compressed
HOL blockingNone
Total time~130ms (0-RTT)
Full feature comparison
FeatureHTTP/1.1HTTP/2HTTP/3
Year RFC199720152022
TransportTCPTCPQUIC (UDP)
Multiplexing✓ streams✓ independent streams
Application HOL✗ severe✓ eliminated✓ eliminated
Transport HOL✗ TCP✗ TCP✓ eliminated (QUIC)
Header compression✗ none✓ HPACK✓ QPACK
EncryptionOptional TLSOptional TLSMandatory (QUIC built-in)
0-RTT resumptionPartial (TLS 1.3)✓ native QUIC 0-RTT
Connection migration✗ breaks on IP change✗ breaks on IP change✓ Connection ID survives
Server push✓ (rarely useful)Removed in practice
Binary framing✗ text✓ binary frames✓ binary (QUIC)
Stream priority✓ weights + depsSimplified (RFC 9218)

HTTP/2 breaks data into frames. Each 9-byte frame header carries: length, type, flags, and stream ID. Frames from different streams are interleaved on one TCP connection. The receiver reassembles per stream ID.

HTTP/2 frame header (9 bytes fixed)
Length
24 bit
Type
8 bit
Flags
8 bit
Stream ID
31 bit
Payload (0 to max frame size, default 16 KB)
Stream ID 0 = connection-level. Client streams: odd IDs (1,3,5…). Server push: even IDs (2,4…).
Frame types
TypePurposeStream 0?
HEADERSHTTP request/response headers — HPACK compressedNo
DATARequest/response body — actual payload bytesNo
SETTINGSConnection config — max streams, window sizeYes
WINDOW_UPDATEFlow control — increase receive bufferBoth
RST_STREAMAbort one stream without killing connectionNo
PINGRTT measurement / keepaliveYes
GOAWAYGraceful shutdown — last processed stream IDYes
PUSH_PROMISEServer announces incoming push on new streamNo
PRIORITYStream dependency + weight for schedulingNo
Wire — 3 streams multiplexed
Frames on the wire — stream IDs interleaved
SETTINGS [s:0] HEADERS [s:1] GET / HEADERS [s:3] GET /css HEADERS [s:5] GET /js
DATA [s:1] END DATA [s:3] END DATA [s:5] part 1 DATA [s:5] part 2 DATA [s:5] END
Stream 5 (large JS) splits across 3 DATA frames. Streams 1 and 3 finish first. Client reassembles each stream independently using stream ID.
HPACK header compression
# HTTP/1.1 — sends full headers every request (~400 bytes) GET /api/users HTTP/1.1 Host: api.example.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X...) Accept-Encoding: gzip, deflate, br Authorization: Bearer eyJhbGciOiJSUzI1NiJ9... Cookie: session=abc123; theme=dark # HTTP/2 — first request: sends full headers once # Subsequent requests: only send what changed :method GET :path /api/users/42 ← ~50 bytes (Host, UA, Auth, Cookie all indexed — not resent)
HTTP/2 vs HTTP/3 key differences
AspectHTTP/2HTTP/3
TransportTCPQUIC (UDP)
Header compressionHPACKQPACK (stateless per stream)
Stream independenceNo — TCP HOLYes — QUIC streams
EncryptionTLS 1.3 over TCPTLS 1.3 inside QUIC
Handshake costTCP (1.5RTT) + TLS (1RTT)QUIC 1RTT or 0-RTT
Connection IDNo — IP:port pairYes — 64-bit opaque ID