4.3.25 · D5Computer Networks

Question bank — HTTP - 2 — multiplexing, header compression (HPACK), server push

1,344 words6 min readBack to topic

True or false — justify

HTTP/2 multiplexing completely eliminates head-of-line blocking.
False. It removes application-layer HOL (streams no longer wait for each other in HTTP), but the single TCP connection still delivers bytes in order, so one lost packet stalls all streams — transport-layer HOL. HTTP-3-and-QUIC fixes that.
HTTP/2 changes the meaning of GET, POST, status codes and headers.
False. Semantics are identical to HTTP-1.1; only the wire format (binary framing instead of text) changed. A 200 OK still means the same thing.
Opening more parallel connections in HTTP/2 makes it faster, like it did in HTTP/1.1.
False. HTTP/1.1 needed ~6 connections to fake parallelism; HTTP/2 wants one connection so it has a single warmed-up congestion window and pays one TCP+TLS handshake instead of six.
HPACK is essentially gzip applied to the header block.
False. Gzip mixes attacker-controlled and secret bytes, and its output length leaks secrets (CRIME-and-BREACH-attacks). HPACK uses a static/dynamic index table plus a fixed Huffman-Coding table, avoiding that adaptive context-mixing.
Client-initiated streams and server-pushed streams can share the same Stream ID.
False. Clients use odd IDs, servers use even IDs, so the two ID spaces never collide on the same connection.
Server push always speeds up page loads.
False. If the server pushes a resource the browser already cached, it wastes bandwidth and steals congestion window from the real HTML. Mis-tuned push often hurt, which is why Chrome dropped it.
A single HTTP/2 frame can carry an unlimited amount of data.
False. The 24-bit Length field allows up to bytes, but the default maximum is so no single frame monopolizes the link.
The dynamic table is shared globally across all HTTP/2 connections to a server.
False. The dynamic table is per-connection; encoder and decoder each maintain their own copy that evolves as headers are seen on that one connection.
HPACK's Huffman table is rebuilt adaptively as it sees your headers.
False. HPACK uses a fixed, spec-defined Huffman code optimized for typical HTTP header characters. Being static is part of what makes it CRIME-resistant, unlike adaptive coding.
Prefix-integer encoding is unique to HPACK.
False. It is the same 7-bit continuation idea used in Varint-encoding and many binary protocols — small numbers fit inline, big ones spill into continuation bytes whose high bit means "more follow".

Spot the error

"Server push sends a DATA frame on the client's stream to deliver style.css."
Wrong frame and stream. The server first sends a PUSH_PROMISE on the client's stream to reserve a new even stream ID, then delivers HEADERS+DATA for the pushed resource on that new stream.
"To signal 'this header is fully in the table', HPACK sets the two leading bits to 01."
Wrong pattern. A single leading 1 bit marks a fully indexed representation. The 01 prefix marks literal with incremental indexing (a new header to remember).
"Since the Stream ID is 31 bits, the top bit of the ID byte lets you pick odd or even streams."
The top bit is a reserved (R) bit, not a chooser. Odd/even is just the parity of the 31-bit ID value itself — clients pick odd, servers pick even.
"HPACK stores index 10 in a 5-bit prefix as 31, 10 because you always emit the max first."
Wrong. , so it fits directly in the 5 bits as 0b01010. You only emit first when the value overflows the prefix.
"A message in HTTP/2 is one frame."
A message (one request or response) is one HEADERS frame plus zero or more DATA frames, all sharing the same Stream ID. It is generally several frames.
"gzip is safe for headers as long as we compress the cookie separately."
The danger isn't which algorithm but length-based leakage when secret and attacker-influenced data are compressed together; HPACK's design (indexing over a static table) is the real fix, not compressing separately.

Why questions

Why does HTTP/2 chop messages into frames instead of sending each message whole?
So many messages can be interleaved on one connection — labeled chunks (by Stream ID) let a slow response yield the wire to ready ones, killing application-layer HOL blocking.
Why is the default max frame size 16 KB rather than the full 24-bit maximum?
To stop any single frame from monopolizing the shared connection; small frames keep interleaving fair so no one stream starves the others.
Why does HPACK bother with a static table of 61 entries at all?
The most common headers (:method GET, :status 200, etc.) are known in advance, so they can be sent as a single index byte from the very first request — no learning phase needed.
Why did SPDY's naive header compression lead to the CRIME attack?
Because compressing a secret (cookie) together with attacker-chosen text made the compressed length depend on how well the guess matched the secret, leaking it byte by byte. See CRIME-and-BREACH-attacks.
Why does a shared congestion window help HTTP/2?
One connection means one properly-warmed TCP congestion window that grows and stays large, instead of six tiny cold windows each restarting from slow-start.
Why did modern browsers deprecate server push in favor of 103 Early Hints?
Push blindly resends resources the browser may already have cached and competes for bandwidth; 103 Early Hints + <link rel=preload> lets the browser decide what to fetch, avoiding waste.

Edge cases

What happens under HTTP/2 if exactly one TCP packet is lost mid-transfer of ten streams?
All ten streams stall until TCP retransmits that packet, because TCP guarantees in-order byte delivery — this transport-level HOL is precisely what HTTP-3-and-QUIC removes.
What does HPACK do when a header value is brand new and shouldn't be remembered?
It uses a literal without indexing (or never-indexed) representation — sent Huffman-encoded but not added to the dynamic table, so it doesn't waste table space or risk it being indexed.
If the dynamic table fills up, what happens to old entries?
Entries are evicted oldest-first to stay under the negotiated size limit; evicting an entry simply means the next occurrence of that header must be sent as a literal again.
What if the server pushes a resource the client explicitly does not want?
The client can send RST_STREAM on the pushed (even) stream to cancel it — but bandwidth already spent on frames in flight is wasted, one reason push fell out of favor.
Encoding index exactly equal to in an -bit prefix — does it fit inline?
No. The rule is if I < 2^N - 1 fits inline; triggers the overflow path: store in the prefix, then in a single continuation byte.
Recall One-sentence summary of the whole trap set

HTTP/2 fixes application-layer HOL and header bloat, but not transport HOL (that's QUIC), and its "obvious" wins — push and gzip-style compression — are the exact places it bites you.