/**************************************************************************** ** ** Copyright (C) 2014 BlackBerry Limited. All rights reserved. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #if defined(QT_BUILD_INTERNAL) && !defined(QT_NO_OPENSSL) #include #endif // QT_BUILD_INTERNAL && !QT_NO_OPENSSL #include "../../../network-settings.h" Q_DECLARE_METATYPE(QAuthenticator*) class tst_Spdy: public QObject { Q_OBJECT public: tst_Spdy(); ~tst_Spdy(); private Q_SLOTS: void initTestCase(); void settingsAndNegotiation_data(); void settingsAndNegotiation(); #ifndef QT_NO_NETWORKPROXY void download_data(); void download(); #endif // !QT_NO_NETWORKPROXY void headerFields(); #ifndef QT_NO_NETWORKPROXY void upload_data(); void upload(); void errors_data(); void errors(); #endif // !QT_NO_NETWORKPROXY void multipleRequests_data(); void multipleRequests(); private: QNetworkAccessManager m_manager; int m_multipleRequestsCount; int m_multipleRepliesFinishedCount; const QString m_rfc3252FilePath; protected Q_SLOTS: void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *authenticator); void multipleRequestsFinishedSlot(); }; tst_Spdy::tst_Spdy() : m_rfc3252FilePath(QFINDTESTDATA("../qnetworkreply/rfc3252.txt")) { #if defined(QT_BUILD_INTERNAL) && !defined(QT_NO_SSL) && OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) qRegisterMetaType(); // for QSignalSpy qRegisterMetaType(); 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::initTestCase() { QVERIFY(!m_rfc3252FilePath.isEmpty()); QVERIFY(QtNetworkSettings::verifyTestNetworkSettings()); } void tst_Spdy::settingsAndNegotiation_data() { QTest::addColumn("url"); QTest::addColumn("setAttribute"); QTest::addColumn("enabled"); QTest::addColumn("expectedProtocol"); QTest::addColumn("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); 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"); } #ifndef QT_NO_NETWORKPROXY void tst_Spdy::download_data() { QTest::addColumn("url"); QTest::addColumn("fileName"); QTest::addColumn("proxy"); QTest::newRow("mediumfile") << QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt") << m_rfc3252FilePath << 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") << m_rfc3252FilePath << QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3128); QTest::newRow("mediumfile-http-proxy-auth") << QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt") << m_rfc3252FilePath << QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3129); QTest::newRow("mediumfile-socks-proxy") << QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt") << m_rfc3252FilePath << QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1080); QTest::newRow("mediumfile-socks-proxy-auth") << QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt") << m_rfc3252FilePath << 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 } #endif // !QT_NO_NETWORKPROXY 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'); } #ifndef QT_NO_NETWORKPROXY void tst_Spdy::upload_data() { QTest::addColumn("url"); QTest::addColumn("data"); QTest::addColumn("uploadMethod"); QTest::addColumn("uploadObject"); QTest::addColumn("md5sum"); QTest::addColumn("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(m_rfc3252FilePath); file->open(QIODevice::ReadOnly); QTest::newRow("file-26K") << md5Url << QByteArray() << QByteArray("POST") << static_cast(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(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(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(uploadObject)) { reply = m_manager.post(request, device); } else if ((multiPart = qobject_cast(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("url"); QTest::addColumn("proxy"); QTest::addColumn("ignoreSslErrors"); QTest::addColumn("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(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 } #endif // !QT_NO_NETWORKPROXY void tst_Spdy::multipleRequests_data() { QTest::addColumn >("urls"); QString baseUrl = "https://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/echo.cgi?"; QList 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, urls); m_multipleRequestsCount = urls.count(); m_multipleRepliesFinishedCount = 0; QList replies; QList metaDataChangedSpies; QList readyReadSpies; QList 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"