summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/network/access/qnetworkaccesshttpbackend.cpp5
-rw-r--r--src/network/access/qnetworkreplyimpl.cpp7
-rw-r--r--tests/auto/qnetworkreply/tst_qnetworkreply.cpp167
3 files changed, 158 insertions, 21 deletions
diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp
index 4189743..108ac68 100644
--- a/src/network/access/qnetworkaccesshttpbackend.cpp
+++ b/src/network/access/qnetworkaccesshttpbackend.cpp
@@ -360,6 +360,11 @@ void QNetworkAccessHttpBackend::validateCache(QHttpNetworkRequest &httpRequest,
return;
}
+ // The disk cache API does not currently support partial content retrieval.
+ // That is why we don't use the disk cache for any such requests.
+ if (request().hasRawHeader("Range"))
+ return;
+
QAbstractNetworkCache *nc = networkCache();
if (!nc)
return; // no local cache
diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp
index 343f344..894df79 100644
--- a/src/network/access/qnetworkreplyimpl.cpp
+++ b/src/network/access/qnetworkreplyimpl.cpp
@@ -505,6 +505,13 @@ void QNetworkReplyImplPrivate::initCacheSaveDevice()
{
Q_Q(QNetworkReplyImpl);
+ // The disk cache does not support partial content, so don't even try to
+ // save any such content into the cache.
+ if (q->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 206) {
+ cacheEnabled = false;
+ return;
+ }
+
// save the meta data
QNetworkCacheMetaData metaData;
metaData.setUrl(url);
diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp
index 39bb0fc..81278b6 100644
--- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp
+++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp
@@ -333,6 +333,8 @@ private Q_SLOTS:
void synchronousRequest();
void synchronousRequestSslFailure();
+ void dontInsertPartialContentIntoTheCache();
+
// NOTE: This test must be last!
void parentingRepliesToTheApp();
};
@@ -573,6 +575,63 @@ public:
Q_DECLARE_METATYPE(MyMemoryCache::CachedContent)
Q_DECLARE_METATYPE(MyMemoryCache::CacheData)
+class MySpyMemoryCache: public QAbstractNetworkCache
+{
+public:
+ MySpyMemoryCache(QObject *parent) : QAbstractNetworkCache(parent) {}
+ ~MySpyMemoryCache()
+ {
+ qDeleteAll(m_buffers);
+ m_buffers.clear();
+ }
+
+ QHash<QUrl, QIODevice*> m_buffers;
+ QList<QUrl> m_insertedUrls;
+
+ QNetworkCacheMetaData metaData(const QUrl &)
+ {
+ return QNetworkCacheMetaData();
+ }
+
+ void updateMetaData(const QNetworkCacheMetaData &)
+ {
+ }
+
+ QIODevice *data(const QUrl &)
+ {
+ return 0;
+ }
+
+ bool remove(const QUrl &url)
+ {
+ delete m_buffers.take(url);
+ return m_insertedUrls.removeAll(url) > 0;
+ }
+
+ qint64 cacheSize() const
+ {
+ return 0;
+ }
+
+ QIODevice *prepare(const QNetworkCacheMetaData &metaData)
+ {
+ QBuffer* buffer = new QBuffer;
+ buffer->open(QIODevice::ReadWrite);
+ buffer->setProperty("url", metaData.url());
+ m_buffers.insert(metaData.url(), buffer);
+ return buffer;
+ }
+
+ void insert(QIODevice *buffer)
+ {
+ QUrl url = buffer->property("url").toUrl();
+ m_insertedUrls << url;
+ delete m_buffers.take(url);
+ }
+
+ void clear() { m_insertedUrls.clear(); }
+};
+
class DataReader: public QObject
{
Q_OBJECT
@@ -2663,6 +2722,7 @@ void tst_QNetworkReply::ioGetFromHttpWithCache_data()
QTest::addColumn<QString>("body");
QTest::addColumn<MyMemoryCache::CachedContent>("cachedReply");
QTest::addColumn<int>("cacheMode");
+ QTest::addColumn<QStringList>("extraHttpHeaders");
QTest::addColumn<bool>("loadedFromCache");
QTest::addColumn<bool>("networkUsed");
@@ -2680,11 +2740,11 @@ void tst_QNetworkReply::ioGetFromHttpWithCache_data()
"\r\n";
QTest::newRow("not-cached,always-network")
- << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::AlwaysNetwork) << false << true;
+ << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::AlwaysNetwork) << QStringList() << false << true;
QTest::newRow("not-cached,prefer-network")
- << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::PreferNetwork) << false << true;
+ << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true;
QTest::newRow("not-cached,prefer-cache")
- << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::PreferCache) << false << true;
+ << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::PreferCache) << QStringList() << false << true;
QDateTime present = QDateTime::currentDateTime().toUTC();
QDateTime past = present.addSecs(-3600);
@@ -2706,14 +2766,14 @@ void tst_QNetworkReply::ioGetFromHttpWithCache_data()
content.first.setLastModified(past);
QTest::newRow("expired,200,prefer-network")
- << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferNetwork) << false << true;
+ << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true;
QTest::newRow("expired,200,prefer-cache")
- << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferCache) << false << true;
+ << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << false << true;
QTest::newRow("expired,304,prefer-network")
- << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << true << true;
+ << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << true;
QTest::newRow("expired,304,prefer-cache")
- << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << true << true;
+ << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << true;
//
// Set to not-expired
@@ -2725,20 +2785,20 @@ void tst_QNetworkReply::ioGetFromHttpWithCache_data()
content.first.setExpirationDate(future);
QTest::newRow("not-expired,200,always-network")
- << reply200 << "Reloaded" << content << int(QNetworkRequest::AlwaysNetwork) << false << true;
+ << reply200 << "Reloaded" << content << int(QNetworkRequest::AlwaysNetwork) << QStringList() << false << true;
QTest::newRow("not-expired,200,prefer-network")
- << reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << true << false;
+ << reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << false;
QTest::newRow("not-expired,200,prefer-cache")
- << reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << true << false;
+ << reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << false;
QTest::newRow("not-expired,200,always-cache")
- << reply200 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << true << false;
+ << reply200 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << true << false;
QTest::newRow("not-expired,304,prefer-network")
- << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << true << false;
+ << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << false;
QTest::newRow("not-expired,304,prefer-cache")
- << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << true << false;
+ << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << false;
QTest::newRow("not-expired,304,always-cache")
- << reply304 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << true << false;
+ << reply304 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << true << false;
//
// Set must-revalidate now
@@ -2749,20 +2809,42 @@ void tst_QNetworkReply::ioGetFromHttpWithCache_data()
content.first.setRawHeaders(rawHeaders);
QTest::newRow("must-revalidate,200,always-network")
- << reply200 << "Reloaded" << content << int(QNetworkRequest::AlwaysNetwork) << false << true;
+ << reply200 << "Reloaded" << content << int(QNetworkRequest::AlwaysNetwork) << QStringList() << false << true;
QTest::newRow("must-revalidate,200,prefer-network")
- << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferNetwork) << false << true;
+ << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true;
QTest::newRow("must-revalidate,200,prefer-cache")
- << reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << true << false;
+ << reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << false;
QTest::newRow("must-revalidate,200,always-cache")
- << reply200 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << true << false;
+ << reply200 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << true << false;
QTest::newRow("must-revalidate,304,prefer-network")
- << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << true << true;
+ << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << true;
QTest::newRow("must-revalidate,304,prefer-cache")
- << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << true << false;
+ << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << false;
QTest::newRow("must-revalidate,304,always-cache")
- << reply304 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << true << false;
+ << reply304 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << true << false;
+
+ //
+ // Partial content
+ //
+ rawHeaders.clear();
+ rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1())
+ << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=7200"); // isn't used in cache loading
+ content.first.setRawHeaders(rawHeaders);
+ content.first.setExpirationDate(future);
+
+ QByteArray reply206 =
+ "HTTP/1.0 206\r\n"
+ "Connection: keep-alive\r\n"
+ "Content-Type: text/plain\r\n"
+ "Cache-control: no-cache\r\n"
+ "Content-Range: bytes 2-6/8\r\n"
+ "Content-length: 4\r\n"
+ "\r\n"
+ "load";
+
+ QTest::newRow("partial,dontuse-cache")
+ << reply206 << "load" << content << int(QNetworkRequest::PreferCache) << (QStringList() << "Range" << "bytes=2-6") << false << true;
}
void tst_QNetworkReply::ioGetFromHttpWithCache()
@@ -2784,6 +2866,15 @@ void tst_QNetworkReply::ioGetFromHttpWithCache()
QNetworkRequest request(url);
request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, cacheMode);
request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false);
+
+ QFETCH(QStringList, extraHttpHeaders);
+ QStringListIterator it(extraHttpHeaders);
+ while (it.hasNext()) {
+ QString header = it.next();
+ QString value = it.next();
+ request.setRawHeader(header.toLatin1(), value.toLatin1()); // To latin1? Deal with it!
+ }
+
QNetworkReplyPtr reply = manager.get(request);
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
@@ -5243,6 +5334,39 @@ void tst_QNetworkReply::synchronousRequestSslFailure()
QCOMPARE(sslErrorsSpy.count(), 0);
}
+void tst_QNetworkReply::dontInsertPartialContentIntoTheCache()
+{
+ QByteArray reply206 =
+ "HTTP/1.0 206\r\n"
+ "Connection: keep-alive\r\n"
+ "Content-Type: text/plain\r\n"
+ "Cache-control: no-cache\r\n"
+ "Content-Range: bytes 2-6/8\r\n"
+ "Content-length: 4\r\n"
+ "\r\n"
+ "load";
+
+ MiniHttpServer server(reply206);
+ server.doClose = false;
+
+ MySpyMemoryCache *memoryCache = new MySpyMemoryCache(&manager);
+ manager.setCache(memoryCache);
+
+ QUrl url = "http://localhost:" + QString::number(server.serverPort());
+ QNetworkRequest request(url);
+ request.setRawHeader("Range", "bytes=2-6");
+
+ QNetworkReplyPtr reply = manager.get(request);
+
+ connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
+ QTestEventLoop::instance().enterLoop(10);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QVERIFY(server.totalConnections > 0);
+ QCOMPARE(reply->readAll().constData(), "load");
+ QCOMPARE(memoryCache->m_insertedUrls.count(), 0);
+}
+
// NOTE: This test must be last testcase in tst_qnetworkreply!
void tst_QNetworkReply::parentingRepliesToTheApp()
{
@@ -5252,4 +5376,5 @@ void tst_QNetworkReply::parentingRepliesToTheApp()
}
QTEST_MAIN(tst_QNetworkReply)
+
#include "tst_qnetworkreply.moc"