summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/network/access/access.pro1
-rw-r--r--tests/auto/network/access/spdy/spdy.pro7
-rw-r--r--tests/auto/network/access/spdy/tst_spdy.cpp690
-rw-r--r--tests/benchmarks/network/access/qnetworkreply/tst_qnetworkreply.cpp43
-rw-r--r--tests/manual/qnetworkreply/main.cpp220
5 files changed, 957 insertions, 4 deletions
diff --git a/tests/auto/network/access/access.pro b/tests/auto/network/access/access.pro
index 3139f19f7b..bc76190e30 100644
--- a/tests/auto/network/access/access.pro
+++ b/tests/auto/network/access/access.pro
@@ -7,6 +7,7 @@ SUBDIRS=\
qnetworkrequest \
qhttpnetworkconnection \
qnetworkreply \
+ spdy \
qnetworkcachemetadata \
qftp \
qhttpnetworkreply \
diff --git a/tests/auto/network/access/spdy/spdy.pro b/tests/auto/network/access/spdy/spdy.pro
new file mode 100644
index 0000000000..6bfc6d84e0
--- /dev/null
+++ b/tests/auto/network/access/spdy/spdy.pro
@@ -0,0 +1,7 @@
+CONFIG += testcase
+CONFIG += parallel_test
+TARGET = tst_spdy
+SOURCES += tst_spdy.cpp
+
+QT = core core-private network network-private testlib
+DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
diff --git a/tests/auto/network/access/spdy/tst_spdy.cpp b/tests/auto/network/access/spdy/tst_spdy.cpp
new file mode 100644
index 0000000000..d2a220bad4
--- /dev/null
+++ b/tests/auto/network/access/spdy/tst_spdy.cpp
@@ -0,0 +1,690 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+#include <QtNetwork/QNetworkAccessManager>
+#include <QtNetwork/QNetworkReply>
+#include <QtNetwork/QHttpPart>
+#include <QtNetwork/QHttpMultiPart>
+#include <QtNetwork/QNetworkProxy>
+#include <QtNetwork/QAuthenticator>
+#ifdef QT_BUILD_INTERNAL
+#include <QtNetwork/private/qsslsocket_openssl_p.h>
+#endif // QT_BUILD_INTERNAL
+
+#include "../../../network-settings.h"
+
+Q_DECLARE_METATYPE(QAuthenticator*)
+
+class tst_Spdy: public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_Spdy();
+ ~tst_Spdy();
+
+private Q_SLOTS:
+ void settingsAndNegotiation_data();
+ void settingsAndNegotiation();
+ void download_data();
+ void download();
+ void headerFields();
+ void upload_data();
+ void upload();
+ void errors_data();
+ void errors();
+ void multipleRequests_data();
+ void multipleRequests();
+
+private:
+ QNetworkAccessManager m_manager;
+ int m_multipleRequestsCount;
+ int m_multipleRepliesFinishedCount;
+
+protected Q_SLOTS:
+ void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *authenticator);
+ void multipleRequestsFinishedSlot();
+};
+
+tst_Spdy::tst_Spdy()
+{
+#if defined(QT_BUILD_INTERNAL) && !defined(QT_NO_SSL) && OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+ qRegisterMetaType<QNetworkReply *>(); // for QSignalSpy
+ qRegisterMetaType<QAuthenticator *>();
+
+ connect(&m_manager, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)),
+ this, SLOT(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
+#else
+ QSKIP("Qt built withouth OpenSSL, or the OpenSSL version is too old");
+#endif // defined(QT_BUILD_INTERNAL) && !defined(QT_NO_SSL) ...
+}
+
+tst_Spdy::~tst_Spdy()
+{
+}
+
+void tst_Spdy::settingsAndNegotiation_data()
+{
+ QTest::addColumn<QUrl>("url");
+ QTest::addColumn<bool>("setAttribute");
+ QTest::addColumn<bool>("enabled");
+ QTest::addColumn<QByteArray>("expectedProtocol");
+ QTest::addColumn<QByteArray>("expectedContent");
+
+ QTest::newRow("default-settings") << QUrl("https://" + QtNetworkSettings::serverName()
+ + "/qtest/cgi-bin/echo.cgi?1")
+ << false << false << QByteArray()
+ << QByteArray("1");
+
+ QTest::newRow("http-url") << QUrl("http://" + QtNetworkSettings::serverName()
+ + "/qtest/cgi-bin/echo.cgi?1")
+ << true << true << QByteArray()
+ << QByteArray("1");
+
+ QTest::newRow("spdy-disabled") << QUrl("https://" + QtNetworkSettings::serverName()
+ + "/qtest/cgi-bin/echo.cgi?1")
+ << true << false << QByteArray()
+ << QByteArray("1");
+
+#ifndef QT_NO_OPENSSL
+ QTest::newRow("spdy-enabled") << QUrl("https://" + QtNetworkSettings::serverName()
+ + "/qtest/cgi-bin/echo.cgi?1")
+ << true << true << QByteArray(QSslConfiguration::NextProtocolSpdy3_0)
+ << QByteArray("1");
+#endif // QT_NO_OPENSSL
+}
+
+void tst_Spdy::settingsAndNegotiation()
+{
+ QFETCH(QUrl, url);
+ QFETCH(bool, setAttribute);
+ QFETCH(bool, enabled);
+
+ QNetworkRequest request(url);
+
+ if (setAttribute) {
+ request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, QVariant(enabled));
+ }
+
+ QNetworkReply *reply = m_manager.get(request);
+ reply->ignoreSslErrors();
+ QSignalSpy metaDataChangedSpy(reply, SIGNAL(metaDataChanged()));
+ QSignalSpy readyReadSpy(reply, SIGNAL(readyRead()));
+ QSignalSpy finishedSpy(reply, SIGNAL(finished()));
+
+ QObject::connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
+ QSignalSpy finishedManagerSpy(&m_manager, SIGNAL(finished(QNetworkReply*)));
+
+ QTestEventLoop::instance().enterLoop(15);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QFETCH(QByteArray, expectedProtocol);
+
+#ifndef QT_NO_OPENSSL
+ bool expectedSpdyUsed = (expectedProtocol == QSslConfiguration::NextProtocolSpdy3_0)
+ ? true : false;
+ QCOMPARE(reply->attribute(QNetworkRequest::SpdyWasUsedAttribute).toBool(), expectedSpdyUsed);
+#endif // QT_NO_OPENSSL
+
+ QCOMPARE(metaDataChangedSpy.count(), 1);
+ QCOMPARE(finishedSpy.count(), 1);
+
+ int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ QCOMPARE(statusCode, 200);
+
+ QByteArray content = reply->readAll();
+
+ QFETCH(QByteArray, expectedContent);
+ QCOMPARE(expectedContent, content);
+
+#ifndef QT_NO_OPENSSL
+ QSslConfiguration::NextProtocolNegotiationStatus expectedStatus =
+ (expectedProtocol.isEmpty())
+ ? QSslConfiguration::NextProtocolNegotiationNone
+ : QSslConfiguration::NextProtocolNegotiationNegotiated;
+ QCOMPARE(reply->sslConfiguration().nextProtocolNegotiationStatus(),
+ expectedStatus);
+
+ QCOMPARE(reply->sslConfiguration().nextNegotiatedProtocol(), expectedProtocol);
+#endif // QT_NO_OPENSSL
+}
+
+void tst_Spdy::proxyAuthenticationRequired(const QNetworkProxy &/*proxy*/,
+ QAuthenticator *authenticator)
+{
+ authenticator->setUser("qsockstest");
+ authenticator->setPassword("password");
+}
+
+void tst_Spdy::download_data()
+{
+ QTest::addColumn<QUrl>("url");
+ QTest::addColumn<QString>("fileName");
+ QTest::addColumn<QNetworkProxy>("proxy");
+
+ QTest::newRow("mediumfile") << QUrl("https://" + QtNetworkSettings::serverName()
+ + "/qtest/rfc3252.txt")
+ << QFINDTESTDATA("../qnetworkreply/rfc3252.txt")
+ << QNetworkProxy();
+
+ QHostInfo hostInfo = QHostInfo::fromName(QtNetworkSettings::serverName());
+ QString proxyserver = hostInfo.addresses().first().toString();
+
+ QTest::newRow("mediumfile-http-proxy") << QUrl("https://" + QtNetworkSettings::serverName()
+ + "/qtest/rfc3252.txt")
+ << QFINDTESTDATA("../qnetworkreply/rfc3252.txt")
+ << QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3128);
+
+ QTest::newRow("mediumfile-http-proxy-auth") << QUrl("https://" + QtNetworkSettings::serverName()
+ + "/qtest/rfc3252.txt")
+ << QFINDTESTDATA("../qnetworkreply/rfc3252.txt")
+ << QNetworkProxy(QNetworkProxy::HttpProxy,
+ proxyserver, 3129);
+
+ QTest::newRow("mediumfile-socks-proxy") << QUrl("https://" + QtNetworkSettings::serverName()
+ + "/qtest/rfc3252.txt")
+ << QFINDTESTDATA("../qnetworkreply/rfc3252.txt")
+ << QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1080);
+
+ QTest::newRow("mediumfile-socks-proxy-auth") << QUrl("https://" + QtNetworkSettings::serverName()
+ + "/qtest/rfc3252.txt")
+ << QFINDTESTDATA("../qnetworkreply/rfc3252.txt")
+ << QNetworkProxy(QNetworkProxy::Socks5Proxy,
+ proxyserver, 1081);
+
+ QTest::newRow("bigfile") << QUrl("https://" + QtNetworkSettings::serverName()
+ + "/qtest/bigfile")
+ << QFINDTESTDATA("../qnetworkreply/bigfile")
+ << QNetworkProxy();
+}
+
+void tst_Spdy::download()
+{
+ QFETCH(QUrl, url);
+ QFETCH(QString, fileName);
+ QFETCH(QNetworkProxy, proxy);
+
+ QNetworkRequest request(url);
+ request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true);
+
+ if (proxy.type() != QNetworkProxy::DefaultProxy) {
+ m_manager.setProxy(proxy);
+ }
+ QNetworkReply *reply = m_manager.get(request);
+ reply->ignoreSslErrors();
+ QSignalSpy metaDataChangedSpy(reply, SIGNAL(metaDataChanged()));
+ QSignalSpy downloadProgressSpy(reply, SIGNAL(downloadProgress(qint64, qint64)));
+ QSignalSpy readyReadSpy(reply, SIGNAL(readyRead()));
+ QSignalSpy finishedSpy(reply, SIGNAL(finished()));
+
+ QObject::connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
+ QSignalSpy finishedManagerSpy(&m_manager, SIGNAL(finished(QNetworkReply*)));
+ QSignalSpy proxyAuthRequiredSpy(&m_manager, SIGNAL(
+ proxyAuthenticationRequired(const QNetworkProxy &,
+ QAuthenticator *)));
+
+ QTestEventLoop::instance().enterLoop(15);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QCOMPARE(finishedManagerSpy.count(), 1);
+ QCOMPARE(metaDataChangedSpy.count(), 1);
+ QCOMPARE(finishedSpy.count(), 1);
+ QVERIFY(downloadProgressSpy.count() > 0);
+ QVERIFY(readyReadSpy.count() > 0);
+
+ QVERIFY(proxyAuthRequiredSpy.count() <= 1);
+
+ QCOMPARE(reply->error(), QNetworkReply::NoError);
+ QCOMPARE(reply->attribute(QNetworkRequest::SpdyWasUsedAttribute).toBool(), true);
+ QCOMPARE(reply->attribute(QNetworkRequest::ConnectionEncryptedAttribute).toBool(), true);
+ QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
+
+ QFile file(fileName);
+ QVERIFY(file.open(QIODevice::ReadOnly));
+
+ qint64 contentLength = reply->header(QNetworkRequest::ContentLengthHeader).toLongLong();
+ qint64 expectedContentLength = file.bytesAvailable();
+ QCOMPARE(contentLength, expectedContentLength);
+
+ QByteArray expectedContent = file.readAll();
+ QByteArray content = reply->readAll();
+ QCOMPARE(content, expectedContent);
+
+ reply->deleteLater();
+ m_manager.setProxy(QNetworkProxy()); // reset
+}
+
+void tst_Spdy::headerFields()
+{
+ QUrl url(QUrl("https://" + QtNetworkSettings::serverName()));
+ QNetworkRequest request(url);
+ request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true);
+
+ QNetworkReply *reply = m_manager.get(request);
+ reply->ignoreSslErrors();
+
+ QObject::connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
+
+ QTestEventLoop::instance().enterLoop(15);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QCOMPARE(reply->rawHeader("Content-Type"), QByteArray("text/html"));
+ QVERIFY(reply->rawHeader("Content-Length").toInt() > 0);
+ QVERIFY(reply->rawHeader("server").contains("Apache"));
+
+ QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toByteArray(), QByteArray("text/html"));
+ QVERIFY(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong() > 0);
+ QVERIFY(reply->header(QNetworkRequest::LastModifiedHeader).toDateTime().isValid());
+ QVERIFY(reply->header(QNetworkRequest::ServerHeader).toByteArray().contains("Apache"));
+}
+
+static inline QByteArray md5sum(const QByteArray &data)
+{
+ return QCryptographicHash::hash(data, QCryptographicHash::Md5).toHex().append('\n');
+}
+
+void tst_Spdy::upload_data()
+{
+ QTest::addColumn<QUrl>("url");
+ QTest::addColumn<QByteArray>("data");
+ QTest::addColumn<QByteArray>("uploadMethod");
+ QTest::addColumn<QObject *>("uploadObject");
+ QTest::addColumn<QByteArray>("md5sum");
+ QTest::addColumn<QNetworkProxy>("proxy");
+
+
+ // 1. test uploading of byte arrays
+
+ QUrl md5Url("https://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
+
+ QByteArray data;
+ data = "";
+ QObject *dummyObject = 0;
+ QTest::newRow("empty") << md5Url << data << QByteArray("POST") << dummyObject
+ << md5sum(data) << QNetworkProxy();
+
+ data = "This is a normal message.";
+ QTest::newRow("generic") << md5Url << data << QByteArray("POST") << dummyObject
+ << md5sum(data) << QNetworkProxy();
+
+ data = "This is a message to show that Qt rocks!\r\n\n";
+ QTest::newRow("small") << md5Url << data << QByteArray("POST") << dummyObject
+ << md5sum(data) << QNetworkProxy();
+
+ data = QByteArray("abcd\0\1\2\abcd",12);
+ QTest::newRow("with-nul") << md5Url << data << QByteArray("POST") << dummyObject
+ << md5sum(data) << QNetworkProxy();
+
+ data = QByteArray(4097, '\4');
+ QTest::newRow("4k+1") << md5Url << data << QByteArray("POST") << dummyObject
+ << md5sum(data)<< QNetworkProxy();
+
+ QHostInfo hostInfo = QHostInfo::fromName(QtNetworkSettings::serverName());
+ QString proxyserver = hostInfo.addresses().first().toString();
+
+ QTest::newRow("4k+1-with-http-proxy") << md5Url << data << QByteArray("POST") << dummyObject
+ << md5sum(data)
+ << QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3128);
+
+ QTest::newRow("4k+1-with-http-proxy-auth") << md5Url << data << QByteArray("POST") << dummyObject
+ << md5sum(data)
+ << QNetworkProxy(QNetworkProxy::HttpProxy,
+ proxyserver, 3129);
+
+ QTest::newRow("4k+1-with-socks-proxy") << md5Url << data << QByteArray("POST") << dummyObject
+ << md5sum(data)
+ << QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1080);
+
+ QTest::newRow("4k+1-with-socks-proxy-auth") << md5Url << data << QByteArray("POST") << dummyObject
+ << md5sum(data)
+ << QNetworkProxy(QNetworkProxy::Socks5Proxy,
+ proxyserver, 1081);
+
+ data = QByteArray(128*1024+1, '\177');
+ QTest::newRow("128k+1") << md5Url << data << QByteArray("POST") << dummyObject
+ << md5sum(data) << QNetworkProxy();
+
+ data = QByteArray(128*1024+1, '\177');
+ QTest::newRow("128k+1-put") << md5Url << data << QByteArray("PUT") << dummyObject
+ << md5sum(data) << QNetworkProxy();
+
+ data = QByteArray(2*1024*1024+1, '\177');
+ QTest::newRow("2MB+1") << md5Url << data << QByteArray("POST") << dummyObject
+ << md5sum(data) << QNetworkProxy();
+
+
+ // 2. test uploading of files
+
+ QFile *file = new QFile(QFINDTESTDATA("../qnetworkreply/rfc3252.txt"));
+ file->open(QIODevice::ReadOnly);
+ QTest::newRow("file-26K") << md5Url << QByteArray() << QByteArray("POST")
+ << static_cast<QObject *>(file)
+ << QByteArray("b3e32ac459b99d3f59318f3ac31e4bee\n") << QNetworkProxy();
+
+ QFile *file2 = new QFile(QFINDTESTDATA("../qnetworkreply/image1.jpg"));
+ file2->open(QIODevice::ReadOnly);
+ QTest::newRow("file-1MB") << md5Url << QByteArray() << QByteArray("POST")
+ << static_cast<QObject *>(file2)
+ << QByteArray("87ef3bb319b004ba9e5e9c9fa713776e\n") << QNetworkProxy();
+
+
+ // 3. test uploading of multipart
+
+ QUrl multiPartUrl("https://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/multipart.cgi");
+
+ 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(QFINDTESTDATA("../qnetworkreply/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(QFINDTESTDATA("../qnetworkreply/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(QFINDTESTDATA("../qnetworkreply/image3.jpg"));
+ file33->open(QIODevice::ReadOnly);
+ imagePart33.setBodyDevice(file33);
+ imageMultiPart3->append(imagePart33);
+ file33->setParent(imageMultiPart3);
+ QByteArray expectedData = "content type: multipart/form-data; boundary=\""
+ + imageMultiPart3->boundary();
+ expectedData.append("\"\nkey: testImage1, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"
+ "key: testImage2, value: 483761b893f7fb1bd2414344cd1f3dfb\n"
+ "key: testImage3, value: ab0eb6fd4fcf8b4436254870b4513033\n");
+
+ QTest::newRow("multipart-3images") << multiPartUrl << QByteArray() << QByteArray("POST")
+ << static_cast<QObject *>(imageMultiPart3) << expectedData
+ << QNetworkProxy();
+}
+
+void tst_Spdy::upload()
+{
+ QFETCH(QUrl, url);
+ QNetworkRequest request(url);
+ request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true);
+
+ QFETCH(QByteArray, data);
+ QFETCH(QByteArray, uploadMethod);
+ QFETCH(QObject *, uploadObject);
+ QFETCH(QNetworkProxy, proxy);
+
+ if (proxy.type() != QNetworkProxy::DefaultProxy) {
+ m_manager.setProxy(proxy);
+ }
+
+ QNetworkReply *reply;
+ QHttpMultiPart *multiPart = 0;
+
+ if (uploadObject) {
+ // upload via device
+ if (QIODevice *device = qobject_cast<QIODevice *>(uploadObject)) {
+ reply = m_manager.post(request, device);
+ } else if ((multiPart = qobject_cast<QHttpMultiPart *>(uploadObject))) {
+ reply = m_manager.post(request, multiPart);
+ } else {
+ QFAIL("got unknown upload device");
+ }
+ } else {
+ // upload via byte array
+ if (uploadMethod == "PUT") {
+ reply = m_manager.put(request, data);
+ } else {
+ reply = m_manager.post(request, data);
+ }
+ }
+
+ reply->ignoreSslErrors();
+ QSignalSpy metaDataChangedSpy(reply, SIGNAL(metaDataChanged()));
+ QSignalSpy uploadProgressSpy(reply, SIGNAL(uploadProgress(qint64, qint64)));
+ QSignalSpy readyReadSpy(reply, SIGNAL(readyRead()));
+ QSignalSpy finishedSpy(reply, SIGNAL(finished()));
+
+ QObject::connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
+ QSignalSpy finishedManagerSpy(&m_manager, SIGNAL(finished(QNetworkReply*)));
+
+ QTestEventLoop::instance().enterLoop(20);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QCOMPARE(finishedManagerSpy.count(), 1);
+ QCOMPARE(metaDataChangedSpy.count(), 1);
+ QCOMPARE(finishedSpy.count(), 1);
+ QVERIFY(uploadProgressSpy.count() > 0);
+ QVERIFY(readyReadSpy.count() > 0);
+
+ QCOMPARE(reply->error(), QNetworkReply::NoError);
+ QCOMPARE(reply->attribute(QNetworkRequest::SpdyWasUsedAttribute).toBool(), true);
+ QCOMPARE(reply->attribute(QNetworkRequest::ConnectionEncryptedAttribute).toBool(), true);
+ QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
+
+ qint64 contentLength = reply->header(QNetworkRequest::ContentLengthHeader).toLongLong();
+ if (!multiPart) // script to test multiparts does not return a content length
+ QCOMPARE(contentLength, 33); // 33 bytes for md5 sums (including new line)
+
+ QFETCH(QByteArray, md5sum);
+ QByteArray content = reply->readAll();
+ QCOMPARE(content, md5sum);
+
+ reply->deleteLater();
+ if (uploadObject)
+ uploadObject->deleteLater();
+
+ m_manager.setProxy(QNetworkProxy()); // reset
+}
+
+void tst_Spdy::errors_data()
+{
+ QTest::addColumn<QUrl>("url");
+ QTest::addColumn<QNetworkProxy>("proxy");
+ QTest::addColumn<bool>("ignoreSslErrors");
+ QTest::addColumn<int>("expectedReplyError");
+
+ QTest::newRow("http-404") << QUrl("https://" + QtNetworkSettings::serverName() + "/non-existent-url")
+ << QNetworkProxy() << true << int(QNetworkReply::ContentNotFoundError);
+
+ QTest::newRow("ssl-errors") << QUrl("https://" + QtNetworkSettings::serverName())
+ << QNetworkProxy() << false << int(QNetworkReply::SslHandshakeFailedError);
+
+ QTest::newRow("host-not-found") << QUrl("https://this-host-does-not.exist")
+ << QNetworkProxy()
+ << true << int(QNetworkReply::HostNotFoundError);
+
+ QTest::newRow("proxy-not-found") << QUrl("https://" + QtNetworkSettings::serverName())
+ << QNetworkProxy(QNetworkProxy::HttpProxy,
+ "https://this-host-does-not.exist", 3128)
+ << true << int(QNetworkReply::HostNotFoundError);
+
+ QHostInfo hostInfo = QHostInfo::fromName(QtNetworkSettings::serverName());
+ QString proxyserver = hostInfo.addresses().first().toString();
+
+ QTest::newRow("proxy-unavailable") << QUrl("https://" + QtNetworkSettings::serverName())
+ << QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 10)
+ << true << int(QNetworkReply::UnknownNetworkError);
+
+ QTest::newRow("no-proxy-credentials") << QUrl("https://" + QtNetworkSettings::serverName())
+ << QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3129)
+ << true << int(QNetworkReply::ProxyAuthenticationRequiredError);
+}
+
+void tst_Spdy::errors()
+{
+ QFETCH(QUrl, url);
+ QFETCH(QNetworkProxy, proxy);
+ QFETCH(bool, ignoreSslErrors);
+ QFETCH(int, expectedReplyError);
+
+ QNetworkRequest request(url);
+ request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true);
+
+ disconnect(&m_manager, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)),
+ 0, 0);
+ if (proxy.type() != QNetworkProxy::DefaultProxy) {
+ m_manager.setProxy(proxy);
+ }
+ QNetworkReply *reply = m_manager.get(request);
+ if (ignoreSslErrors)
+ reply->ignoreSslErrors();
+ QSignalSpy finishedSpy(reply, SIGNAL(finished()));
+ QSignalSpy errorSpy(reply, SIGNAL(error(QNetworkReply::NetworkError)));
+
+ QObject::connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
+
+ QTestEventLoop::instance().enterLoop(15);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QCOMPARE(finishedSpy.count(), 1);
+ QCOMPARE(errorSpy.count(), 1);
+
+ QCOMPARE(reply->error(), static_cast<QNetworkReply::NetworkError>(expectedReplyError));
+
+ m_manager.setProxy(QNetworkProxy()); // reset
+ m_manager.clearAccessCache(); // e.g. to get an SSL error we need a new connection
+ connect(&m_manager, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)),
+ this, SLOT(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)),
+ Qt::UniqueConnection); // reset
+}
+
+void tst_Spdy::multipleRequests_data()
+{
+ QTest::addColumn<QList<QUrl> >("urls");
+
+ QString baseUrl = "https://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/echo.cgi?";
+ QList<QUrl> urls;
+ for (int a = 1; a <= 50; ++a)
+ urls.append(QUrl(baseUrl + QLatin1String(QByteArray::number(a))));
+
+ QTest::newRow("one-request") << urls.mid(0, 1);
+ QTest::newRow("two-requests") << urls.mid(0, 2);
+ QTest::newRow("ten-requests") << urls.mid(0, 10);
+ QTest::newRow("twenty-requests") << urls.mid(0, 20);
+ QTest::newRow("fifty-requests") << urls;
+}
+
+void tst_Spdy::multipleRequestsFinishedSlot()
+{
+ m_multipleRepliesFinishedCount++;
+ if (m_multipleRepliesFinishedCount == m_multipleRequestsCount)
+ QTestEventLoop::instance().exitLoop();
+}
+
+void tst_Spdy::multipleRequests()
+{
+ QFETCH(QList<QUrl>, urls);
+ m_multipleRequestsCount = urls.count();
+ m_multipleRepliesFinishedCount = 0;
+
+ QList<QNetworkReply *> replies;
+ QList<QSignalSpy *> metaDataChangedSpies;
+ QList<QSignalSpy *> readyReadSpies;
+ QList<QSignalSpy *> finishedSpies;
+
+ foreach (const QUrl &url, urls) {
+ QNetworkRequest request(url);
+ request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true);
+ QNetworkReply *reply = m_manager.get(request);
+ replies.append(reply);
+ reply->ignoreSslErrors();
+ QObject::connect(reply, SIGNAL(finished()), this, SLOT(multipleRequestsFinishedSlot()));
+ QSignalSpy *metaDataChangedSpy = new QSignalSpy(reply, SIGNAL(metaDataChanged()));
+ metaDataChangedSpies << metaDataChangedSpy;
+ QSignalSpy *readyReadSpy = new QSignalSpy(reply, SIGNAL(readyRead()));
+ readyReadSpies << readyReadSpy;
+ QSignalSpy *finishedSpy = new QSignalSpy(reply, SIGNAL(finished()));
+ finishedSpies << finishedSpy;
+ }
+
+ QSignalSpy finishedManagerSpy(&m_manager, SIGNAL(finished(QNetworkReply*)));
+
+ QTestEventLoop::instance().enterLoop(15);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QCOMPARE(finishedManagerSpy.count(), m_multipleRequestsCount);
+
+ for (int a = 0; a < replies.count(); ++a) {
+
+#ifndef QT_NO_OPENSSL
+ QCOMPARE(replies.at(a)->sslConfiguration().nextProtocolNegotiationStatus(),
+ QSslConfiguration::NextProtocolNegotiationNegotiated);
+ QCOMPARE(replies.at(a)->sslConfiguration().nextNegotiatedProtocol(),
+ QByteArray(QSslConfiguration::NextProtocolSpdy3_0));
+#endif // QT_NO_OPENSSL
+
+ QCOMPARE(replies.at(a)->error(), QNetworkReply::NoError);
+ QCOMPARE(replies.at(a)->attribute(QNetworkRequest::SpdyWasUsedAttribute).toBool(), true);
+ QCOMPARE(replies.at(a)->attribute(QNetworkRequest::ConnectionEncryptedAttribute).toBool(), true);
+ QCOMPARE(replies.at(a)->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
+
+ // using the echo script, a request to "echo.cgi?1" will return a body of "1"
+ QByteArray expectedContent = replies.at(a)->url().query().toUtf8();
+ QByteArray content = replies.at(a)->readAll();
+ QCOMPARE(expectedContent, content);
+
+ QCOMPARE(metaDataChangedSpies.at(a)->count(), 1);
+ metaDataChangedSpies.at(a)->deleteLater();
+
+ QCOMPARE(finishedSpies.at(a)->count(), 1);
+ finishedSpies.at(a)->deleteLater();
+
+ QVERIFY(readyReadSpies.at(a)->count() > 0);
+ readyReadSpies.at(a)->deleteLater();
+
+ replies.at(a)->deleteLater();
+ }
+}
+
+QTEST_MAIN(tst_Spdy)
+
+#include "tst_spdy.moc"
diff --git a/tests/benchmarks/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/benchmarks/network/access/qnetworkreply/tst_qnetworkreply.cpp
index 55376d5a79..3b8565a0ec 100644
--- a/tests/benchmarks/network/access/qnetworkreply/tst_qnetworkreply.cpp
+++ b/tests/benchmarks/network/access/qnetworkreply/tst_qnetworkreply.cpp
@@ -52,6 +52,7 @@
#ifdef QT_BUILD_INTERNAL
#include <QtNetwork/private/qhostinfo_p.h>
+#include <QtNetwork/private/qsslsocket_openssl_p.h>
#endif
Q_DECLARE_METATYPE(QSharedPointer<char>)
@@ -552,10 +553,16 @@ void tst_qnetworkreply::echoPerformance()
void tst_qnetworkreply::preConnectEncrypted()
{
+ QFETCH(int, sleepTime);
+ QFETCH(QSslConfiguration, sslConfiguration);
+ bool spdyEnabled = !sslConfiguration.isNull();
+
QString hostName = QLatin1String("www.google.com");
QNetworkAccessManager manager;
QNetworkRequest request(QUrl("https://" + hostName));
+ if (spdyEnabled)
+ request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true);
// make sure we have a full request including
// DNS lookup, TCP and SSL handshakes
@@ -581,8 +588,12 @@ void tst_qnetworkreply::preConnectEncrypted()
manager.clearAccessCache();
// now try to make the connection beforehand
- QFETCH(int, sleepTime);
- manager.connectToHostEncrypted(hostName);
+ if (spdyEnabled) {
+ request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true);
+ manager.connectToHostEncrypted(hostName, 443, sslConfiguration);
+ } else {
+ manager.connectToHostEncrypted(hostName);
+ }
QTestEventLoop::instance().enterLoopMSecs(sleepTime);
// now make another request and hopefully use the existing connection
@@ -590,18 +601,42 @@ void tst_qnetworkreply::preConnectEncrypted()
QNetworkReply *preConnectReply = normalResult.first;
QVERIFY(!QTestEventLoop::instance().timeout());
QVERIFY(preConnectReply->error() == QNetworkReply::NoError);
+ bool spdyWasUsed = preConnectReply->attribute(QNetworkRequest::SpdyWasUsedAttribute).toBool();
+ QCOMPARE(spdyEnabled, spdyWasUsed);
qint64 preConnectElapsed = preConnectResult.second;
qDebug() << request.url().toString() << "full request:" << normalElapsed
<< "ms, pre-connect request:" << preConnectElapsed << "ms, difference:"
<< (normalElapsed - preConnectElapsed) << "ms";
}
+
#endif // !QT_NO_SSL
void tst_qnetworkreply::preConnectEncrypted_data()
{
+#ifndef QT_NO_OPENSSL
QTest::addColumn<int>("sleepTime");
- QTest::newRow("2secs") << 2000; // to start a new request after preconnecting is done
- QTest::newRow("100ms") << 100; // to start a new request while preconnecting is in-flight
+ QTest::addColumn<QSslConfiguration>("sslConfiguration");
+
+ // start a new normal request after preconnecting is done
+ QTest::newRow("HTTPS-2secs") << 2000 << QSslConfiguration();
+
+ // start a new normal request while preconnecting is in-flight
+ QTest::newRow("HTTPS-100ms") << 100 << QSslConfiguration();
+
+ QSslConfiguration spdySslConf = QSslConfiguration::defaultConfiguration();
+ QList<QByteArray> nextProtocols = QList<QByteArray>()
+ << QSslConfiguration::NextProtocolSpdy3_0
+ << QSslConfiguration::NextProtocolHttp1_1;
+ spdySslConf.setAllowedNextProtocols(nextProtocols);
+
+#if defined(QT_BUILD_INTERNAL) && !defined(QT_NO_SSL) && OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+ // start a new SPDY request while preconnecting is done
+ QTest::newRow("SPDY-2secs") << 2000 << spdySslConf;
+
+ // start a new SPDY request while preconnecting is in-flight
+ QTest::newRow("SPDY-100ms") << 100 << spdySslConf;
+#endif // defined (QT_BUILD_INTERNAL) && !defined(QT_NO_SSL) ...
+#endif // QT_NO_OPENSSL
}
void tst_qnetworkreply::downloadPerformance()
diff --git a/tests/manual/qnetworkreply/main.cpp b/tests/manual/qnetworkreply/main.cpp
index fe667e92a0..ff96f2598d 100644
--- a/tests/manual/qnetworkreply/main.cpp
+++ b/tests/manual/qnetworkreply/main.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
@@ -53,6 +54,7 @@
#if defined(QT_BUILD_INTERNAL) && !defined(QT_NO_SSL)
#include "private/qsslsocket_p.h"
+#include <QtNetwork/private/qsslsocket_openssl_p.h>
#endif
#define BANDWIDTH_LIMIT_BYTES (1024*100)
@@ -68,8 +70,16 @@ private slots:
void setSslConfiguration_data();
void setSslConfiguration();
void uploadToFacebook();
+ void spdy_data();
+ void spdy();
+ void spdyMultipleRequestsPerHost();
+
+protected slots:
+ void spdyReplyFinished(); // only used by spdyMultipleRequestsPerHost test
+
private:
QHttpMultiPart *createFacebookMultiPart(const QByteArray &accessToken);
+ QNetworkAccessManager m_manager;
};
QNetworkReply *reply;
@@ -104,6 +114,7 @@ protected:
void tst_qnetworkreply::initTestCase()
{
+ qRegisterMetaType<QNetworkReply *>(); // for QSignalSpy
QVERIFY(QtNetworkSettings::verifyTestNetworkSettings());
}
@@ -284,6 +295,215 @@ void tst_qnetworkreply::uploadToFacebook()
}
}
+void tst_qnetworkreply::spdy_data()
+{
+ QTest::addColumn<QString>("host");
+ QTest::addColumn<bool>("setAttribute");
+ QTest::addColumn<bool>("enabled");
+ QTest::addColumn<QByteArray>("expectedProtocol");
+
+ QList<QString> hosts = QList<QString>()
+ << QStringLiteral("www.google.com") // sends SPDY and 30x redirect
+ << QStringLiteral("www.google.de") // sends SPDY and 200 OK
+ << QStringLiteral("mail.google.com") // sends SPDY and 200 OK
+ << QStringLiteral("www.youtube.com") // sends SPDY and 200 OK
+ << QStringLiteral("www.dropbox.com") // no SPDY, but NPN which selects HTTP
+ << QStringLiteral("www.facebook.com") // sends SPDY and 200 OK
+ << QStringLiteral("graph.facebook.com") // sends SPDY and 200 OK
+ << QStringLiteral("www.twitter.com") // sends SPDY and 30x redirect
+ << QStringLiteral("twitter.com") // sends SPDY and 200 OK
+ << QStringLiteral("api.twitter.com"); // sends SPDY and 200 OK
+
+ foreach (const QString &host, hosts) {
+ QByteArray tag = host.toLocal8Bit();
+ tag.append("-not-used");
+ QTest::newRow(tag)
+ << QStringLiteral("https://") + host
+ << false
+ << false
+ << QByteArray();
+
+ tag = host.toLocal8Bit();
+ tag.append("-disabled");
+ QTest::newRow(tag)
+ << QStringLiteral("https://") + host
+ << true
+ << false
+ << QByteArray();
+
+ if (host != QStringLiteral("api.twitter.com")) { // they don't offer an API over HTTP
+ tag = host.toLocal8Bit();
+ tag.append("-no-https-url");
+ QTest::newRow(tag)
+ << QStringLiteral("http://") + host
+ << true
+ << true
+ << QByteArray();
+ }
+
+#ifndef QT_NO_OPENSSL
+ tag = host.toLocal8Bit();
+ tag.append("-enabled");
+ QTest::newRow(tag)
+ << QStringLiteral("https://") + host
+ << true
+ << true
+ << (host == QStringLiteral("www.dropbox.com")
+ ? QByteArray(QSslConfiguration::NextProtocolHttp1_1)
+ : QByteArray(QSslConfiguration::NextProtocolSpdy3_0));
+#endif // QT_NO_OPENSSL
+ }
+}
+
+void tst_qnetworkreply::spdy()
+{
+#if defined(QT_BUILD_INTERNAL) && !defined(QT_NO_SSL) && OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+
+ m_manager.clearAccessCache();
+
+ QFETCH(QString, host);
+ QUrl url(host);
+ QNetworkRequest request(url);
+
+ QFETCH(bool, setAttribute);
+ QFETCH(bool, enabled);
+ if (setAttribute) {
+ request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, QVariant(enabled));
+ }
+
+ QNetworkReply *reply = m_manager.get(request);
+ QObject::connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
+
+ QSignalSpy metaDataChangedSpy(reply, SIGNAL(metaDataChanged()));
+ QSignalSpy readyReadSpy(reply, SIGNAL(readyRead()));
+ QSignalSpy finishedSpy(reply, SIGNAL(finished()));
+ QSignalSpy finishedManagerSpy(&m_manager, SIGNAL(finished(QNetworkReply*)));
+
+ QTestEventLoop::instance().enterLoop(15);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QFETCH(QByteArray, expectedProtocol);
+
+ bool expectedSpdyUsed = (expectedProtocol == QSslConfiguration::NextProtocolSpdy3_0)
+ ? true : false;
+ QCOMPARE(reply->attribute(QNetworkRequest::SpdyWasUsedAttribute).toBool(), expectedSpdyUsed);
+
+ QCOMPARE(metaDataChangedSpy.count(), 1);
+ QCOMPARE(finishedSpy.count(), 1);
+ QCOMPARE(finishedManagerSpy.count(), 1);
+
+ QUrl redirectUrl = reply->header(QNetworkRequest::LocationHeader).toUrl();
+ QByteArray content = reply->readAll();
+
+ int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ QVERIFY(statusCode >= 200 && statusCode < 500);
+ if (statusCode == 200 || statusCode >= 400) {
+ QVERIFY(readyReadSpy.count() > 0);
+ QVERIFY(!content.isEmpty());
+ } else if (statusCode >= 300 && statusCode < 400) {
+ QVERIFY(!redirectUrl.isEmpty());
+ }
+
+ QSslConfiguration::NextProtocolNegotiationStatus expectedStatus =
+ expectedProtocol.isNull() ? QSslConfiguration::NextProtocolNegotiationNone
+ : QSslConfiguration::NextProtocolNegotiationNegotiated;
+ QCOMPARE(reply->sslConfiguration().nextProtocolNegotiationStatus(),
+ expectedStatus);
+
+ QCOMPARE(reply->sslConfiguration().nextNegotiatedProtocol(), expectedProtocol);
+#else
+ QSKIP("Qt built withouth OpenSSL, or the OpenSSL version is too old");
+#endif // defined(QT_BUILD_INTERNAL) && !defined(QT_NO_SSL) ...
+}
+
+void tst_qnetworkreply::spdyReplyFinished()
+{
+ static int finishedCount = 0;
+ finishedCount++;
+
+ if (finishedCount == 12)
+ QTestEventLoop::instance().exitLoop();
+}
+
+void tst_qnetworkreply::spdyMultipleRequestsPerHost()
+{
+#if defined(QT_BUILD_INTERNAL) && !defined(QT_NO_SSL) && OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+
+ QList<QNetworkRequest> requests;
+ requests
+ << QNetworkRequest(QUrl("https://www.facebook.com"))
+ << QNetworkRequest(QUrl("https://www.facebook.com/images/fb_icon_325x325.png"))
+
+ << QNetworkRequest(QUrl("https://www.google.de"))
+ << QNetworkRequest(QUrl("https://www.google.de/preferences?hl=de"))
+ << QNetworkRequest(QUrl("https://www.google.de/intl/de/policies/?fg=1"))
+ << QNetworkRequest(QUrl("https://www.google.de/intl/de/about.html?fg=1"))
+ << QNetworkRequest(QUrl("https://www.google.de/services/?fg=1"))
+ << QNetworkRequest(QUrl("https://www.google.de/intl/de/ads/?fg=1"))
+
+ << QNetworkRequest(QUrl("https://i1.ytimg.com/li/tnHdj3df7iM/default.jpg"))
+ << QNetworkRequest(QUrl("https://i1.ytimg.com/li/7Dr1BKwqctY/default.jpg"))
+ << QNetworkRequest(QUrl("https://i1.ytimg.com/li/hfZhJdhTqX8/default.jpg"))
+ << QNetworkRequest(QUrl("https://i1.ytimg.com/vi/14Nprh8163I/hqdefault.jpg"))
+ ;
+ QList<QNetworkReply *> replies;
+ QList<QSignalSpy *> metaDataChangedSpies;
+ QList<QSignalSpy *> readyReadSpies;
+ QList<QSignalSpy *> finishedSpies;
+
+ QSignalSpy finishedManagerSpy(&m_manager, SIGNAL(finished(QNetworkReply*)));
+
+ foreach (QNetworkRequest request, requests) {
+ request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true);
+ QNetworkReply *reply = m_manager.get(request);
+ QObject::connect(reply, SIGNAL(finished()), this, SLOT(spdyReplyFinished()));
+ replies << reply;
+ QSignalSpy *metaDataChangedSpy = new QSignalSpy(reply, SIGNAL(metaDataChanged()));
+ metaDataChangedSpies << metaDataChangedSpy;
+ QSignalSpy *readyReadSpy = new QSignalSpy(reply, SIGNAL(readyRead()));
+ readyReadSpies << readyReadSpy;
+ QSignalSpy *finishedSpy = new QSignalSpy(reply, SIGNAL(finished()));
+ finishedSpies << finishedSpy;
+ }
+
+ QCOMPARE(requests.count(), replies.count());
+
+ QTestEventLoop::instance().enterLoop(15);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QCOMPARE(finishedManagerSpy.count(), requests.count());
+
+ for (int a = 0; a < replies.count(); ++a) {
+
+ QCOMPARE(replies.at(a)->sslConfiguration().nextProtocolNegotiationStatus(),
+ QSslConfiguration::NextProtocolNegotiationNegotiated);
+ QCOMPARE(replies.at(a)->sslConfiguration().nextNegotiatedProtocol(),
+ QByteArray(QSslConfiguration::NextProtocolSpdy3_0));
+
+ QCOMPARE(replies.at(a)->error(), QNetworkReply::NoError);
+ QCOMPARE(replies.at(a)->attribute(QNetworkRequest::SpdyWasUsedAttribute).toBool(), true);
+ QCOMPARE(replies.at(a)->attribute(QNetworkRequest::ConnectionEncryptedAttribute).toBool(), true);
+ QCOMPARE(replies.at(a)->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
+
+ QByteArray content = replies.at(a)->readAll();
+ QVERIFY(content.count() > 0);
+
+ QCOMPARE(metaDataChangedSpies.at(a)->count(), 1);
+ metaDataChangedSpies.at(a)->deleteLater();
+
+ QCOMPARE(finishedSpies.at(a)->count(), 1);
+ finishedSpies.at(a)->deleteLater();
+
+ QVERIFY(readyReadSpies.at(a)->count() > 0);
+ readyReadSpies.at(a)->deleteLater();
+
+ replies.at(a)->deleteLater();
+ }
+#else
+ QSKIP("Qt built withouth OpenSSL, or the OpenSSL version is too old");
+#endif // defined(QT_BUILD_INTERNAL) && !defined(QT_NO_SSL) ...
+}
+
QTEST_MAIN(tst_qnetworkreply)
#include "main.moc"