When remote peers set the value of HEADER_TABLE_SIZE to any non-default value, or when we update it, we should respect that value when we're emitting headers.
Unfortunately, right now we don't. In particular, we manage to update the wrong setting: when the peer sets HEADER_TABLE_SIZE we bound the maximum size of the dynamic table they can use, not the maximum size we can use. That's incorrect by the spec, which says:
This setting allows the sender to inform the remote endpoint of the
maximum size of the compression table used to decode field blocks,
in units of octets. The encoder can select any size equal to or less
than this value by using signaling specific to the compression
format inside a field block (see [COMPRESSION]).
If a peer sent us SETTINGS_HEADER_TABLE_SIZE with a value of 0, we'd restrict them to only using a maximum table size of 0, instead of us. This is wrong.
Additionally, when we updated the encoder we used the wrong method, so the encoder would never send dynamic table size changes. This was also incorrect!
In general this managed to get missed because, as RFC 9113 notes:
Implementers are advised that reducing the value of
SETTINGS_HEADER_TABLE_SIZE is not widely interoperable. Use of the
connection preface to reduce the value below the initial value of
4,096 is somewhat better supported, but this might fail with some
implementations.
It turns out one of those implementations this might fail with is us! The result, however, is that very few implementations actually try to reduce the value of the header table size, so we rarely ran into this issue. nginx does actually try this in some cases, however, which is how we found this problem.
Modifications:
Correctly invert the application of the value of SETTINGS_HEADER_TABLE_SIZE
Correctly use setDynamicTableSize on HPACKEncoder instead of just setting the field manually.
Deprecate the invalid method of setting the field on HPACKEncoder.
Add some HTTP/2-level tests that ensure we correctly handle these changes.
Result:
Vastly better handling of peers reducing the value of SETTINGS_HEADER_TABLE_SIZE.
Motivation:
When remote peers set the value of HEADER_TABLE_SIZE to any non-default value, or when we update it, we should respect that value when we're emitting headers.
Unfortunately, right now we don't. In particular, we manage to update the wrong setting: when the peer sets HEADER_TABLE_SIZE we bound the maximum size of the dynamic table they can use, not the maximum size we can use. That's incorrect by the spec, which says:
If a peer sent us SETTINGS_HEADER_TABLE_SIZE with a value of 0, we'd restrict them to only using a maximum table size of 0, instead of us. This is wrong.
Additionally, when we updated the encoder we used the wrong method, so the encoder would never send dynamic table size changes. This was also incorrect!
In general this managed to get missed because, as RFC 9113 notes:
It turns out one of those implementations this might fail with is us! The result, however, is that very few implementations actually try to reduce the value of the header table size, so we rarely ran into this issue. nginx does actually try this in some cases, however, which is how we found this problem.
Modifications:
setDynamicTableSize
on HPACKEncoder instead of just setting the field manually.Result:
Vastly better handling of peers reducing the value of SETTINGS_HEADER_TABLE_SIZE.