Skip to content

HTTP/2 and HTTP/3 | Networking

HTTP/2 (RFC 9113) and HTTP/3 (RFC 9114) are the modern versions of the Hypertext Transfer Protocol. HTTP/2 brought binary framing, multiplexing, and header compression to address the limitations of HTTP/1.1. HTTP/3 replaces TCP with QUIC (a UDP-based transport) to eliminate TCP-level head-of-line Blocking and enable features like connection migration.

Both protocols maintain the same HTTP semantics (methods, status codes, headers, URIs) as HTTP/1.1. The change is in how the bytes are formatted on the wire, not in what they mean.

HTTP/1.1 is a text protocol. HTTP/2 is a binary protocol. Every HTTP/2 communication is performed Over a single TCP connection, and all communication is split into smaller messages and frames.

+-----------------------------------------------+
| Frame Header (9 bytes) |
| |
| Length (24): frame payload length |
| Type (8): DATA, HEADERS, SETTINGS, etc. |
| Flags (8): END_STREAM, END_HEADERS, etc. |
| Reserved (1) + Stream Identifier (31) |
+-----------------------------------------------+
| Frame Payload (0 to 2^24-1) |
+-----------------------------------------------+

A stream is a bidirectional flow of frames within a single HTTP/2 connection. Multiple streams are Multiplexed over a single TCP connection. Each stream has a unique 31-bit identifier. Client-initiated streams use odd numbers; server-initiated streams use even numbers.

Client Server
| |
|--- HEADERS [stream 1] ----------------------->| GET /style.css
|--- HEADERS [stream 3] ----------------------->| GET /script.js
|--- HEADERS [stream 5] ----------------------->| GET /image.png
| |
|<-- HEADERS [stream 1] ------------------------| 200 OK
|<-- DATA [stream 1] ---------------------------| CSS content
|<-- HEADERS [stream 3] ------------------------| 200 OK
|<-- DATA [stream 3] ---------------------------| JS content
|<-- HEADERS [stream 5] ------------------------| 200 OK
|<-- DATA [stream 5] ---------------------------| Image data

No ordering requirement exists between streams. The server can send stream 5”s data before stream 1’s, and the client reassembles each stream independently.

HTTP/2 implements flow control at the stream level and the connection level. Each side advertises a Window size (initially 65,535 bytes, configurable via SETTINGS). The sender must not send more data Than the receiver’s window allows. The receiver sends WINDOW_UPDATE frames to increase the window.

This prevents a fast sender from overwhelming a slow receiver. Without flow control, a server Sending a large response could exhaust the client’s receive buffer.

Client Server
| |
|<-- DATA [stream 1, 16KB] --------------------| (client window decreases)
|<-- DATA [stream 1, 16KB] --------------------| (client window decreases)
|--- WINDOW_UPDATE [stream 1, +32KB] ---------->| (client grants more window)
|<-- DATA [stream 1, 32KB] --------------------| (server can send more)

HTTP/1.1 sends headers as plain text, repeated on every request. For a typical page load with 30-100 Requests, headers like User-Agent``Accept``CookieAnd Accept-Encoding are sent dozens of Times, each time consuming hundreds of bytes.

HPACK (RFC 7541) compresses headers using three techniques:

  1. Static table: 61 predefined common header field/value pairs (e.g., :method: GET :path: /``accept-encoding: gzip, deflate)
  2. Dynamic table: Header fields sent in previous messages are cached and referenced by index number
  3. Huffman coding: Literal header values are encoded using Huffman coding, which reduces common ASCII strings by ~20-30%
First request:
:method: GET
:path: /api/users
accept: application/json
user-agent: Mozilla/5.0...
Second request (to same server):
:method: GET <- static table index 2
:path: /api/users <- dynamic table index (from first request)
accept: application/json <- dynamic table index
user-agent: Mozilla/5.0... <- dynamic table index
Second request on wire: ~20 bytes (3 index references) vs ~200 bytes (full headers)

HTTP/2 is like upgrading from a single-lane road to a multi-lane highway. HTTP/1.1 forces all requests to wait in line (head-of-line blocking), while HTTP/2 lets multiple requests travel simultaneously in separate lanes (streams) on the same connection. Header compression is like using abbreviations for frequently used phrases - instead of repeating the full address every time, you use a short code. HTTP/3 goes further by replacing the road entirely - QUIC runs over UDP, eliminating TCP’s requirement that all packets arrive in order. This is like switching from a convoy system (where a slow truck blocks everyone) to independent delivery drones that can take different paths. The key insight is that these versions improve transport mechanics without changing HTTP semantics.

  • HTTP - HTTP/1.1 fundamentals that HTTP/2 and HTTP/3 build upon
  • TLS - How TLS 1.3 is required for HTTP/2 and integral to HTTP/3’s QUIC transport
  • WebSockets - How persistent connections differ between HTTP/2 streams and WebSocket frames