Skip to main content

HEADERS_BUFFER_BUDGET

Constant HEADERS_BUFFER_BUDGET 

Source
pub const HEADERS_BUFFER_BUDGET: usize = _; // 1_048_576usize
Expand description

Most encoded frame payload one connection may hold buffered at once, in bytes (D77).

MAX_FIELD_SECTION_SIZE bounds one frame; this bounds their sum, and the two are reached by different peers. A client held to the per-frame bound may still open every request stream its transport parameters allow – 1024 by default – announce a 64 KiB HEADERS frame on each and stop one byte short of finishing any of them. Nothing in that is a rule broken on any single stream, and the frames are held because they cannot be acted on piecewise: 64 MiB of a connection’s memory, from a peer that has not authenticated, for as long as the transport is willing to call it alive, and available again the moment the streams are reset. Multiplied by limits.max_connections it is the whole of the machine. D76 bounds how long one stream may wait; this bounds how much waiting costs.

A megabyte is sixteen frames of the largest size this server will buffer at all, and some four thousand of the size a real one is – a CONNECT request carrying Basic credentials is under 300 bytes, so all 1024 request streams the transport allows could be mid-HEADERS at once and still be using a tenth of this.

The exact boundary is worth stating, because it is not “a client that finishes what it starts”: what is counted is the announced length of the frames being buffered at one moment, so sixteen concurrent field sections of the largest advertised size fill it and the seventeenth does not fit – whether or not every one of them is completed a moment later. A peer that reaches it loses that one request, which is answered with 431 and stopped (frame::BufferBudget::charge); the connection and every tunnel on it carry on. Bounding a moment rather than a rate is what makes the value a constant here rather than a knob in [limits]: it is a ceiling on memory, and the machine’s is not configurable either.

The peer’s control stream is not counted here. There is one of it per connection and it buffers one frame at a time, so frame::MAX_BUFFERED_FRAME bounds it on its own – and a peer that had filled this budget with request streams must not thereby have its own SETTINGS or GOAWAY refused, since nothing on that stream can be refused stream by stream.

The unit is encoded octets as they arrived, the same count frame::MAX_BUFFERED_FRAME applies per frame – not RFC 9114 §4.2.2’s field-section size, which is what MAX_FIELD_SECTION_SIZE measures.