Connection setup and HTTP/1.1 vs 2 vs 3
Setup is paid in round trips, once per connection; HTTP/2 stops requests waiting for each other, but not bytes waiting behind a lost packet.
Predict first
Before you read: predict
At 09:00 a candidate's browser loads the ECON-201 exam shell over HTTP/2, on one TCP connection. Three responses are in flight, and the server's packets leave in this order: (1) all of logo.svg; (2) part 1 of paper.json; (3) part 1 of timer.js; (4) part 2 of paper.json; (5) the rest of timer.js; (6) the rest of paper.json. Packet 3 is lost and is retransmitted later; every other packet arrives on time.
Which responses finish late?
The 30-second version
A first HTTPS request waits for DNS, a TCP handshake (one round trip) and a TLS 1.3 handshake (one more). Keep-alive reuses the connection. HTTP/2 interleaves streams on one TCP connection, but TCP delivers bytes only in order, so a lost packet holds every stream with bytes behind it. HTTP/3 (QUIC) holds only the streams with data in that packet.
Setup is paid in round trips, once per connection; HTTP/2 stops requests waiting for each other, but not bytes waiting behind a lost packet.
Step through the code
Trace of the opening question
Play options
Ready: press Play or step with Next frame
Row 1 of 4 · Packet 1
Starting row · computed by comparing each row with the one before
- Packet: 1
- Carries: all of
logo.svg - Reaches the browser: at once; the logo is complete
Rule · step 6
HTTP/2 cuts each response into frames on numbered streams and interleaves them on one connection, so a slow response no longer blocks a quick one.
- Packet
- 1
- Carries
- all of
logo.svg - Reaches the browser
- at once; the logo is complete
- Step
- 6
| Packet | Carries | Reaches the browser | Step |
|---|---|---|---|
| 1 | all of logo.svg | at once; the logo is complete | 6 |
| 2 (changed) | paper.json part 1 (changed) | at once (changed) | 6 |
| 3 (changed) | timer.js part 1 (changed) | lost; arrives with the retransmission (changed) | 7 |
| 4, 5, 6 (changed) | the rest of paper.json and timer.js (changed) | already here, but held until packet 3 arrives (changed) | 7 |
Space plays or pauses · ←/→ one row · Home/End first/last
Rows come from the pack's own trace table.
How it works
Step 1 of 9
See it run
Not in this run
In the kitchen
- looking up the tunnel, the "open?"/"open" call, the paper check → DNS, the TCP handshake, the TLS handshake (steps 1–2)
Analogy: A single-bore river tunnel with one exit gate
Lorries from several firms share one tunnel. Before the first lorry goes in, the dispatcher looks up which tunnel serves the address, phones the far gate and hears "open", then both gates check papers and agree a seal. At the exit, the gatekeeper releases trailers strictly in the order they entered.
| In the tunnel | In the protocol |
|---|---|
| looking up the tunnel, the "open?"/"open" call, the paper check | DNS, the TCP handshake, the TLS handshake (steps 1–2) |
| keeping the gates open for the next lorry | keep-alive (step 4) |
| one firm's whole convoy at a time per tunnel | HTTP/1.1 (step 5) |
| trailers of many firms mixed in one line | HTTP/2 streams (step 6) |
| a trailer that breaks down holds every trailer behind it, any firm | TCP head-of-line blocking (step 7) |
| a second tunnel, with its own look-up, call and paper check | another connection (step 8) |
| one exit queue per firm | QUIC streams (step 9) |
In real terms: a new connection costs one round trip for TCP and one for TLS 1.3 before the request; after a lost packet, TCP delays every later byte on that connection, whatever stream it belongs to.
Breaks down when: a broken-down trailer blocks the road. A lost packet does not: the later packets arrive and sit in the receiver's buffer. Wrong inference: "more bandwidth clears the queue." It does not; only the retransmission does.
Contrasting case: a courier who sends every parcel by its own motorbike. Nothing waits behind anything, but every parcel pays the whole setup: that is one connection per request.
Examples, run for real
4.1 ExamHall: what a Cairo candidate's first request costs
A relay adds a fixed delay to every packet, and the script counts the server's replies (round trips) on real TLS connections. TCP and DNS round trips are added by rule (steps 1–2).
cold, uncached DNS, TLS 1.3 observed TLS+HTTP 2 | model TCP 1 DNS 1 | total 4 RTT | 600 ms at 150 ms RTT | connections 1
cold, cached DNS, TLS 1.3 observed TLS+HTTP 2 | model TCP 1 DNS 0 | total 3 RTT | 450 ms at 150 ms RTT | connections 1
cold, cached DNS, TLS 1.2 observed TLS+HTTP 3 | model TCP 1 DNS 0 | total 4 RTT | 600 ms at 150 ms RTT | connections 1
new connection, TLS 1.3 resumed (PSK) observed TLS+HTTP 2 | model TCP 1 DNS 0 | total 3 RTT | 450 ms at 150 ms RTT | connections 2
resumed handshake used the ticket: connect>secureConnect(resumed)>response (session from request 1: yes)
new connection, TLS 1.2 resumed observed TLS+HTTP 2 | model TCP 1 DNS 0 | total 3 RTT | 450 ms at 150 ms RTT | connections 2
2nd request, same kept-alive connection observed TLS+HTTP 1 | model TCP 0 DNS 0 | total 1 RTT | 150 ms at 150 ms RTT | connections 1
0-RTT early data: not run (node:tls does not expose TLS 1.3 early data); RFC 8446 §2.3: 0 RTT, replayable.
At a 150 ms round trip, three round trips of setup pass before the HTML request is sent (row 1). TLS 1.3 is one round trip cheaper than TLS 1.2. A resumed TLS 1.3 session still spends its round trip (step 3). The kept-alive connection pays one (step 4).
4.2 Ticketing: a seat map and a hold-status poll on one HTTP/2 connection
ExamHall hit this on the exam shell as EXH-917. MR !931 serves the exam shell over HTTP/3 with an HTTP/2 fallback. The same effect on a ticketing page:
no loss, one connection: finished first: /hold-status.json (the seat map was still sending)
seat map packet lost, HTTP/2 over TCP (observed h2, modelled loss): /seatmap.png delayed, /hold-status.json delayed
seat map packet lost, per-stream delivery (model of HTTP/3): /seatmap.png delayed, /hold-status.json on time
Without loss, the small poll overtakes the big seat map (step 6). One lost seat-map packet makes the poll late too, although none of its own packets was lost (step 7). With per-stream delivery, only the seat map waits (step 9, a model).
4.3 Catalog: HTTP/1.1 and the connection pool
A product page asks for /reviews (the server takes 400 ms) and /price (instant) at the same moment:
1 connection, keep-alive finished: /reviews then /price | TCP connections: 1
up to 6 connections, keep-alive finished: /price then /reviews | TCP connections: 2
On one connection, the price waits for the reviews (step 5). A second connection frees it, at the price of a second setup (step 8).
Picture it

Try it
Answer first, then check. Nothing is saved.
Question 1 of 5
A fan's phone opens its first connection to the ticket API: HTTPS over TCP, TLS 1.3, no resumption, and the DNS answer is already cached. The round trip is 120 ms and the server answers at once.
About how long from the start of the TCP connect to the first byte of the response?
Question 2 of 5
A video app requests its first playlist from a host it has never contacted.
In what order do its setup steps happen?
Your order
- 1empty
- 2empty
- 3empty
- 4empty
Tap the lines in the order you expect.
Question 3 of 5
A payments dashboard uses HTTP/1.1 and may keep only one connection to its API. It requests /settlement-export (the server needs 400 ms) and /status (instant) at the same moment, and /status always finishes after the export.
Which change lets /status finish first on one connection?
Question 4 of 5
A ticketing app checks three seats one after another with seatStatus(id), which calls https.get(url, { agent: new https.Agent({ keepAlive: true }) }). Every check takes three round trips; the team expected the second and third to take one.
Which is the bug?
Question 5 of 5
A live-stream app gets video segments and chat messages from live.example over one HTTP/2 connection, through its own HTTP client. On a lossy phone network, chat freezes each time a video packet is lost. The CDN offers no HTTP/3.
Which change keeps chat on time when a video packet is lost, with every chat message after the first taking one round trip?
Go deeper
Pro tips
- Split a slow first request with curl's timers:
curl -s -o /dev/null -w 'dns=%{time_namelookup} tcp=%{time_connect} tls=%{time_appconnect} ttfb=%{time_starttransfer}\n' https://HOST/. Each value is a cumulative timestamp, so TLS cost isappconnect − connect. When: a first request is slow and you need to know whether it is DNS, connect, TLS or the server (steps 1–2). Verify: the four timestamps come back in setup order, and the relay counts 1 connection and 2 server replies (TLS, then the request). Tips bank CURL-01. - Preconnect to an origin you will call soon:
<link rel="preconnect" href="https://api.example.com">lets the browser do DNS, TCP and TLS before the first request needs them. When: the page will certainly call another origin early, as the exam shell calls its API (step 1). Verify: in DevTools Network, the first API request's Timing tab shows no "Initial connection" or "SSL" part. Status: DOC (MDN rel=preconnect); not run in this session.
Source
- The browser figure of 6 per host is a browser convention, not the RFC. Valid as of 2026-09-27.
- RFC 9204 (QPACK) §2.1.2: dynamic-table references can add cross-stream head-of-line blocking (not taught). Valid as of 2026-09-27.
- MDN,
rel="preconnect": https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/preconnect (pro tip 2; DOC). curl manual,--write-out: https://curl.se/docs/manpage.html#-w (pro tip 1).
Checked against the tools and docs as of 2026-09-27.