diff --git a/src/core/jobs/httpworker.h b/src/core/jobs/httpworker.h --- a/src/core/jobs/httpworker.h +++ b/src/core/jobs/httpworker.h @@ -45,7 +45,7 @@ Q_SIGNAL void data(const QByteArray& data); Q_SLOT void handleReadyRead(); - Q_SLOT void handleFinished(QNetworkReply* reply); + Q_SLOT void handleFinished(); Q_SLOT void handleData(const QByteArray& data); private: class Private; diff --git a/src/core/jobs/httpworker.cpp b/src/core/jobs/httpworker.cpp --- a/src/core/jobs/httpworker.cpp +++ b/src/core/jobs/httpworker.cpp @@ -20,24 +20,54 @@ #include "knewstuffcore_debug.h" #include +#include +#include +#include #include +#include #include #include +#include +#include + +class HTTPWorkerNAM { +public: + HTTPWorkerNAM() + { + QMutexLocker locker(&mutex); + const QString cacheLocation = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QStringLiteral("/knewstuff"); + cache.setCacheDirectory(cacheLocation); + QStorageInfo storageInfo(cacheLocation); + cache.setMaximumCacheSize(qMin(50 * 1024 * 1024, (int)(storageInfo.bytesTotal() / 1000))); + nam.setCache(&cache); + } + QNetworkAccessManager nam; + QMutex mutex; + + QNetworkReply* get(const QNetworkRequest& request) + { + QMutexLocker locker(&mutex); + return nam.get(request); + } + +private: + QNetworkDiskCache cache; +}; + +Q_GLOBAL_STATIC(HTTPWorkerNAM, s_httpWorkerNAM) using namespace KNSCore; class HTTPWorker::Private { public: Private() : jobType(GetJob) - , qnam(nullptr) , reply(nullptr) {} JobType jobType; QUrl source; QUrl destination; - QNetworkAccessManager* qnam; QNetworkReply* reply; QUrl redirectUrl; @@ -51,9 +81,6 @@ qCDebug(KNEWSTUFFCORE) << Q_FUNC_INFO; d->jobType = jobType; d->source = url; - - d->qnam = new QNetworkAccessManager(parent); - connect(d->qnam, &QNetworkAccessManager::finished, this, &HTTPWorker::handleFinished); } HTTPWorker::HTTPWorker(const QUrl& source, const QUrl& destination, KNSCore::HTTPWorker::JobType jobType, QObject* parent) @@ -64,9 +91,6 @@ d->jobType = jobType; d->source = source; d->destination = destination; - - d->qnam = new QNetworkAccessManager(parent); - connect(d->qnam, &QNetworkAccessManager::finished, this, &HTTPWorker::handleFinished); } HTTPWorker::~HTTPWorker() @@ -87,8 +111,10 @@ } QNetworkRequest request(d->source); - d->reply = d->qnam->get(request); + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); + d->reply = s_httpWorkerNAM->get(request); connect(d->reply, &QNetworkReply::readyRead, this, &HTTPWorker::handleReadyRead); + connect(d->reply, &QNetworkReply::finished, this, &HTTPWorker::handleFinished); if(d->jobType == DownloadJob) { d->dataFile.setFileName(d->destination.toLocalFile()); connect(this, &HTTPWorker::data, this, &HTTPWorker::handleData); @@ -98,35 +124,45 @@ void HTTPWorker::handleReadyRead() { // qCDebug(KNEWSTUFFCORE) << Q_FUNC_INFO; + QMutexLocker locker(&s_httpWorkerNAM->mutex); if (d->reply->attribute(QNetworkRequest::RedirectionTargetAttribute).isNull()) { do { emit data(d->reply->read(32768)); } while(!d->reply->atEnd()); } } -void HTTPWorker::handleFinished(QNetworkReply* reply) +void HTTPWorker::handleFinished() { - qCDebug(KNEWSTUFFCORE) << Q_FUNC_INFO; - if (reply->error() != QNetworkReply::NoError) { - qCWarning(KNEWSTUFFCORE) << reply->errorString(); - emit error(reply->errorString()); + qCDebug(KNEWSTUFFCORE) << Q_FUNC_INFO << d->reply->url(); + if (d->reply->error() != QNetworkReply::NoError) { + qCWarning(KNEWSTUFFCORE) << d->reply->errorString(); + emit error(d->reply->errorString()); } + // Check if the data was obtained from cache or not + QString fromCache = d->reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool() ? "(cached)" : "(NOT cached)"; + // Handle redirections - const QUrl possibleRedirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); + const QUrl possibleRedirectUrl = d->reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); if (!possibleRedirectUrl.isEmpty() && possibleRedirectUrl != d->redirectUrl) { - d->redirectUrl = reply->url().resolved(possibleRedirectUrl); + d->redirectUrl = d->reply->url().resolved(possibleRedirectUrl); if (d->redirectUrl.scheme().startsWith("http")) { - qCInfo(KNEWSTUFFCORE) << "Redirected to " << d->redirectUrl.toDisplayString() << "..."; - reply->deleteLater(); - d->reply = d->qnam->get(QNetworkRequest(d->redirectUrl)); + qCDebug(KNEWSTUFFCORE) << d->reply->url().toDisplayString() << "was redirected to" << d->redirectUrl.toDisplayString() << fromCache << d->reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + d->reply->deleteLater(); + QNetworkRequest request(d->redirectUrl); + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); + d->reply = s_httpWorkerNAM->get(request); connect(d->reply, &QNetworkReply::readyRead, this, &HTTPWorker::handleReadyRead); + connect(d->reply, &QNetworkReply::finished, this, &HTTPWorker::handleFinished); return; } else { qCWarning(KNEWSTUFFCORE) << "Redirection to" << d->redirectUrl.toDisplayString() << "forbidden."; } } + else { + qCDebug(KNEWSTUFFCORE) << "Data for" << d->reply->url().toDisplayString() << "was fetched" << fromCache; + } if(d->dataFile.isOpen()) { d->dataFile.close();