Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-83205

QNetworkAccessManager doesn't reply when using AlwaysCache as cache attribute

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed
    • Priority: P1: Critical
    • Resolution: Done
    • Affects Version/s: 5.12.7
    • Fix Version/s: 5.15.1
    • Component/s: Network: Cache
    • Labels:
      None
    • Platform/s:
      Linux/X11, Windows
    • Commits:
      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();
          });
      }
      

        Attachments

        For Gerrit Dashboard: QTBUG-83205
        # Subject Branch Project Status CR V

          Activity

            People

            Assignee:
            manordheim Mårten Nordheim
            Reporter:
            rflobao Rafael Fassi Lobão
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved:

                Gerrit Reviews

                There are no open Gerrit changes