Http2 protocol handler: Fix handling of MAX_HEADER_TABLE_SIZE setting
Like the patch in dev, but for 6.8 and below We need to, following the RFC, send a Dynamic Table Size Update using HPack once we have acknowledged the setting as long as the new size is smaller, or if we decide to use the new, larger size. It's further complicated by the fact that we need to send this update on the next 'field block' (anything with headers in it), and we may have multiple SETTING frames come in, and we need to then acknowledge the _smallest_ one as well as the _final_ one. This is so the decoder on the peer's side can know that we have set the smallest size, and trimmed our tables thusly, before going to the larger size. This could, for example, be used to clear the table. Fixes: QTBUG-132277 Pick-to: 6.5 Change-Id: I95f006248dfcbc7952c7e184f92d8859270e9e70 Reviewed-by: Mate Barany <mate.barany@qt.io>
This commit is contained in:
parent
42a62db6f9
commit
a428e89562
@ -441,6 +441,16 @@ bool QHttp2ProtocolHandler::sendHEADERS(Stream &stream)
|
||||
|
||||
// Compress in-place:
|
||||
BitOStream outputStream(frameWriter.outboundFrame().buffer);
|
||||
|
||||
// Possibly perform and notify of dynamic table size update:
|
||||
for (auto &maybePendingTableSizeUpdate : pendingTableSizeUpdates) {
|
||||
if (!maybePendingTableSizeUpdate)
|
||||
break; // They are ordered, so if the first one is null, the other one is too.
|
||||
encoder.setMaxDynamicTableSize(*maybePendingTableSizeUpdate);
|
||||
encoder.encodeSizeUpdate(outputStream, *maybePendingTableSizeUpdate);
|
||||
maybePendingTableSizeUpdate.reset();
|
||||
}
|
||||
|
||||
if (!encoder.encodeRequest(outputStream, headers))
|
||||
return false;
|
||||
|
||||
@ -989,7 +999,15 @@ bool QHttp2ProtocolHandler::acceptSetting(Http2::Settings identifier, quint32 ne
|
||||
connectionError(PROTOCOL_ERROR, "SETTINGS invalid table size");
|
||||
return false;
|
||||
}
|
||||
encoder.setMaxDynamicTableSize(newValue);
|
||||
if (!pendingTableSizeUpdates[0] && encoder.dynamicTableCapacity() == newValue)
|
||||
return true; // No change, no need to update.
|
||||
|
||||
if (pendingTableSizeUpdates[0].value_or(std::numeric_limits<quint32>::max()) >= newValue) {
|
||||
pendingTableSizeUpdates[0] = newValue;
|
||||
pendingTableSizeUpdates[1].reset(); // 0 is the latest _and_ smallest, so we don't need 1
|
||||
} else {
|
||||
pendingTableSizeUpdates[1] = newValue; // newValue was larger than 0, so it goes to 1
|
||||
}
|
||||
}
|
||||
|
||||
if (identifier == Settings::INITIAL_WINDOW_SIZE_ID) {
|
||||
|
@ -127,6 +127,13 @@ private:
|
||||
HPack::Decoder decoder;
|
||||
HPack::Encoder encoder;
|
||||
|
||||
// If we receive SETTINGS_HEADER_TABLE_SIZE in a SETTINGS frame we have to perform a dynamic
|
||||
// table size update on the _next_ HEADER block we send.
|
||||
// Because this only happens on the next block we may have multiple pending updates, so we must
|
||||
// notify of the _smallest_ one followed by the _final_ one. We keep them sorted in that order.
|
||||
// @future: keep in mind if we add support for sending PUSH_PROMISE because it is a HEADER block
|
||||
std::array<std::optional<quint32>, 2> pendingTableSizeUpdates;
|
||||
|
||||
QHash<QObject *, int> streamIDs;
|
||||
QHash<quint32, Stream> activeStreams;
|
||||
std::deque<quint32> suspendedStreams[3]; // 3 for priorities: High, Normal, Low.
|
||||
|
Loading…
x
Reference in New Issue
Block a user