HTTP/2 uses two levels of flow control (RFC 7540 Section 5.2):
- Connection-level: shared across all streams
- Per-stream: independent for each stream
Both start at 65535 bytes (default initial window size).
When the server receives DATA frames:
- Check payload size against connection receive window
- If exceeded → GOAWAY with FLOW_CONTROL_ERROR
- Deduct from connection window
- Send WINDOW_UPDATE on stream 0 (connection) to replenish
- Send WINDOW_UPDATE on stream ID to replenish
- Accumulate data in request body
The server immediately replenishes windows after consuming data, preventing backpressure from blocking clients.
When sending response DATA frames:
- Calculate sendable = min(remaining, maxFrameSize, connWindow, streamWindow)
- If sendable = 0 → stop; caller must retry after WINDOW_UPDATE
- Consume from stream send window via
ConsumeSendWindow - Deduct from connection send window
- Encode DATA frame header + payload
- Advance body offset
If the send window is exhausted mid-response, SendResponse returns
early. The caller must call FlushData after receiving WINDOW_UPDATE
frames from the client.
Incoming WINDOW_UPDATE frames:
- Stream 0: updates
connRecvWindow(connection level) - Stream N: calls
UpdateSendWindowon the stream's H2Stream
Zero-increment WINDOW_UPDATE is a protocol error.
The SETTINGS_INITIAL_WINDOW_SIZE parameter affects new streams.
When the remote peer changes this setting, existing streams are NOT
retroactively adjusted (simplified implementation).