summaryrefslogtreecommitdiffstats
path: root/tests/auto/qnetworkreply/tst_qnetworkreply.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qnetworkreply/tst_qnetworkreply.cpp')
-rw-r--r--tests/auto/qnetworkreply/tst_qnetworkreply.cpp521
1 files changed, 492 insertions, 29 deletions
diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp
index 2c799511bb..f509ceaad6 100644
--- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp
+++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp
@@ -47,6 +47,7 @@
#include <QtCore/QEventLoop>
#include <QtCore/QFile>
#include <QtCore/QSharedPointer>
+#include <QtCore/QScopedPointer>
#include <QtCore/QTemporaryFile>
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
@@ -60,10 +61,17 @@
#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>
#endif
+#ifndef QT_NO_BEARERMANAGEMENT
+#include <QtNetwork/qnetworkconfigmanager.h>
+#include <QtNetwork/qnetworkconfiguration.h>
+#include <QtNetwork/qnetworksession.h>
+#endif
#include <time.h>
@@ -83,6 +91,11 @@ 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
+#ifndef QT_NO_OPENSSL
+Q_DECLARE_METATYPE(QSslConfiguration)
+#endif
class QNetworkReplyPtr: public QSharedPointer<QNetworkReply>
{
@@ -133,12 +146,19 @@ class tst_QNetworkReply: public QObject
QSslConfiguration storedSslConfiguration;
QList<QSslError> storedExpectedSslErrors;
#endif
+#ifndef QT_NO_BEARERMANAGEMENT
+ QNetworkConfigurationManager *netConfMan;
+ QNetworkConfiguration networkConfiguration;
+ QScopedPointer<QNetworkSession> networkSession;
+#endif
public:
tst_QNetworkReply();
~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);
@@ -185,10 +205,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();
@@ -309,6 +333,8 @@ private Q_SLOTS:
void ignoreSslErrorsList();
void ignoreSslErrorsListWithSlot_data();
void ignoreSslErrorsListWithSlot();
+ void sslConfiguration_data();
+ void sslConfiguration();
#endif
void getAndThenDeleteObject_data();
@@ -337,6 +363,8 @@ private Q_SLOTS:
void qtbug15311doubleContentLength();
+ void qtbug18232gzipContentLengthZero();
+
void synchronousRequest_data();
void synchronousRequest();
#ifndef QT_NO_OPENSSL
@@ -416,16 +444,23 @@ public:
QTcpSocket *client; // always the last one that was received
QByteArray dataToTransmit;
QByteArray receivedData;
+ QSemaphore ready;
bool doClose;
bool doSsl;
bool multiple;
int totalConnections;
- MiniHttpServer(const QByteArray &data, bool ssl = false)
+ MiniHttpServer(const QByteArray &data, bool ssl = false, QThread *thread = 0)
: client(0), dataToTransmit(data), doClose(true), doSsl(ssl),
multiple(false), totalConnections(0)
{
listen();
+ if (thread) {
+ connect(thread, SIGNAL(started()), this, SLOT(threadStartedSlot()));
+ moveToThread(thread);
+ thread->start();
+ ready.acquire();
+ }
}
protected:
@@ -502,6 +537,11 @@ public slots:
disconnect(client, 0, this, 0);
}
}
+
+ void threadStartedSlot()
+ {
+ ready.release();
+ }
};
class MyCookieJar: public QNetworkCookieJar
@@ -1090,6 +1130,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,
@@ -1197,6 +1269,18 @@ void tst_QNetworkReply::initTestCase()
#endif
QDir::setSearchPaths("srcdir", QStringList() << SRCDIR);
+#ifndef QT_NO_OPENSSL
+ QSslSocket::defaultCaCertificates(); //preload certificates
+#endif
+#ifndef QT_NO_BEARERMANAGEMENT
+ netConfMan = new QNetworkConfigurationManager(this);
+ networkConfiguration = netConfMan->defaultConfiguration();
+ networkSession.reset(new QNetworkSession(networkConfiguration));
+ if (!networkSession->isOpen()) {
+ networkSession->open();
+ QVERIFY(networkSession->waitForOpened(30000));
+ }
+#endif
}
void tst_QNetworkReply::cleanupTestCase()
@@ -1204,6 +1288,9 @@ void tst_QNetworkReply::cleanupTestCase()
#if !defined Q_OS_WIN
QFile::remove(wronlyFileName);
#endif
+ if (networkSession && networkSession->isOpen()) {
+ networkSession->close();
+ }
}
void tst_QNetworkReply::init()
@@ -1563,7 +1650,7 @@ void tst_QNetworkReply::getErrors()
QNetworkRequest request(url);
#if defined(Q_OS_WIN) || defined (Q_OS_SYMBIAN)
- if (qstrcmp(QTest::currentDataTag(), "empty-scheme-host") == 0)
+ if (qstrcmp(QTest::currentDataTag(), "empty-scheme-host") == 0 && QFileInfo(url).isAbsolute())
QTest::ignoreMessage(QtWarningMsg, "QNetworkAccessFileBackendFactory: URL has no schema set, use file:// for files");
#endif
@@ -1582,7 +1669,8 @@ void tst_QNetworkReply::getErrors()
QFETCH(int, error);
#if defined(Q_OS_WIN) || defined (Q_OS_SYMBIAN)
- QEXPECT_FAIL("empty-scheme-host", "this is expected to fail on Windows and Symbian, QTBUG-17731", Abort);
+ if (QFileInfo(url).isAbsolute())
+ QEXPECT_FAIL("empty-scheme-host", "this is expected to fail on Windows and Symbian, QTBUG-17731", Abort);
#endif
QEXPECT_FAIL("ftp-is-dir", "QFtp cannot provide enough detail", Abort);
// the line below is not necessary
@@ -1788,6 +1876,7 @@ void tst_QNetworkReply::postToHttp()
QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
QNetworkRequest request(url);
+ request.setRawHeader("Content-Type", "application/octet-stream");
QNetworkReplyPtr reply;
QFETCH(QByteArray, data);
@@ -1814,6 +1903,7 @@ void tst_QNetworkReply::postToHttpSynchronous()
QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
QNetworkRequest request(url);
+ request.setRawHeader("Content-Type", "application/octet-stream");
request.setAttribute(
QNetworkRequest::SynchronousRequestAttribute,
@@ -1835,6 +1925,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");
@@ -3272,8 +3663,7 @@ void tst_QNetworkReply::ioPutToFileFromLocalSocket()
QString socketname = "networkreplytest";
QLocalServer server;
if (!server.listen(socketname)) {
- if (QFile::exists(server.fullServerName()))
- QFile::remove(server.fullServerName());
+ QLocalServer::removeServer(socketname);
QVERIFY(server.listen(socketname));
}
QLocalSocket active;
@@ -3318,7 +3708,7 @@ void tst_QNetworkReply::ioPutToFileFromProcess()
{
#if defined(Q_OS_WINCE) || defined (Q_OS_SYMBIAN)
QSKIP("Currently no stdin/out supported for Windows CE / Symbian OS", SkipAll);
-#endif
+#else
#ifdef Q_OS_WIN
if (qstrcmp(QTest::currentDataTag(), "small") == 0)
@@ -3356,6 +3746,7 @@ void tst_QNetworkReply::ioPutToFileFromProcess()
QByteArray contents = file.readAll();
QCOMPARE(contents, data);
#endif
+#endif
}
void tst_QNetworkReply::ioPutToFtpFromFile_data()
@@ -3469,6 +3860,8 @@ void tst_QNetworkReply::ioPostToHttpFromFile()
QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
QNetworkRequest request(url);
+ request.setRawHeader("Content-Type", "application/octet-stream");
+
QNetworkReplyPtr reply = manager.post(request, &sourceFile);
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
@@ -3545,8 +3938,10 @@ void tst_QNetworkReply::ioPostToHttpFromSocket()
socketpair.endPoints[0]->write(data);
QNetworkRequest request(url);
+ request.setRawHeader("Content-Type", "application/octet-stream");
+
manager.setProxy(proxy);
- QNetworkReplyPtr reply = manager.post(QNetworkRequest(url), socketpair.endPoints[1]);
+ QNetworkReplyPtr reply = manager.post(request, socketpair.endPoints[1]);
socketpair.endPoints[0]->close();
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
@@ -3619,6 +4014,7 @@ void tst_QNetworkReply::ioPostToHttpFromSocketSynchronous()
QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
QNetworkRequest request(url);
+ request.setRawHeader("Content-Type", "application/octet-stream");
request.setAttribute(
QNetworkRequest::SynchronousRequestAttribute,
true);
@@ -3648,7 +4044,8 @@ void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileToEnd()
QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
QNetworkRequest request(url);
- QNetworkReplyPtr reply = manager.post(QNetworkRequest(url), &sourceFile);
+ request.setRawHeader("Content-Type", "application/octet-stream");
+ QNetworkReplyPtr reply = manager.post(request, &sourceFile);
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
@@ -3674,6 +4071,7 @@ void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileFiveBytes()
QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
QNetworkRequest request(url);
+ request.setRawHeader("Content-Type", "application/octet-stream");
// only send 5 bytes
request.setHeader(QNetworkRequest::ContentLengthHeader, 5);
QVERIFY(request.header(QNetworkRequest::ContentLengthHeader).isValid());
@@ -3734,6 +4132,7 @@ void tst_QNetworkReply::ioPostToHttpNoBufferFlag()
QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
QNetworkRequest request(url);
+ request.setRawHeader("Content-Type", "application/octet-stream");
// disallow buffering
request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, true);
request.setHeader(QNetworkRequest::ContentLengthHeader, data.size());
@@ -3796,6 +4195,7 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress()
// create the request
QUrl url = QUrl(QString("https://127.0.0.1:%1/").arg(server.serverPort()));
QNetworkRequest request(url);
+ request.setRawHeader("Content-Type", "application/octet-stream");
QNetworkReplyPtr reply = manager.post(request, &sourceFile);
QSignalSpy spy(reply, SIGNAL(uploadProgress(qint64,qint64)));
connect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
@@ -3814,14 +4214,8 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress()
// some progress should have been made
QVERIFY(!spy.isEmpty());
QList<QVariant> args = spy.last();
- qDebug() << "tst_QNetworkReply::ioPostToHttpsUploadProgress"
- << args.at(0).toLongLong()
- << sourceFile.size()
- << spy.size();
QVERIFY(args.at(0).toLongLong() > 0);
- // FIXME this is where it messes up
- QEXPECT_FAIL("", "Either the readBufferSize of QSslSocket is broken or we do upload too much. Hm.", Abort);
QVERIFY(args.at(0).toLongLong() != sourceFile.size());
incomingSocket->setReadBufferSize(32*1024);
@@ -3870,6 +4264,7 @@ void tst_QNetworkReply::ioGetFromBuiltinHttp_data()
void tst_QNetworkReply::ioGetFromBuiltinHttp()
{
+ QSKIP("Limiting is broken right now, check QTBUG-15065", SkipAll);
QFETCH(bool, https);
QFETCH(int, bufferSize);
@@ -3908,7 +4303,7 @@ void tst_QNetworkReply::ioGetFromBuiltinHttp()
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
QTime loopTime;
loopTime.start();
- QTestEventLoop::instance().enterLoop(11);
+ QTestEventLoop::instance().enterLoop(30);
const int elapsedTime = loopTime.elapsed();
server.wait();
reader.wrapUp();
@@ -3940,10 +4335,9 @@ void tst_QNetworkReply::ioGetFromBuiltinHttp()
const int minRate = rate * 1024 * (100-allowedDeviation) / 100;
const int maxRate = rate * 1024 * (100+allowedDeviation) / 100;
qDebug() << minRate << "<="<< server.transferRate << "<=" << maxRate << "?";
- QVERIFY(server.transferRate >= minRate);
QEXPECT_FAIL("http+limited", "Limiting is broken right now, check QTBUG-15065", Continue);
QEXPECT_FAIL("https+limited", "Limiting is broken right now, check QTBUG-15065", Continue);
- QVERIFY(server.transferRate <= maxRate);
+ QVERIFY(server.transferRate >= minRate && server.transferRate <= maxRate);
}
}
@@ -4018,6 +4412,7 @@ void tst_QNetworkReply::ioPostToHttpEmptyUploadProgress()
// create the request
QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort()));
QNetworkRequest request(url);
+ request.setRawHeader("Content-Type", "application/octet-stream");
QNetworkReplyPtr reply = manager.post(request, &buffer);
QSignalSpy spy(reply, SIGNAL(uploadProgress(qint64,qint64)));
connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
@@ -4364,6 +4759,7 @@ void tst_QNetworkReply::receiveCookiesFromHttp()
QByteArray data = cookieString.toLatin1() + '\n';
QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/set-cookie.cgi");
QNetworkRequest request(url);
+ request.setRawHeader("Content-Type", "application/octet-stream");
QNetworkReplyPtr reply;
RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
@@ -4391,7 +4787,7 @@ void tst_QNetworkReply::receiveCookiesFromHttpSynchronous()
QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/set-cookie.cgi");
QNetworkRequest request(url);
-
+ request.setRawHeader("Content-Type", "application/octet-stream");
request.setAttribute(
QNetworkRequest::SynchronousRequestAttribute,
true);
@@ -4607,6 +5003,26 @@ void tst_QNetworkReply::httpProxyCommandsSynchronous_data()
httpProxyCommands_data();
}
+struct QThreadCleanup
+{
+ static inline void cleanup(QThread *thread)
+ {
+ thread->quit();
+ if (thread->wait(3000))
+ delete thread;
+ else
+ qWarning("thread hung, leaking memory so test can finish");
+ }
+};
+
+struct QDeleteLaterCleanup
+{
+ static inline void cleanup(QObject *o)
+ {
+ o->deleteLater();
+ }
+};
+
void tst_QNetworkReply::httpProxyCommandsSynchronous()
{
QFETCH(QUrl, url);
@@ -4616,11 +5032,9 @@ void tst_QNetworkReply::httpProxyCommandsSynchronous()
// when using synchronous commands, we need a different event loop for
// the server thread, because the client is never returning to the
// event loop
- MiniHttpServer proxyServer(responseToSend);
- QThread serverThread;
- proxyServer.moveToThread(&serverThread);
- serverThread.start();
- QNetworkProxy proxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer.serverPort());
+ QScopedPointer<QThread, QThreadCleanup> serverThread(new QThread);
+ QScopedPointer<MiniHttpServer, QDeleteLaterCleanup> proxyServer(new MiniHttpServer(responseToSend, false, serverThread.data()));
+ QNetworkProxy proxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer->serverPort());
manager.setProxy(proxy);
QNetworkRequest request(url);
@@ -4633,8 +5047,6 @@ void tst_QNetworkReply::httpProxyCommandsSynchronous()
QNetworkReplyPtr reply = manager.get(request);
QVERIFY(reply->isFinished()); // synchronous
manager.setProxy(QNetworkProxy());
- serverThread.quit();
- serverThread.wait(3000);
//qDebug() << reply->error() << reply->errorString();
@@ -4642,7 +5054,7 @@ void tst_QNetworkReply::httpProxyCommandsSynchronous()
// especially since it won't succeed in the HTTPS case
// so just check that the command was correct
- QString receivedHeader = proxyServer.receivedData.left(expectedCommand.length());
+ QString receivedHeader = proxyServer->receivedData.left(expectedCommand.length());
QCOMPARE(receivedHeader, expectedCommand);
}
@@ -5025,6 +5437,37 @@ void tst_QNetworkReply::ignoreSslErrorsListWithSlot()
QCOMPARE(reply->error(), expectedNetworkError);
}
+void tst_QNetworkReply::sslConfiguration_data()
+{
+ QTest::addColumn<QSslConfiguration>("configuration");
+ QTest::addColumn<bool>("works");
+
+ QTest::newRow("empty") << QSslConfiguration() << false;
+ QSslConfiguration conf = QSslConfiguration::defaultConfiguration();
+ QTest::newRow("default") << conf << false; // does not contain test server cert
+ QList<QSslCertificate> testServerCert = QSslCertificate::fromPath(SRCDIR "/certs/qt-test-server-cacert.pem");
+ conf.setCaCertificates(testServerCert);
+ QTest::newRow("set-root-cert") << conf << true;
+ conf.setProtocol(QSsl::SecureProtocols);
+ QTest::newRow("secure") << conf << true;
+}
+
+void tst_QNetworkReply::sslConfiguration()
+{
+ QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/index.html"));
+ QFETCH(QSslConfiguration, configuration);
+ request.setSslConfiguration(configuration);
+ QNetworkReplyPtr reply = manager.get(request);
+
+ connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
+ QTestEventLoop::instance().enterLoop(10);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QFETCH(bool, works);
+ QNetworkReply::NetworkError expectedError = works ? QNetworkReply::NoError : QNetworkReply::SslHandshakeFailedError;
+ QCOMPARE(reply->error(), expectedError);
+}
+
#endif // QT_NO_OPENSSL
void tst_QNetworkReply::getAndThenDeleteObject_data()
@@ -5135,7 +5578,7 @@ void tst_QNetworkReply::getFromHttpIntoBuffer()
// FIXME we really need to consolidate all those server implementations
class GetFromHttpIntoBuffer2Server : QObject {
- Q_OBJECT;
+ Q_OBJECT
qint64 dataSize;
qint64 dataSent;
QTcpServer server;
@@ -5257,6 +5700,7 @@ public:
void finishedSlot() {
// We should have already received all readyRead
+ QVERIFY(!bytesAvailableList.isEmpty());
QVERIFY(bytesAvailableList.last() == uploadSize);
}
};
@@ -5402,7 +5846,7 @@ void tst_QNetworkReply::getFromUnreachableIp()
QNetworkReplyPtr reply = manager.get(request);
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
- QTestEventLoop::instance().enterLoop(5);
+ QTestEventLoop::instance().enterLoop(10);
QVERIFY(!QTestEventLoop::instance().timeout());
QVERIFY(reply->error() != QNetworkReply::NoError);
@@ -5532,6 +5976,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");
@@ -5569,7 +6032,7 @@ void tst_QNetworkReply::synchronousRequest_data()
<< QString("text/plain");
QTest::newRow("simple-file")
- << QUrl(QString::fromLatin1("file:///" SRCDIR "/rfc3252.txt"))
+ << QUrl::fromLocalFile(SRCDIR "/rfc3252.txt")
<< QString("file:" SRCDIR "/rfc3252.txt")
<< true
<< QString();