diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp index 419c1e2180d..b288e3a885f 100644 --- a/src/network/access/qhttp2protocolhandler.cpp +++ b/src/network/access/qhttp2protocolhandler.cpp @@ -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::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) { diff --git a/src/network/access/qhttp2protocolhandler_p.h b/src/network/access/qhttp2protocolhandler_p.h index 3b818771a64..80581ea1313 100644 --- a/src/network/access/qhttp2protocolhandler_p.h +++ b/src/network/access/qhttp2protocolhandler_p.h @@ -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, 2> pendingTableSizeUpdates; + QHash streamIDs; QHash activeStreams; std::deque suspendedStreams[3]; // 3 for priorities: High, Normal, Low.