GAP·MAP

HTTP/2 and HTTP/3

[ junior depth ]

One connection can carry many exchanges

HTTP/2 keeps HTTP semantics such as methods, status codes, URLs, and header fields. It changes how messages travel. A request and its response belong to a numbered stream, and the protocol divides messages into frames. Frames from several streams can be interleaved on one TCP connection.

Suppose a page needs CSS while a large image is still arriving. HTTP/2 does not require the image response to finish before CSS response frames can use the connection. Flow control still limits what a sender can transmit, and the peer can cap concurrent streams, so “multiplexed” does not mean “unlimited.”

Wrong “HTTP/2 downloads one complete response at a time, only with a binary format.”

Right “HTTP/2 can interleave frames from concurrent request and response streams on the same connection.”

HPACK compresses repeated fields

HTTP requests often repeat field names and values. Cookies and user-agent data are common examples. HTTP/2 uses HPACK for field section compression. HPACK has a predefined static table and a connection-specific dynamic table. A field may be encoded as an index into a table instead of repeating its full name and value. Literal forms cover values that are absent from the tables, and an encoder can add suitable fields to the dynamic table.

HPACK compresses HTTP field sections. It does not compress JavaScript, images, or other response bodies. Content compression such as Brotli or gzip is a separate concern.

Wrong “HPACK makes image and JavaScript payloads smaller.”

Right “HPACK reduces repeated HTTP field data by using indexed and literal representations.”

Why old asset tricks became liabilities

Under HTTP/1.x, browsers used several connections to gain concurrency. Domain sharding spread assets across hostnames to obtain more connections. With HTTP/2, one connection can already carry concurrent streams. Extra hostnames can instead add DNS lookups and connection setup.

Concatenating every script or stylesheet into one file also targeted request overhead. Multiplexing reduces that reason for a single giant bundle. Separate resources can be cached and loaded independently. This is not a rule to ship thousands of tiny files. Compression, caching, code splitting, and browser work still need measurement. The obsolete idea is concatenation whose only argument is “fewer requests must always be faster.”

# HTTP/1.x-era layout chosen only to create more connections
static-1.example.com/app.js
static-2.example.com/styles.css

# Multiplexed delivery can keep independently cacheable assets together
www.example.com/app.js
www.example.com/styles.css

Server Push is not the modern default

HTTP/2 Server Push let a server send a promised response before the client requested it. The feature could waste bytes when the browser already had the resource and could compete with resources the browser considered more important. Chrome disabled HTTP/2 Server Push by default in Chrome 106 after reporting mixed performance results and regressions. HTTP/3 still specifies push, but specification support does not imply useful browser deployment.

The replacements keep request choice closer to the browser. A 103 Early Hints response can advertise resources before the final response, while preload metadata can identify important resources. Both need restraint because eager loading can also hurt performance.

HTTP/3 moves HTTP onto QUIC

HTTP/2 streams share TCP's one ordered byte stream. When TCP data is missing, later bytes wait for retransmission before TCP delivers them to HTTP/2. That can stall frames from otherwise independent HTTP/2 streams.

HTTP/3 runs over QUIC. QUIC provides ordered delivery within each stream, so packet loss affecting one stream does not prevent unrelated streams from progressing. A lost packet can carry data for several streams and delay data for each of them. Congestion control still affects the connection. HTTP/3 reduces cross-stream transport head-of-line blocking; it does not make packet loss free.

QUIC also supports 0-RTT on a resumed connection. A returning client can send application data before the handshake completes by reusing state from an earlier connection. The data can be replayed by an attacker, so requests with harmful effects under replay are unsuitable. A first connection has no prior session state to use for 0-RTT.

[ middle depth ]

Multiplexing fixes one queue and exposes another

HTTP/2 maps each request and response exchange to a stream. HEADERS and DATA frames from open streams share a TCP connection and may be interleaved. A slow application response therefore does not force every later response to wait behind it at the HTTP layer.

TCP presents one reliable, ordered byte stream to HTTP/2. If a segment is lost, TCP cannot deliver later bytes to the application until the missing range arrives. Those later bytes may contain HTTP/2 frames from several streams. This is transport head-of-line blocking, and it explains why the phrase “HTTP/2 eliminates head-of-line blocking” is incomplete.

Wrong “Independent HTTP/2 streams mean a lost TCP packet delays only the stream whose frame was lost.”

Right “HTTP/2 streams are independent at the framing layer, but all of them share TCP's ordered delivery.”

Multiplexing also depends on flow control and prioritization. HTTP/2 has connection-level and stream-level flow-control windows. The current HTTP/2 specification deprecates the priority signaling scheme defined by the earlier RFC 7540 because it was complex and not uniformly implemented. A protocol feature does not guarantee that a deployment schedules important bytes well.

What HPACK keeps as connection state

HPACK encodes a field as an index or a literal. Its static table contains predefined common fields. Its dynamic table starts empty and stores entries selected by the encoder as field blocks are processed. New entries go at the beginning, and old entries are evicted when the bounded table runs out of capacity.

The request and response directions maintain independent dynamic tables. Compression state applies across field blocks on a connection, which is why repeated fields become cheap after suitable entries exist. A decoder sets the maximum table capacity that its peer's encoder may use.

HPACK also defines literal forms with incremental indexing, without indexing, and never indexed. “Never indexed” signals that an intermediary must not re-encode the field using a representation that indexes it. The larger security point is that encrypted traffic still exposes lengths. Compression can create an oracle when attacker-controlled and secret values share a compression context, so “TLS encrypts it” is not a complete compression-safety argument.

Bundling and sharding after HTTP/1.x

Domain sharding bought more parallel TCP connections when per-origin connection limits constrained HTTP/1.x pages. On HTTP/2, it can split requests across separate DNS lookups and connections when one multiplexed connection was enough. Connection coalescing may allow one authoritative HTTP/2 connection to serve multiple origins, but it has authority and certificate conditions. Do not assume that shard names automatically share a connection.

Large concatenated bundles have a different tradeoff. Fewer requests are less valuable under multiplexing, while a single changed byte can invalidate a whole bundle and route-specific code may be transferred before it is needed. Splitting everything has costs too: field data, scheduling, compression efficiency, and browser processing remain. The defensible recommendation is bounded splitting based on dependency and cache behavior, then measurement.

# One release invalidates the whole shared bundle
/assets/site.4f3a.js

# Stable vendor code and changing application code can cache separately
/assets/vendor.a121.js
/assets/app.4f3a.js

Why Server Push failed in browsers

Server Push was speculative. The server sent a PUSH_PROMISE, then a response on another stream for a synthesized request. The browser could reject unwanted pushes, but the server had to decide before it fully knew the browser's cache and current priorities. Duplicate transfer and bandwidth competition could erase the intended latency win.

Chrome's removal notice says push was disabled by default in Chrome 106. It cites mixed analysis, no clear net performance gain, and performance regressions. The HTTP/2 and HTTP/3 specifications still define push, so “removed from Chrome” and “removed from the protocol” are different claims.

103 Early Hints sends hints rather than response bodies. The browser retains the decision to request a hinted resource, including the ability to account for its cache. Preload is another explicit discovery mechanism. Neither should become “push everything” under a new name.

QUIC streams and 0-RTT

HTTP/3 uses QUIC's stream abstraction. QUIC sends information from lost frames again as needed while allowing unrelated streams to progress. If one lost QUIC packet contains data from several streams, delivery of that data can be delayed for each represented stream. Loss also invokes congestion control, which can reduce the sending rate for the connection. The guarantee is narrower than “other requests are unaffected.”

0-RTT applies when a client can resume using parameters learned from a previous connection and a TLS session ticket. It lets the client send application data immediately, before handshake completion. The server may reject that early data, and the application must account for replay exposure.

Wrong “An encrypted 0-RTT purchase request is safe because an attacker cannot read it.”

Right “Confidentiality does not prevent replay. Early data must be restricted to operations whose effects are safe if the request is replayed, or delayed until the handshake completes.”

[ senior depth ]

Name the layer that is blocking

There are three distinct scheduling boundaries in this topic. HTTP/2 has streams at its framing layer. TCP exposes one ordered byte stream underneath them. The endpoint also has shared constraints such as flow control, congestion control, and compute capacity.

An HTTP/2 response can stall without preventing another stream from making application-layer progress. A missing TCP segment is different: later TCP bytes are withheld from HTTP/2 until the gap is filled, even if those bytes contain frames for another stream. Connection-level flow control can also block all streams when its window is exhausted. Stream independence is therefore qualified rather than absolute.

HTTP/3 delegates reliable streams to QUIC. STREAM frames carry per-stream offsets, and QUIC sends information from lost frames again as needed. Packet loss affecting one stream does not prevent progress on unrelated streams. A packet may contain STREAM frames from several streams, so its loss can delay data for each represented stream. Congestion control remains shared and can lower the connection's rate after loss.

Wrong “QUIC removes head-of-line blocking.”

Right “QUIC avoids head-of-line blocking across unaffected streams. Ordering within a stream and shared congestion effects remain.”

Compression state has ordering costs

HPACK's dynamic table improves compression because later field blocks can refer to earlier entries. That state couples decoding order across an HTTP/2 connection. HTTP/2 requires each compressed field block to be transmitted as a contiguous frame sequence, and a compression decoding error is a connection error.

HTTP/3 cannot copy HPACK unchanged without recreating cross-stream blocking. It uses QPACK, a variation designed to let the encoder trade compression efficiency against blocking. This module does not cover QPACK's encoder and decoder streams in detail, but the design reason matters: moving HTTP streams away from TCP's ordered connection is insufficient if header compression adds an equivalent connection-wide ordering dependency.

HPACK's security properties also deserve precision. Its “never indexed” representation keeps a field out of the dynamic table and must be preserved when a received field is forwarded. It does not hide the literal field length. RFC 7541 discusses attackers who can control values, observe encoded lengths, and probe shared compression state. Treat sensitive field selection and compression context as security decisions.

Asset strategy is a cache strategy now

Domain sharding should be removed when its sole purpose is bypassing an HTTP/1.x connection limit. Each extra origin can require DNS and connection establishment. HTTP/2 permits connection reuse across authority names only when the server is authoritative; for HTTPS, the certificate must be valid for the requested host. Operational routing can still prevent safe reuse.

The corresponding bundle review should avoid a new absolute rule. Multiplexing weakens the request-count argument for one monolith. Independent files can preserve long-lived cache entries and allow route-specific loading. Larger files may compress better, and every resource still carries discovery, fields, scheduling, and processing work. Protocol version alone cannot choose a chunk graph.

# Review chunks by invalidation and dependency boundaries
/assets/runtime.91c2.js   # small, changes with build metadata
/assets/vendor.6aa1.js    # large, changes infrequently
/assets/checkout.f413.js  # loaded by the checkout route

Push support is not deployment support

Both HTTP/2 and HTTP/3 specify server push. Browser reality diverged. Chrome disabled HTTP/2 Server Push by default in Chrome 106 after reporting that benefits were difficult to realize, use was low, and measured results included regressions. The server could send a body the browser already had cached or consume bandwidth before the browser's more informed prioritization had run.

The practical distinction is who retains the fetch decision. A 103 Early Hints response advertises likely resources while the final response is pending. Preload metadata does something similar from a response or document. The browser still issues a request and can use cache state. Eager hints can compete for bandwidth too, so measure them against an unhinted baseline.

HTTP/1.1 103 Early Hints
Link: </assets/app.css>; rel=preload; as=style

HTTP/1.1 200 OK
Content-Type: text/html

0-RTT is a replay tradeoff

QUIC integrates TLS 1.3. With resumed state from an earlier connection, the client can place application data in 0-RTT packets before the handshake completes. It is unavailable without that prior state, and a server can reject it. “Zero RTT” describes when the client may send early application data, not completion of the whole exchange with no network round trip.

Encryption does not supply replay protection for this early data. An attacker may replay captured 0-RTT application data without learning its contents. HTTP/3 therefore requires HTTP early-data anti-replay mitigations. A non-idempotent name is not the only concern; assess whether repeating the operation can cause unwanted effects in the concrete application.

Reasonable 0-RTT candidate: a read whose repeated execution has no unwanted effect
Unsafe 0-RTT candidate: create an order, transfer funds, or consume a one-time action

The HTTP method's defined safety is one input, but it is not sufficient by itself. RFC 8470 notes that some resources produce side effects even with safe methods. When the application cannot make replay harmless or mitigate it, wait for handshake completion.

dig deeper

Primary sources behind these notes - the specs and official docs worth reading in full.

beta

The interviewer part is in the works.

The diagnostic, personal maps, and AI mock interviews are being finished right now. The notes stay free either way. Leave an email and you'll get the first-cohort invite, plus a month of Pro when it opens.

builds on

more Browser & Network

was this useful?