HTTP/2 gets its speed from multiplexing: many requests share one TCP connection by riding on independent streams. But multiplexing also creates contention. If a receiver cannot process data on one stream yet wants to keep working on others, it needs a way to hold back that one stream without stalling the whole connection. RFC 9113 §5.2 defines flow control as the mechanism that lets endpoints do exactly that, and it is defined to protect endpoints operating under resource constraints.
The scheme is credit-based and runs on WINDOW_UPDATE frames. A receiver advertises how many octets it is prepared to accept, and a sender must not transmit DATA beyond that credit. As the receiver consumes data it sends WINDOW_UPDATE to add credit back. Flow control is directional and receiver-driven: each endpoint advertises its own window for what it receives and must obey the window its peer advertises for what it sends.
There are two windows, and a sender must respect both. One covers the connection as a whole, shared by every stream on it. The other covers each stream individually. A sender may send DATA only when both the connection window and that stream’s own window have room. This two-level design is what lets a receiver hold back one stream it cannot process yet while the other streams on the connection keep flowing, and it ensures streams on the same connection do not destructively interfere with each other.
Two details matter in practice. First, only DATA frames are subject to flow control. HEADERS, SETTINGS, WINDOW_UPDATE, and the other control frames do not consume window space. The RFC states the reason directly: this ensures that important control frames are not blocked by flow control (RFC 9113 §5.2.1). Second, the initial window is 65,535 octets for both a new stream and the overall connection, though an endpoint can advertise more, up to 2^31-1.
The RFC is explicit about who this protects: constrained receivers. A proxy that shares memory across many connections, or one with a slow upstream and a fast downstream, uses flow control to bound how much a peer can push at it. An endpoint that needs no protection can advertise the maximum window and top it up as data arrives, effectively disabling its own flow control. What it cannot do is ignore its peer’s signals: a sender is always bound by the window the receiver advertises.
The cost is throughput. §5.2.3 notes that if an endpoint cannot keep the window it grants its peer larger than that peer’s bandwidth-delay product, its own receive throughput will be limited by flow control and performance degrades. The improvement is hedged, not free: sending timely WINDOW_UPDATE frames can improve performance, balanced against the risk of letting a peer consume too much memory.

The Campfire
CommentsThanks. Your comment is waiting for the desk. Once it is approved it appears here within about a minute.
Add a comment