Skip to content

HTTP/2 Deep Dive#

HTTP/2 replaces HTTP/1.1's per-request connection model with a single binary, multiplexed connection. Many requests share one TCP socket; framing lets them interleave; HPACK compresses headers.

Multiplexing several logical streams onto one channel, the core idea behind HTTP/2 streams
Source: Wikimedia Commons. CC BY-SA 3.0.
sequenceDiagram
  participant C as Client
  participant S as Server
  C->>S: open one TCP connection + TLS
  par stream 1
    C->>S: HEADERS GET /a
    S->>C: HEADERS + DATA /a
  and stream 3
    C->>S: HEADERS GET /b
    S->>C: HEADERS + DATA /b
  and stream 5
    C->>S: HEADERS GET /c
    S->>C: HEADERS + DATA /c
  end

Each request gets its own stream id; frames carry the stream id so the receiver can demultiplex. Solved HTTP/1.1's head-of-line blocking at the HTTP layer (TCP-level HOL still exists; that's HTTP/3's job).

HTTP/2 (RFC 7540, 2015) keeps HTTP semantics identical but rewrites the wire format. The protocol is binary, multiplexed, and stateful at the connection level.

Frame structure#

+-----------------+
| Length (24)     |
+-----------------+
| Type (8)        |
+-----------------+
| Flags (8)       |
+-----------------+
| R| Stream Id (31)|
+-----------------+
| Frame Payload   |
+-----------------+

Every frame belongs to a stream. Common types:

Type Purpose
DATA Request/response body
HEADERS Request/response headers
SETTINGS Connection-level config
WINDOW_UPDATE Flow control credit
PUSH_PROMISE Server push declaration
RST_STREAM Abort one stream
PING Liveness and RTT
GOAWAY Connection shutdown

Multiplexed streams#

flowchart TB
  subgraph Connection[Single TCP+TLS connection]
    direction LR
    S1[Stream 1<br/>HEADERS, DATA, DATA] -.frames.-> Wire
    S3[Stream 3<br/>HEADERS, DATA] -.frames.-> Wire
    S5[Stream 5<br/>HEADERS] -.frames.-> Wire
    Wire[Multiplexed frame stream]
  end

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;

Client opens stream ids 1, 3, 5, ... (odd). Server opens even-numbered streams (for push). Frames from different streams interleave; the receiver assembles per stream.

HPACK header compression#

HTTP headers are repetitive (Host, Accept, User-Agent, cookies). HPACK combines:

  • Static table of 61 common headers.
  • Dynamic table of recently seen headers.
  • Huffman encoding of literal values.

Result: a 1KB header set often compresses to <100 bytes.

:method GET           # static table index 2
:path /api/users      # dynamic + Huffman
authorization Bearer eyJ...  # dynamic + Huffman

HPACK was the answer to CRIME-style compression attacks on TLS-compressed HTTP/1.

Flow control#

Per-stream and per-connection windows (default 64KB):

WINDOW_UPDATE  stream_id=3  delta=32768  # I can receive 32KB more on stream 3
WINDOW_UPDATE  stream_id=0  delta=32768  # connection-level

Recipient must consume bytes before issuing more credit. Prevents a fast sender from overwhelming a slow stream.

Prioritisation#

Each stream declares a priority: a weight and an optional dependency on another stream. Servers use these to schedule frame output. The original priority scheme in RFC 7540 was complex and largely abandoned; RFC 9218 introduced the simpler Priority header (urgency 0-7, incremental flag).

Server push#

PUSH_PROMISE stream=3 promised_stream=4 headers=GET /style.css

Server proactively sends resources the client will need. In practice, server push has been deprecated in Chrome and most CDNs in favor of 103 Early Hints, because it was hard to predict cache state.

Connection coalescing#

If a client has an HTTP/2 connection to a.example.com and is about to open one to b.example.com, and the TLS cert covers both, the browser may reuse the existing connection. Saves a handshake per origin.

Head-of-line blocking - still there at the TCP layer#

flowchart LR
  S1[Stream 1] --> Wire
  S2[Stream 2] --> Wire
  Wire --> TCP[TCP segment]
  TCP -. one packet lost .-> Drop
  Drop -. stalls all streams .-> S1
  Drop -. stalls all streams .-> S2

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;

HTTP/2 fixed HOL at the HTTP layer, but a lost TCP segment still stalls every multiplexed stream until retransmit. QUIC (HTTP/3) finally solves this by replacing TCP.

Operational notes#

  • Connection longevity: HTTP/2 connections live for minutes/hours. Load balancers must handle long-lived L7 connections.
  • Single connection per origin: solves the 6-connection limit of HTTP/1.1 but concentrates load. Make sure LBs distribute streams.
  • Slow start: TCP slow start applies; new connections are slow for the first second.

Where HTTP/2 fits#

flowchart TB
  H2((HTTP/2))
  HTTP[HTTP protocols<br/>parent comparison]
  TCP[TCP deep dive<br/>the transport]
  H3[HTTP/3 + QUIC<br/>successor]
  GRPC[gRPC mechanics<br/>top H2 user]
  HTTP --> H2
  TCP --> H2
  H2 -. evolves to .-> H3
  H2 --> GRPC

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
    class H2 service;
    class HTTP,TCP,H3,GRPC datastore;

Glossary & fundamentals#

Tag Concept What it is Page
HLD HTTP protocols the overview page http-protocols
HLD TCP deep dive underlying transport tcp-deep-dive
HLD HTTP3 QUIC TCP HOL fix http3-quic
HLD gRPC mechanics top consumer of HTTP/2 grpc-mechanics

Quick reference#

Key changes from HTTP/1.1#

  • Binary framing instead of text
  • Stream multiplexing on one TCP connection
  • HPACK header compression
  • Server push (now deprecated, use 103 Early Hints)
  • Flow control per stream and connection

Frame types#

DATA, HEADERS, SETTINGS, WINDOW_UPDATE, PUSH_PROMISE, RST_STREAM, PING, GOAWAY.

Streams#

Client streams: 1, 3, 5, ... (odd) Server-pushed streams: 2, 4, 6, ... (even)

HPACK#

Static table + dynamic table + Huffman; typical compression 90%+ on repeated headers.

Flow control#

WINDOW_UPDATE per stream and connection. Default 64KB window. Tune up for high-BDP.

Prioritization#

Original tree-based scheme deprecated. RFC 9218 Priority header (urgency 0-7, incremental).

Limitation#

TCP-level HOL: one lost segment blocks every multiplexed stream until retransmit. Fixed by HTTP/3.

Tools#

  • nghttp2, h2load for testing
  • Chrome chrome://net-export/ for traces
  • curl --http2 for client experiments

Refs#

  • RFC 9113 - HTTP/2
  • RFC 7541 - HPACK
  • web.dev HTTP/2 introduction

FAQ#

What problem does HTTP/2 solve over HTTP/1.1?#

HTTP/2 removes HTTP-layer head-of-line blocking by multiplexing many requests over one TCP connection, and compresses headers with HPACK to cut bytes on the wire.

How does HTTP/2 multiplexing work?#

Each request gets a stream ID, and frames carry that ID so the receiver can interleave and demultiplex many in-flight requests on a single TCP connection.

Does HTTP/2 still suffer from head-of-line blocking?#

Yes, at the TCP layer. If a packet is lost, all HTTP/2 streams stall until retransmission. HTTP/3 over QUIC fixes this by running streams over UDP.

What is HPACK in HTTP/2?#

HPACK is a stateful header compression scheme that uses static and dynamic tables of common header fields to avoid resending the same headers on every request.

Is HTTP/2 server push still used?#

Rarely. Most browsers and CDNs have deprecated server push because cache-aware preload links proved simpler and more effective in practice.

Further reading#