diff --git a/tests/auto/network/access/http2/http2srv.cpp b/tests/auto/network/access/http2/http2srv.cpp index b52ea5527bd..00c7669b38f 100644 --- a/tests/auto/network/access/http2/http2srv.cpp +++ b/tests/auto/network/access/http2/http2srv.cpp @@ -191,6 +191,9 @@ void Http2Server::sendServerSettings() writer.append(it.value()); if (it.key() == Settings::INITIAL_WINDOW_SIZE_ID) streamRecvWindowSize = it.value(); + if (it.key() == Settings::HEADER_TABLE_SIZE_ID) { + pendingMaxTableSizeUpdate = it.value(); + } } writer.write(*socket); // Now, let's update our peer on a session recv window size: @@ -669,6 +672,13 @@ void Http2Server::handleSETTINGS() return; } + // The client ACKed our setting, including the new decoder table size, + // so we can update it now: + if (pendingMaxTableSizeUpdate) { + decoder.setMaxDynamicTableSize(*pendingMaxTableSizeUpdate); + pendingMaxTableSizeUpdate.reset(); + } + waitingClientAck = false; emit serverSettingsAcked(); return; diff --git a/tests/auto/network/access/http2/http2srv.h b/tests/auto/network/access/http2/http2srv.h index dc94318527b..c74a51bdb9d 100644 --- a/tests/auto/network/access/http2/http2srv.h +++ b/tests/auto/network/access/http2/http2srv.h @@ -213,6 +213,8 @@ private: bool sendTrailingHEADERS = false; int informationalStatusCode = 0; + + std::optional pendingMaxTableSizeUpdate; protected slots: void ignoreErrorSlot(); }; diff --git a/tests/auto/network/access/http2/tst_http2.cpp b/tests/auto/network/access/http2/tst_http2.cpp index d80a7fbc656..d7a36f61274 100644 --- a/tests/auto/network/access/http2/tst_http2.cpp +++ b/tests/auto/network/access/http2/tst_http2.cpp @@ -113,6 +113,8 @@ private slots: void limitedConcurrentStreamsAllowed(); + void maxHeaderTableSize(); + protected slots: // Slots to listen to our in-process server: void serverStarted(quint16 port); @@ -1637,6 +1639,55 @@ void tst_Http2::limitedConcurrentStreamsAllowed() QCOMPARE(finishedCount, TotalRequests); } +void tst_Http2::maxHeaderTableSize() +{ + clearHTTP2State(); + serverPort = 0; + + H2Type connectionType = H2Type::h2Direct; + RawSettings maxHeaderTableSize{ { Http2::Settings::HEADER_TABLE_SIZE_ID, 0 } }; + ServerPtr targetServer(newServer(maxHeaderTableSize, connectionType)); + + QMetaObject::invokeMethod(targetServer.data(), "startServer", Qt::QueuedConnection); + runEventLoop(); + + QVERIFY(serverPort != 0); + + nRequests = 1; + + const auto url = requestUrl(connectionType); + QNetworkRequest request(url); + request.setAttribute(QNetworkRequest::Http2DirectAttribute, true); + + constexpr int extraRequests = 5; + std::array, extraRequests> replies; + for (qint32 i = 0; i < 1 + extraRequests; ++i) { + for (qint32 j = 0; j < 100; ++j) { + request.setRawHeader("x-test" + QByteArray::number(j), + "Hello World" + QByteArray::number(i)); + } + std::unique_ptr reply{ manager->get(request) }; + reply->ignoreSslErrors(); + connect(reply.get(), &QNetworkReply::finished, this, &tst_Http2::replyFinished); + + if (i == 0) { + runEventLoop(); + STOP_ON_FAILURE + QCOMPARE(reply->error(), QNetworkReply::NoError); + nRequests = extraRequests; + } else { + replies[i - 1] = std::move(reply); + } + } + + runEventLoop(); + STOP_ON_FAILURE + + QCOMPARE(nRequests, 0); + for (const auto &reply : replies) + QCOMPARE(reply->error(), QNetworkReply::NoError); +} + void tst_Http2::serverStarted(quint16 port) { serverPort = port;