diff options
author | Shane Kearns <shane.kearns@accenture.com> | 2011-03-25 14:08:28 (GMT) |
---|---|---|
committer | Shane Kearns <shane.kearns@accenture.com> | 2011-03-25 14:08:28 (GMT) |
commit | 12fd077f71a8bc6f865e4e8a4ffe61d5d1b8a504 (patch) | |
tree | ba98e1ff32f288b47b0a05eb0fc293e3c3420889 /tests/auto/qnetworkreply | |
parent | be5e7924ec7bd6cccd626f931f55e2687910ad13 (diff) | |
parent | 116fed06f9ed561befb505d94b6b44dc71bf9e45 (diff) | |
download | Qt-12fd077f71a8bc6f865e4e8a4ffe61d5d1b8a504.zip Qt-12fd077f71a8bc6f865e4e8a4ffe61d5d1b8a504.tar.gz Qt-12fd077f71a8bc6f865e4e8a4ffe61d5d1b8a504.tar.bz2 |
Merge remote branch 'earth/master' into symbian-socket-engine
Conflicts:
src/network/access/qhttpnetworkconnectionchannel.cpp
src/network/socket/qlocalsocket.cpp
src/s60installs/bwins/QtCoreu.def
src/s60installs/bwins/QtGuiu.def
src/s60installs/bwins/QtTestu.def
src/s60installs/eabi/QtCoreu.def
src/s60installs/eabi/QtGuiu.def
Diffstat (limited to 'tests/auto/qnetworkreply')
-rw-r--r-- | tests/auto/qnetworkreply/image1.jpg | bin | 0 -> 1045459 bytes | |||
-rw-r--r-- | tests/auto/qnetworkreply/image2.jpg | bin | 0 -> 879218 bytes | |||
-rw-r--r-- | tests/auto/qnetworkreply/image3.jpg | bin | 0 -> 887729 bytes | |||
-rw-r--r-- | tests/auto/qnetworkreply/tst_qnetworkreply.cpp | 556 |
4 files changed, 527 insertions, 29 deletions
diff --git a/tests/auto/qnetworkreply/image1.jpg b/tests/auto/qnetworkreply/image1.jpg Binary files differnew file mode 100644 index 0000000..dba31c1 --- /dev/null +++ b/tests/auto/qnetworkreply/image1.jpg diff --git a/tests/auto/qnetworkreply/image2.jpg b/tests/auto/qnetworkreply/image2.jpg Binary files differnew file mode 100644 index 0000000..72936e2 --- /dev/null +++ b/tests/auto/qnetworkreply/image2.jpg diff --git a/tests/auto/qnetworkreply/image3.jpg b/tests/auto/qnetworkreply/image3.jpg Binary files differnew file mode 100644 index 0000000..cede519 --- /dev/null +++ b/tests/auto/qnetworkreply/image3.jpg diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index a5f1577..4b8dc3b 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -61,6 +61,8 @@ #include <QtNetwork/qnetworkrequest.h> #include <QtNetwork/qnetworkreply.h> #include <QtNetwork/qnetworkcookie.h> +#include <QtNetwork/QHttpPart> +#include <QtNetwork/QHttpMultiPart> #ifndef QT_NO_OPENSSL #include <QtNetwork/qsslerror.h> #include <QtNetwork/qsslconfiguration.h> @@ -89,6 +91,8 @@ Q_DECLARE_METATYPE(QNetworkProxyQuery) Q_DECLARE_METATYPE(QList<QNetworkProxy>) Q_DECLARE_METATYPE(QNetworkReply::NetworkError) Q_DECLARE_METATYPE(QBuffer*) +Q_DECLARE_METATYPE(QHttpMultiPart *) +Q_DECLARE_METATYPE(QList<QFile*>) // for multiparts class QNetworkReplyPtr: public QSharedPointer<QNetworkReply> { @@ -150,6 +154,8 @@ public: ~tst_QNetworkReply(); QString runSimpleRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QNetworkReplyPtr &reply, const QByteArray &data = QByteArray()); + QString runMultipartRequest(const QNetworkRequest &request, QNetworkReplyPtr &reply, + QHttpMultiPart *multiPart, const QByteArray &verb); QString runCustomRequest(const QNetworkRequest &request, QNetworkReplyPtr &reply, const QByteArray &verb, QIODevice *data); @@ -196,10 +202,14 @@ private Q_SLOTS: void putToHttp(); void putToHttpSynchronous_data(); void putToHttpSynchronous(); + void putToHttpMultipart_data(); + void putToHttpMultipart(); void postToHttp_data(); void postToHttp(); void postToHttpSynchronous_data(); void postToHttpSynchronous(); + void postToHttpMultipart_data(); + void postToHttpMultipart(); void deleteFromHttp_data(); void deleteFromHttp(); void putGetDeleteGetFromHttp_data(); @@ -348,6 +358,8 @@ private Q_SLOTS: void qtbug15311doubleContentLength(); + void qtbug18232gzipContentLengthZero(); + void synchronousRequest_data(); void synchronousRequest(); #ifndef QT_NO_OPENSSL @@ -356,6 +368,8 @@ private Q_SLOTS: void httpAbort(); + void dontInsertPartialContentIntoTheCache(); + // NOTE: This test must be last! void parentingRepliesToTheApp(); }; @@ -516,7 +530,6 @@ public slots: if (doClose && client->bytesToWrite() == 0) { client->disconnectFromHost(); disconnect(client, 0, this, 0); - client = 0; } } @@ -613,6 +626,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 @@ -993,6 +1063,7 @@ tst_QNetworkReply::tst_QNetworkReply() #ifndef QT_NO_OPENSSL qRegisterMetaType<QList<QSslError> >(); #endif + qRegisterMetaType<QNetworkReply::NetworkError>(); Q_SET_DEFAULT_IAP @@ -1054,6 +1125,38 @@ void tst_QNetworkReply::storeSslConfiguration() } #endif +QString tst_QNetworkReply::runMultipartRequest(const QNetworkRequest &request, + QNetworkReplyPtr &reply, + QHttpMultiPart *multiPart, + const QByteArray &verb) +{ + if (verb == "POST") + reply = manager.post(request, multiPart); + else + reply = manager.put(request, multiPart); + + // the code below is copied from tst_QNetworkReply::runSimpleRequest, see below + reply->setParent(this); + connect(reply, SIGNAL(finished()), SLOT(finished())); + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError())); + multiPart->setParent(reply); + + returnCode = Timeout; + loop = new QEventLoop; + QTimer::singleShot(25000, loop, SLOT(quit())); + int code = returnCode == Timeout ? loop->exec() : returnCode; + delete loop; + loop = 0; + + switch (code) { + case Failure: + return "Request failed: " + reply->errorString(); + case Timeout: + return "Network timeout"; + } + return QString(); +} + QString tst_QNetworkReply::runSimpleRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QNetworkReplyPtr &reply, @@ -1817,6 +1920,307 @@ void tst_QNetworkReply::postToHttpSynchronous() QCOMPARE(uploadedData, md5sum.toHex()); } +void tst_QNetworkReply::postToHttpMultipart_data() +{ + QTest::addColumn<QUrl>("url"); + QTest::addColumn<QHttpMultiPart *>("multiPart"); + QTest::addColumn<QByteArray>("expectedReplyData"); + QTest::addColumn<QByteArray>("contentType"); + + QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/multipart.cgi"); + QByteArray expectedData; + + + // empty parts + + QHttpMultiPart *emptyMultiPart = new QHttpMultiPart; + QTest::newRow("empty") << url << emptyMultiPart << expectedData << QByteArray("mixed"); + + QHttpMultiPart *emptyRelatedMultiPart = new QHttpMultiPart; + emptyRelatedMultiPart->setContentType(QHttpMultiPart::RelatedType); + QTest::newRow("empty-related") << url << emptyRelatedMultiPart << expectedData << QByteArray("related"); + + QHttpMultiPart *emptyAlternativeMultiPart = new QHttpMultiPart; + emptyAlternativeMultiPart->setContentType(QHttpMultiPart::AlternativeType); + QTest::newRow("empty-alternative") << url << emptyAlternativeMultiPart << expectedData << QByteArray("alternative"); + + + // text-only parts + + QHttpPart textPart; + textPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain")); + textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text\"")); + textPart.setBody("7 bytes"); + QHttpMultiPart *multiPart1 = new QHttpMultiPart; + multiPart1->setContentType(QHttpMultiPart::FormDataType); + multiPart1->append(textPart); + expectedData = "key: text, value: 7 bytes\n"; + QTest::newRow("text") << url << multiPart1 << expectedData << QByteArray("form-data"); + + QHttpMultiPart *customMultiPart = new QHttpMultiPart; + customMultiPart->append(textPart); + expectedData = "header: Content-Type, value: 'text/plain'\n" + "header: Content-Disposition, value: 'form-data; name=\"text\"'\n" + "content: 7 bytes\n" + "\n"; + QTest::newRow("text-custom") << url << customMultiPart << expectedData << QByteArray("custom"); + + QHttpPart textPart2; + textPart2.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain")); + textPart2.setRawHeader("myRawHeader", "myValue"); + textPart2.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text2\"")); + textPart2.setBody("some more bytes"); + textPart2.setBodyDevice((QIODevice *) 1); // test whether setting and unsetting of the device works + textPart2.setBodyDevice(0); + QHttpMultiPart *multiPart2 = new QHttpMultiPart; + multiPart2->setContentType(QHttpMultiPart::FormDataType); + multiPart2->append(textPart); + multiPart2->append(textPart2); + expectedData = "key: text2, value: some more bytes\n" + "key: text, value: 7 bytes\n"; + QTest::newRow("text-text") << url << multiPart2 << expectedData << QByteArray("form-data"); + + + QHttpPart textPart3; + textPart3.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain")); + textPart3.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text3\"")); + textPart3.setRawHeader("Content-Location", "http://my.test.location.tld"); + textPart3.setBody("even more bytes"); + QHttpMultiPart *multiPart3 = new QHttpMultiPart; + multiPart3->setContentType(QHttpMultiPart::AlternativeType); + multiPart3->append(textPart); + multiPart3->append(textPart2); + multiPart3->append(textPart3); + expectedData = "header: Content-Type, value: 'text/plain'\n" + "header: Content-Disposition, value: 'form-data; name=\"text\"'\n" + "content: 7 bytes\n" + "\n" + "header: Content-Type, value: 'text/plain'\n" + "header: myRawHeader, value: 'myValue'\n" + "header: Content-Disposition, value: 'form-data; name=\"text2\"'\n" + "content: some more bytes\n" + "\n" + "header: Content-Type, value: 'text/plain'\n" + "header: Content-Disposition, value: 'form-data; name=\"text3\"'\n" + "header: Content-Location, value: 'http://my.test.location.tld'\n" + "content: even more bytes\n\n"; + QTest::newRow("text-text-text") << url << multiPart3 << expectedData << QByteArray("alternative"); + + + + // text and image parts + + QHttpPart imagePart11; + imagePart11.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg")); + imagePart11.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage\"")); + imagePart11.setRawHeader("Content-Location", "http://my.test.location.tld"); + imagePart11.setRawHeader("Content-ID", "my@id.tld"); + QFile *file11 = new QFile(SRCDIR "/image1.jpg"); + file11->open(QIODevice::ReadOnly); + imagePart11.setBodyDevice(file11); + QHttpMultiPart *imageMultiPart1 = new QHttpMultiPart(QHttpMultiPart::FormDataType); + imageMultiPart1->append(imagePart11); + file11->setParent(imageMultiPart1); + expectedData = "key: testImage, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"; // md5 sum of file + QTest::newRow("image") << url << imageMultiPart1 << expectedData << QByteArray("form-data"); + + QHttpPart imagePart21; + imagePart21.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg")); + imagePart21.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage1\"")); + imagePart21.setRawHeader("Content-Location", "http://my.test.location.tld"); + imagePart21.setRawHeader("Content-ID", "my@id.tld"); + QFile *file21 = new QFile(SRCDIR "/image1.jpg"); + file21->open(QIODevice::ReadOnly); + imagePart21.setBodyDevice(file21); + QHttpMultiPart *imageMultiPart2 = new QHttpMultiPart(); + imageMultiPart2->setContentType(QHttpMultiPart::FormDataType); + imageMultiPart2->append(textPart); + imageMultiPart2->append(imagePart21); + file21->setParent(imageMultiPart2); + QHttpPart imagePart22; + imagePart22.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg")); + imagePart22.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage2\"")); + QFile *file22 = new QFile(SRCDIR "/image2.jpg"); + file22->open(QIODevice::ReadOnly); + imagePart22.setBodyDevice(file22); + imageMultiPart2->append(imagePart22); + file22->setParent(imageMultiPart2); + expectedData = "key: testImage1, value: 87ef3bb319b004ba9e5e9c9fa713776e\n" + "key: text, value: 7 bytes\n" + "key: testImage2, value: 483761b893f7fb1bd2414344cd1f3dfb\n"; + QTest::newRow("text-image-image") << url << imageMultiPart2 << expectedData << QByteArray("form-data"); + + + QHttpPart imagePart31; + imagePart31.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg")); + imagePart31.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage1\"")); + imagePart31.setRawHeader("Content-Location", "http://my.test.location.tld"); + imagePart31.setRawHeader("Content-ID", "my@id.tld"); + QFile *file31 = new QFile(SRCDIR "/image1.jpg"); + file31->open(QIODevice::ReadOnly); + imagePart31.setBodyDevice(file31); + QHttpMultiPart *imageMultiPart3 = new QHttpMultiPart(QHttpMultiPart::FormDataType); + imageMultiPart3->append(imagePart31); + file31->setParent(imageMultiPart3); + QHttpPart imagePart32; + imagePart32.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg")); + imagePart32.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage2\"")); + QFile *file32 = new QFile(SRCDIR "/image2.jpg"); + file32->open(QIODevice::ReadOnly); + imagePart32.setBodyDevice(file31); // check that resetting works + imagePart32.setBodyDevice(file32); + imageMultiPart3->append(imagePart32); + file32->setParent(imageMultiPart3); + QHttpPart imagePart33; + imagePart33.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg")); + imagePart33.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage3\"")); + QFile *file33 = new QFile(SRCDIR "/image3.jpg"); + file33->open(QIODevice::ReadOnly); + imagePart33.setBodyDevice(file33); + imageMultiPart3->append(imagePart33); + file33->setParent(imageMultiPart3); + expectedData = "key: testImage1, value: 87ef3bb319b004ba9e5e9c9fa713776e\n" + "key: testImage2, value: 483761b893f7fb1bd2414344cd1f3dfb\n" + "key: testImage3, value: ab0eb6fd4fcf8b4436254870b4513033\n"; + QTest::newRow("3-images") << url << imageMultiPart3 << expectedData << QByteArray("form-data"); + + + // note: nesting multiparts is not working currently; for that, the outputDevice would need to be public + +// QHttpPart imagePart41; +// imagePart41.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg")); +// QFile *file41 = new QFile(SRCDIR "/image1.jpg"); +// file41->open(QIODevice::ReadOnly); +// imagePart41.setBodyDevice(file41); +// +// QHttpMultiPart *innerMultiPart = new QHttpMultiPart(); +// innerMultiPart->setContentType(QHttpMultiPart::FormDataType); +// textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant()); +// innerMultiPart->append(textPart); +// innerMultiPart->append(imagePart41); +// textPart2.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant()); +// innerMultiPart->append(textPart2); +// +// QHttpPart nestedPart; +// nestedPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"nestedMessage")); +// nestedPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("multipart/alternative; boundary=\"" + innerMultiPart->boundary() + "\"")); +// innerMultiPart->outputDevice()->open(QIODevice::ReadOnly); +// nestedPart.setBodyDevice(innerMultiPart->outputDevice()); +// +// QHttpMultiPart *outerMultiPart = new QHttpMultiPart; +// outerMultiPart->setContentType(QHttpMultiPart::FormDataType); +// outerMultiPart->append(textPart); +// outerMultiPart->append(nestedPart); +// outerMultiPart->append(textPart2); +// expectedData = "nothing"; // the CGI.pm module running on the test server does not understand nested multiparts +// openFiles.clear(); +// openFiles << file41; +// QTest::newRow("nested") << url << outerMultiPart << expectedData << openFiles; + + + // test setting large chunks of content with a byte array instead of a device (DISCOURAGED because of high memory consumption, + // but we need to test that the behavior is correct) + QHttpPart imagePart51; + imagePart51.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg")); + imagePart51.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage\"")); + QFile *file51 = new QFile(SRCDIR "/image1.jpg"); + file51->open(QIODevice::ReadOnly); + QByteArray imageData = file51->readAll(); + file51->close(); + delete file51; + imagePart51.setBody("7 bytes"); // check that resetting works + imagePart51.setBody(imageData); + QHttpMultiPart *imageMultiPart5 = new QHttpMultiPart; + imageMultiPart5->setContentType(QHttpMultiPart::FormDataType); + imageMultiPart5->append(imagePart51); + expectedData = "key: testImage, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"; // md5 sum of file + QTest::newRow("image-as-content") << url << imageMultiPart5 << expectedData << QByteArray("form-data"); +} + +void tst_QNetworkReply::postToHttpMultipart() +{ + QFETCH(QUrl, url); + + static QSet<QByteArray> boundaries; + + QNetworkRequest request(url); + QNetworkReplyPtr reply; + + QFETCH(QHttpMultiPart *, multiPart); + QFETCH(QByteArray, expectedReplyData); + QFETCH(QByteArray, contentType); + + // hack for testing the setting of the content-type header by hand: + if (contentType == "custom") { + QByteArray contentType("multipart/custom; boundary=\"" + multiPart->boundary() + "\""); + request.setHeader(QNetworkRequest::ContentTypeHeader, contentType); + } + + QVERIFY2(! boundaries.contains(multiPart->boundary()), "boundary '" + multiPart->boundary() + "' has been created twice"); + boundaries.insert(multiPart->boundary()); + + RUN_REQUEST(runMultipartRequest(request, reply, multiPart, "POST")); + multiPart->deleteLater(); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok + + QVERIFY(multiPart->boundary().count() > 20); // check that there is randomness after the "boundary_.oOo._" string + QVERIFY(multiPart->boundary().count() < 70); + QByteArray replyData = reply->readAll(); + + expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n"); +// QEXPECT_FAIL("nested", "the server does not understand nested multipart messages", Continue); // see above + QCOMPARE(replyData, expectedReplyData); +} + +void tst_QNetworkReply::putToHttpMultipart_data() +{ + postToHttpMultipart_data(); +} + +void tst_QNetworkReply::putToHttpMultipart() +{ + QSKIP("test server script cannot handle PUT data yet", SkipAll); + QFETCH(QUrl, url); + + static QSet<QByteArray> boundaries; + + QNetworkRequest request(url); + QNetworkReplyPtr reply; + + QFETCH(QHttpMultiPart *, multiPart); + QFETCH(QByteArray, expectedReplyData); + QFETCH(QByteArray, contentType); + + // hack for testing the setting of the content-type header by hand: + if (contentType == "custom") { + QByteArray contentType("multipart/custom; boundary=\"" + multiPart->boundary() + "\""); + request.setHeader(QNetworkRequest::ContentTypeHeader, contentType); + } + + QVERIFY2(! boundaries.contains(multiPart->boundary()), "boundary '" + multiPart->boundary() + "' has been created twice"); + boundaries.insert(multiPart->boundary()); + + RUN_REQUEST(runMultipartRequest(request, reply, multiPart, "PUT")); + multiPart->deleteLater(); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok + + QVERIFY(multiPart->boundary().count() > 20); // check that there is randomness after the "boundary_.oOo._" string + QVERIFY(multiPart->boundary().count() < 70); + QByteArray replyData = reply->readAll(); + + expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n"); +// QEXPECT_FAIL("nested", "the server does not understand nested multipart messages", Continue); // see above + QCOMPARE(replyData, expectedReplyData); +} + void tst_QNetworkReply::deleteFromHttp_data() { QTest::addColumn<QUrl>("url"); @@ -2647,6 +3051,9 @@ void tst_QNetworkReply::ioGetFromHttpBrokenServer_data() QTest::newRow("justHalfStatus+disconnect") << QByteArray("HTTP/1.1") << true; QTest::newRow("justStatus+disconnect") << QByteArray("HTTP/1.1 200 OK\r\n") << true; QTest::newRow("justStatusAndHalfHeaders+disconnect") << QByteArray("HTTP/1.1 200 OK\r\nContent-L") << true; + + QTest::newRow("halfContent+disconnect") << QByteArray("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nAB") << true; + } void tst_QNetworkReply::ioGetFromHttpBrokenServer() @@ -2658,29 +3065,35 @@ void tst_QNetworkReply::ioGetFromHttpBrokenServer() QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); QNetworkReplyPtr reply = manager.get(request); + QSignalSpy spy(reply, SIGNAL(error(QNetworkReply::NetworkError))); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); QTestEventLoop::instance().enterLoop(10); QVERIFY(!QTestEventLoop::instance().timeout()); QCOMPARE(reply->url(), request.url()); + QCOMPARE(spy.count(), 1); QVERIFY(reply->error() != QNetworkReply::NoError); } void tst_QNetworkReply::ioGetFromHttpStatus100_data() { QTest::addColumn<QByteArray>("dataToSend"); - QTest::newRow("normal") << QByteArray("HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); - QTest::newRow("minimal") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); - QTest::newRow("minimal2") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 200 OK\r\n\r\n"); - QTest::newRow("minimal3") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 200 OK\n\n"); - QTest::newRow("with_headers") << QByteArray("HTTP/1.1 100 Continue\r\nBla: x\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); - QTest::newRow("with_headers2") << QByteArray("HTTP/1.1 100 Continue\nBla: x\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + QTest::addColumn<int>("statusCode"); + QTest::newRow("normal") << QByteArray("HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200; + QTest::newRow("minimal") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200; + QTest::newRow("minimal2") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 200 OK\r\n\r\n") << 200; + QTest::newRow("minimal3") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 200 OK\n\n") << 200; + QTest::newRow("minimal+404") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 204 No Content\r\n\r\n") << 204; + QTest::newRow("with_headers") << QByteArray("HTTP/1.1 100 Continue\r\nBla: x\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200; + QTest::newRow("with_headers2") << QByteArray("HTTP/1.1 100 Continue\nBla: x\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200; } void tst_QNetworkReply::ioGetFromHttpStatus100() { QFETCH(QByteArray, dataToSend); + QFETCH(int, statusCode); MiniHttpServer server(dataToSend); server.doClose = true; @@ -2693,7 +3106,7 @@ void tst_QNetworkReply::ioGetFromHttpStatus100() QCOMPARE(reply->url(), request.url()); QCOMPARE(reply->error(), QNetworkReply::NoError); - QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), statusCode); QVERIFY(reply->rawHeader("bla").isNull()); } @@ -2728,6 +3141,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"); @@ -2745,11 +3159,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); @@ -2771,14 +3185,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 @@ -2790,20 +3204,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 @@ -2814,20 +3228,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() @@ -2849,6 +3285,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())); @@ -5500,6 +5945,25 @@ void tst_QNetworkReply::qtbug15311doubleContentLength() QCOMPARE(reply->readAll(), QByteArray("ABC")); } +void tst_QNetworkReply::qtbug18232gzipContentLengthZero() +{ + QByteArray response("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: 0\r\n\r\n"); + MiniHttpServer server(response); + server.doClose = true; + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + QNetworkReplyPtr reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(reply->isFinished()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->size(), qint64(0)); + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(0)); + QCOMPARE(reply->readAll(), QByteArray()); +} + void tst_QNetworkReply::synchronousRequest_data() { QTest::addColumn<QUrl>("url"); @@ -5631,6 +6095,39 @@ void tst_QNetworkReply::httpAbort() // It must not crash either. } +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() { @@ -5640,4 +6137,5 @@ void tst_QNetworkReply::parentingRepliesToTheApp() } QTEST_MAIN(tst_QNetworkReply) + #include "tst_qnetworkreply.moc" |