From 41d217829cc1c34ae7c2fee92316a91a77018f00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Thu, 21 Apr 2022 17:32:59 +0200 Subject: [PATCH] QHttp: Fix handling of redirect loaded from cache In some situations when loading a redirect from cache which would lead to a real request we would not emit the finished() signal because the replyFinished function has a pre-condition that the response did not originate from the cache. However, after the initial redirect was loaded from the cache we never unset the 'loadingFromCache' boolean, so it was still true after the request had been made to the real target. Pick-to: 6.2 6.3 5.15 Change-Id: I015a2ebae4af4bd17392182c3951e875a7b353c4 Reviewed-by: Edward Welbourne Reviewed-by: Timur Pocheptsov --- src/network/access/qnetworkreplyhttpimpl.cpp | 1 + .../qnetworkreply/tst_qnetworkreply.cpp | 59 +++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 486994a1de..5a125850d5 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -712,6 +712,7 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq httpRequest.setRedirectPolicy(redirectPolicy); httpRequest.setPriority(convert(newHttpRequest.priority())); + loadingFromCache = false; switch (operation) { case QNetworkAccessManager::GetOperation: diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index 9c177e6281..50084beb0a 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -500,6 +500,7 @@ private Q_SLOTS: void ioHttpCookiesDuringRedirect(); void ioHttpRedirect_data(); void ioHttpRedirect(); + void ioHttpRedirectWithCache(); void ioHttpRedirectFromLocalToRemote(); void ioHttpRedirectPostPut_data(); void ioHttpRedirectPostPut(); @@ -8874,6 +8875,64 @@ void tst_QNetworkReply::ioHttpRedirect() QVERIFY(validateRedirectedResponseHeaders(reply)); } +/* + Test that, if we load a redirect from cache, we don't treat the request to + the destination of the redirect as a redirect. + + If it was treated as a redirect the finished() signal was never emitted! +*/ +void tst_QNetworkReply::ioHttpRedirectWithCache() +{ + // Disallow caching the result so that the second request must also send the request + QByteArray http200ResponseNoCache = "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "Cache-Control: no-cache\r\n" + "\r\nHello"; + + MiniHttpServer target(http200ResponseNoCache, false); + QUrl targetUrl("http://localhost/"); + targetUrl.setPort(target.serverPort()); + + // A cache-able redirect reply + QString redirectReply = QStringLiteral("HTTP/1.1 308\r\n" + "Content-Type: text/plain\r\n" + "location: %1\r\n" + "Cache-Control: max-age=3600\r\n" + "\r\nYou're being redirected").arg(targetUrl.toString()); + MiniHttpServer redirectServer(redirectReply.toLatin1(), false); + QUrl url("http://localhost/"); + url.setPort(redirectServer.serverPort()); + + QTemporaryDir tempDir(QDir::tempPath() + "/tmp_cache_28035"); + QVERIFY2(tempDir.isValid(), qPrintable(tempDir.errorString())); + tempDir.setAutoRemove(true); + + QNetworkDiskCache *diskCache = new QNetworkDiskCache(); + diskCache->setCacheDirectory(tempDir.path()); + // Manager takes ownership of the cache: + manager.setCache(diskCache); + QCOMPARE(diskCache->cacheSize(), 0); + + // Send the first request, we end up caching the redirect reply + QNetworkRequest request(url); + QNetworkReplyPtr reply(manager.get(request)); + + QCOMPARE(waitForFinish(reply), int(Success)); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QVERIFY(validateRedirectedResponseHeaders(reply)); + + QVERIFY(diskCache->cacheSize() != 0); + + // Now for the second request, we will use the cache, and we test that the finished() + // signal is still emitted. + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); + reply.reset(manager.get(request)); + + QCOMPARE(waitForFinish(reply), int(Success)); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QVERIFY(validateRedirectedResponseHeaders(reply)); +} + void tst_QNetworkReply::ioHttpRedirectFromLocalToRemote() { QUrl targetUrl("http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt");