Details
-
Bug
-
Resolution: Fixed
-
P1: Critical
-
6.4.2
-
None
-
8
-
a6776de0c (dev), e5f295c8a (dev), de47bc2c1 (6.5), cfb879565 (6.5), 9c27e1659 (6.4), c3dd38cf8 (tqtc/lts-6.2), 45b691f02 (6.4), 8755c0561 (tqtc/lts-6.2)
-
Foundation Sprint 77
Description
When making a cached request for which there is a corrupted cache file (in particular a cache file with empty contents), the request never terminates.
Steps to reproduce
The issue can be reproduced with the following MWE:
#include <QtCore> #include <QtNetwork>int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QNetworkAccessManager nam; QObject::connect(&nam, &QNetworkAccessManager::finished, &nam, [](QNetworkReply *reply) { QTextStream(stdout) << "Got a reply: " << reply->url().toDisplayString() << Qt::endl; reply->deleteLater(); }); auto cache = new QNetworkDiskCache; cache->setCacheDirectory("/tmp/qtcache"); nam.setCache(cache); nam.setRedirectPolicy(QNetworkRequest::ManualRedirectPolicy); QNetworkRequest req(QUrl("https://www.qt.io/hubfs/Quality_Assurance.png")); auto reply = nam.get(req); QObject::connect(reply, &QNetworkReply::finished, &a, &QCoreApplication::quit); return a.exec(); }
- Run the code once to download a cached copy of https://www.qt.io/hubfs/Quality_Assurance.png (this is just an URL that has proper caching headers set) in `/tmp/qtcache`. It should print `Got a reply: https://www.qt.io/hubfs/Quality_Assurance.png` then exit cleanly.
- Manually corrupt the cache file that got created in `/tmp/qtcache/data8/` to only keep the first line (the exact name of the cache file may be different on your machine):
$ sed -i -n '1p' /tmp/qtcache/data8/6/3ia6ms7v.d
- Run the code again. It now never prints the `Got a reply` message and hangs forever.
Additional Information
I tracked this down to `QNetworkReplyHttpImplPrivate::_q_cacheLoadReadyRead` failing early because `cacheLoadDevice->bytesAvailable()` is `0` in that case, but `_q_cacheLoadReadyRead` is never called again afterwards.
Note that QNetworkDiskCache seems to be using atomic rename in `QNetworkDiskCachePrivate::storeItem` so from my understanding it should not be able to create such corrupted/partial cache files yet we saw it happen here.
Attachments
For Gerrit Dashboard: QTBUG-111397 | ||||||
---|---|---|---|---|---|---|
# | Subject | Branch | Project | Status | CR | V |
464521,3 | QNetworkDiskCache: use QSaveFile | dev | qt/qtbase | Status: MERGED | +2 | 0 |
464523,4 | QNetwork[http]: Discard or ignore corrupted cache entries | dev | qt/qtbase | Status: MERGED | +2 | 0 |
465543,3 | QNetworkDiskCache: use QSaveFile | 6.5 | qt/qtbase | Status: MERGED | +2 | 0 |
465544,3 | QNetworkDiskCache: use QSaveFile | 6.4 | qt/qtbase | Status: MERGED | +2 | 0 |
465546,2 | QNetwork[http]: Discard or ignore corrupted cache entries | 6.4 | qt/qtbase | Status: MERGED | +2 | 0 |
465547,2 | QNetwork[http]: Discard or ignore corrupted cache entries | 6.5 | qt/qtbase | Status: MERGED | +2 | 0 |
465550,3 | QNetworkDiskCache: use QSaveFile | tqtc/lts-6.2 | qt/tqtc-qtbase | Status: MERGED | +2 | 0 |
465551,2 | QNetwork[http]: Discard or ignore corrupted cache entries | tqtc/lts-6.2 | qt/tqtc-qtbase | Status: MERGED | +2 | 0 |