Details
-
Bug
-
Resolution: Done
-
P1: Critical
-
5.12.7
-
None
-
-
90012f12b0fd7a6f9d2554fb2027e5f8c08d95ee (qt/qtbase/5.15)
Description
When the fist request made for QNetworkAccessManager is to localhost address and the second request is to a remote address using AlwaysCache as cache attribute, QNetworkAccessManager never replies.
The problem was tested with Qt 5.12.7 in Linux OpenSuse 15.1 and Windows 10, and the problem happens in both.
The issue can be reproduced with the following example:
#include <QCoreApplication> #include <QNetworkAccessManager> #include <QNetworkDiskCache> #include <QNetworkRequest> #include <QNetworkReply> #include <QEventLoop> #include <QTimer> #include <QDebug> #define LocalAddress "http://localhost:3000" #define RemoteAddress "http://www.google.com" #define CacheDirectory "<My cache directoty>" // Set it to some directory void test() { QEventLoop evLoop; QNetworkAccessManager *manager = new QNetworkAccessManager(); QNetworkDiskCache *diskCache = new QNetworkDiskCache(manager); diskCache->setCacheDirectory(CacheDirectory); manager->setCache(diskCache); { QNetworkRequest request(QUrl(LocalAddress)); request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); QNetworkReply *reply = manager->get(request); QObject::connect(reply, &QNetworkReply::finished, &evLoop, &QEventLoop::quit); evLoop.exec(); qDebug() << "Got reply from local"; } { QNetworkRequest request(QUrl(RemoteAddress)); const QNetworkCacheMetaData &metadata = diskCache->metaData(request.url()); request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, metadata.isValid() ? QNetworkRequest::AlwaysCache : QNetworkRequest::PreferCache); QNetworkReply *reply = manager->get(request); QObject::connect(reply, &QNetworkReply::finished, &evLoop, &QEventLoop::quit); evLoop.exec(); qDebug() << "Got reply from remote"; } } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QTimer::singleShot(1, test); return a.exec(); }
The first time the code runs it'll work and the two messages ("Got reply from local" and "Got reply from remote") will be printed, because as there's no cache yet, the provided attribute is PreferCache.
At the second time the code runs, the second message "Got reply from remote" is no longer printed.
A workaround to dodge this problem is always make a request for an external address as the first request for QNetworkAccessManager.
The external address don't need to exist, just the format of the address is important (the QUrl::host shall not be "localhost"). By doing it, the QNetworkAccessManager activates a network session and the bug is avoided.
This is my workaround, where an external address is called after the constructor of the QNetworkAccessManager be called:
NetworkAccess::NetworkAccess(QObject *parent) : QNetworkAccessManager(parent) { QNetworkDiskCache *diskCache = new QNetworkDiskCache(this); diskCache->setCacheDirectory("<My cache directoty>"); setCache(diskCache); QNetworkRequest request(QUrl("http://www.abcdezykzykzyk.mt")); QNetworkReply* reply = QNetworkAccessManager::get(request); QObject::connect(reply, &QNetworkReply::finished, [reply]() { reply->deleteLater(); }); }