summaryrefslogtreecommitdiffstats
path: root/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp')
-rw-r--r--tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp1498
1 files changed, 1135 insertions, 363 deletions
diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
index 2ebeff8689..a4a05b18f5 100644
--- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
+++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtNetwork/qtnetworkglobal.h>
@@ -39,19 +14,25 @@
#include <QWaitCondition>
#include <QScopeGuard>
#include <QBuffer>
+#include <QMap>
#include <QtCore/QCryptographicHash>
#include <QtCore/QDataStream>
-#include <QtCore/QUrl>
+#include <QtCore/QDateTime>
#include <QtCore/QEventLoop>
#include <QtCore/QElapsedTimer>
#include <QtCore/QFile>
+#include <QtCore/QList>
#include <QtCore/QRandomGenerator>
#include <QtCore/QRegularExpression>
#include <QtCore/QRegularExpressionMatch>
+#include <QtCore/QSet>
#include <QtCore/QSharedPointer>
#include <QtCore/QScopedPointer>
#include <QtCore/QTemporaryFile>
+#include <QtCore/QTimeZone>
+#include <QtCore/QUrl>
+
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QLocalSocket>
@@ -66,6 +47,7 @@
#include <QtNetwork/qnetworkdiskcache.h>
#include <QtNetwork/qnetworkrequest.h>
#include <QtNetwork/qnetworkreply.h>
+#include <QtNetwork/QHttp1Configuration>
#include <QtNetwork/qnetworkcookie.h>
#include <QtNetwork/QNetworkCookieJar>
#include <QtNetwork/QHttpPart>
@@ -86,6 +68,9 @@
Q_DECLARE_METATYPE(QSharedPointer<char>)
#endif
+#include <memory>
+#include <optional>
+
#ifdef Q_OS_UNIX
# include <sys/types.h>
# include <unistd.h> // for getuid()
@@ -105,6 +90,9 @@ Q_DECLARE_METATYPE(QNetworkProxyQuery)
typedef QSharedPointer<QNetworkReply> QNetworkReplyPtr;
+using namespace Qt::StringLiterals;
+using namespace std::chrono_literals;
+
#if QT_CONFIG(ssl)
QT_BEGIN_NAMESPACE
// Technically, a workaround, and only needed for OpenSSL:
@@ -146,6 +134,29 @@ class tst_QNetworkReply: public QObject
"\r\n";
return s;
}
+ static QString movedReplyStr() {
+ QString s = "HTTP/1.1 301 Moved Permanently\r\n"
+ "Content-Type: text/plain\r\n"
+ "location: %1\r\n"
+ "\r\n";
+ return s;
+ }
+
+ static QString foundReplyStr() {
+ QString s = "HTTP/1.1 302 Found\r\n"
+ "Content-Type: text/plain\r\n"
+ "location: %1\r\n"
+ "\r\n";
+ return s;
+ }
+
+ static QString permRedirectReplyStr() {
+ QString s = "HTTP/1.1 308 Permanent Redirect\r\n"
+ "Content-Type: text/plain\r\n"
+ "location: %1\r\n"
+ "\r\n";
+ return s;
+ }
static const QByteArray httpEmpty200Response;
static const QString filePermissionFileName;
@@ -229,6 +240,12 @@ private Q_SLOTS:
void getFromFtpAfterError(); // QTBUG-40797
void getFromHttp_data();
void getFromHttp();
+ void getWithBodyFromHttp_data();
+ void getWithBodyFromHttp();
+ void getWithAndWithoutBodyFromHttp_data();
+ void getWithAndWithoutBodyFromHttp();
+ void getWithBodyRedirected_data();
+ void getWithBodyRedirected();
void getErrors_data();
void getErrors();
#if QT_CONFIG(networkproxy)
@@ -246,6 +263,8 @@ private Q_SLOTS:
void putToHttpSynchronous();
void putToHttpMultipart_data();
void putToHttpMultipart();
+ void putWithoutBody();
+ void putWithoutBody_data();
void postToHttp_data();
void postToHttp();
void postToHttpSynchronous_data();
@@ -253,6 +272,8 @@ private Q_SLOTS:
void postToHttpMultipart_data();
void postToHttpMultipart();
void multipartSkipIndices(); // QTBUG-32534
+ void postWithoutBody_data();
+ void postWithoutBody();
#if QT_CONFIG(ssl)
void putToHttps_data();
void putToHttps();
@@ -280,6 +301,7 @@ private Q_SLOTS:
void ioGetFromFileSpecial();
void ioGetFromFile_data();
void ioGetFromFile();
+ void ioGetFromFileUrl();
void ioGetFromFtp_data();
void ioGetFromFtp();
void ioGetFromFtpWithReuse();
@@ -304,8 +326,8 @@ private Q_SLOTS:
#endif
void ioGetFromHttpBrokenServer_data();
void ioGetFromHttpBrokenServer();
- void ioGetFromHttpStatus100_data();
- void ioGetFromHttpStatus100();
+ void ioGetFromHttpStatusInformational_data();
+ void ioGetFromHttpStatusInformational();
void ioGetFromHttpNoHeaders_data();
void ioGetFromHttpNoHeaders();
void ioGetFromHttpWithCache_data();
@@ -462,6 +484,9 @@ private Q_SLOTS:
void varyingCacheExpiry_data();
void varyingCacheExpiry();
+ void amountOfHttp1ConnectionsQtbug25280_data();
+ void amountOfHttp1ConnectionsQtbug25280();
+
void dontInsertPartialContentIntoTheCache();
void httpUserAgent();
@@ -496,6 +521,7 @@ private Q_SLOTS:
void ioHttpCookiesDuringRedirect();
void ioHttpRedirect_data();
void ioHttpRedirect();
+ void ioHttpRedirectWithCache();
void ioHttpRedirectFromLocalToRemote();
void ioHttpRedirectPostPut_data();
void ioHttpRedirectPostPut();
@@ -514,8 +540,8 @@ private Q_SLOTS:
void autoDeleteReplies_data();
void autoDeleteReplies();
- void getWithTimeout();
- void postWithTimeout();
+ void requestWithTimeout_data();
+ void requestWithTimeout();
void moreActivitySignals_data();
void moreActivitySignals();
@@ -528,6 +554,16 @@ private Q_SLOTS:
void cacheWithContentEncoding();
void downloadProgressWithContentEncoding_data();
void downloadProgressWithContentEncoding();
+ void contentEncodingError_data();
+ void contentEncodingError();
+ void compressedReadyRead();
+ void notFoundWithCompression_data();
+ void notFoundWithCompression();
+
+ void qtbug68821proxyError_data();
+ void qtbug68821proxyError();
+
+ void abortAndError();
// NOTE: This test must be last!
void parentingRepliesToTheApp();
@@ -613,7 +649,8 @@ public:
int totalConnections;
bool stopTransfer = false;
- bool hasContent = false;
+ bool checkedContentLength = false;
+ bool foundContentLength = false;
int contentRead = 0;
int contentLength = 0;
@@ -645,6 +682,7 @@ public:
{
contentLength = 0;
receivedData.clear();
+ foundContentLength = false;
}
protected:
@@ -701,8 +739,13 @@ private:
void parseContentLength()
{
- int index = receivedData.indexOf("Content-Length:");
- index += sizeof("Content-Length:") - 1;
+ int index = receivedData.indexOf("content-length:");
+ if (index == -1)
+ return;
+
+ foundContentLength = true;
+
+ index += sizeof("content-length:") - 1;
const auto end = std::find(receivedData.cbegin() + index, receivedData.cend(), '\r');
auto num = receivedData.mid(index, std::distance(receivedData.cbegin() + index, end));
bool ok;
@@ -742,12 +785,14 @@ public slots:
if (doubleEndlPos != -1) {
const int endOfHeader = doubleEndlPos + 4;
- hasContent = receivedData.startsWith("POST") || receivedData.startsWith("PUT")
- || receivedData.startsWith("CUSTOM_WITH_PAYLOAD");
- if (hasContent && contentLength == 0)
+ contentRead = receivedData.size() - endOfHeader;
+
+ if (!checkedContentLength) {
parseContentLength();
- contentRead = receivedData.length() - endOfHeader;
- if (hasContent && contentRead < contentLength)
+ checkedContentLength = true;
+ }
+
+ if (contentRead < contentLength)
return;
// multiple requests incoming. remove the bytes of the current one
@@ -848,7 +893,7 @@ public:
qint64 cacheSize() const override
{
qint64 total = 0;
- foreach (const CachedContent &entry, cache)
+ for (const auto &[_, entry] : cache.asKeyValueRange())
total += entry.second.size();
return total;
}
@@ -1473,11 +1518,11 @@ QString tst_QNetworkReply::runSimpleRequest(QNetworkAccessManager::Operation op,
while (!reply->isFinished()) {
QTimer::singleShot(20000, loop, SLOT(quit()));
code = loop->exec();
- if (count == spy.count() && !reply->isFinished()) {
+ if (count == spy.size() && !reply->isFinished()) {
code = Timeout;
break;
}
- count = spy.count();
+ count = spy.size();
}
delete loop;
loop = 0;
@@ -1543,11 +1588,11 @@ int tst_QNetworkReply::waitForFinish(QNetworkReplyPtr &reply)
QSignalSpy spy(reply.data(), SIGNAL(downloadProgress(qint64,qint64)));
while (!reply->isFinished()) {
QTimer::singleShot(5000, loop, SLOT(quit()));
- if (loop->exec() == Timeout && count == spy.count() && !reply->isFinished()) {
+ if (loop->exec() == Timeout && count == spy.size() && !reply->isFinished()) {
returnCode = Timeout;
break;
}
- count = spy.count();
+ count = spy.size();
}
delete loop;
loop = 0;
@@ -1575,8 +1620,10 @@ void tst_QNetworkReply::initTestCase()
testDataDir = QCoreApplication::applicationDirPath();
#if defined(QT_TEST_SERVER)
- QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpServerName(), 21));
- QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpProxyServerName(), 2121));
+ if (ftpSupported) {
+ QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpServerName(), 21));
+ QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpProxyServerName(), 2121));
+ }
QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpServerName(), 80));
QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpServerName(), 443));
QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3128));
@@ -1989,6 +2036,253 @@ void tst_QNetworkReply::getFromHttp()
QCOMPARE(reply->readAll(), reference.readAll());
}
+void tst_QNetworkReply::getWithBodyFromHttp_data()
+{
+ QTest::addColumn<QByteArray>("dataFromClientToServer");
+ QTest::addColumn<bool>("useDevice");
+ QTest::newRow("with-bytearray") << QByteArray("Body 1") << false;
+ QTest::newRow("with-bytearray2") << QByteArray("Body 2") << false;
+ QTest::newRow("with-bytearray3") << QByteArray("Body 3") << false;
+ QTest::newRow("with-device") << QByteArray("Body 1") << true;
+ QTest::newRow("with-device2") << QByteArray("Body 2") << true;
+ QTest::newRow("with-device3") << QByteArray("Body 3") << true;
+}
+
+void tst_QNetworkReply::getWithBodyFromHttp()
+{
+ QFETCH(QByteArray, dataFromClientToServer);
+ QFETCH(bool, useDevice);
+
+ QBuffer buff;
+ buff.setData(dataFromClientToServer);
+ buff.open(QIODevice::ReadOnly);
+
+ QByteArray dataFromServerToClient = QByteArray("Long first line\r\nLong second line");
+ QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: ");
+ httpResponse += QByteArray::number(dataFromServerToClient.size());
+ httpResponse += "\r\n\r\n";
+ httpResponse += dataFromServerToClient;
+
+ MiniHttpServer server(httpResponse);
+ server.doClose = true;
+
+ QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
+ QNetworkReplyPtr reply;
+
+ if (useDevice)
+ reply.reset(manager.get(request, &buff));
+ else
+ reply.reset(manager.get(request, dataFromClientToServer));
+
+ QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply));
+ QCOMPARE(server.contentLength, dataFromClientToServer.size());
+ QCOMPARE(server.receivedData.right(dataFromClientToServer.size()), dataFromClientToServer);
+ QByteArray content = reply->readAll();
+ QCOMPARE(content, dataFromServerToClient);
+}
+
+void tst_QNetworkReply::getWithAndWithoutBodyFromHttp_data()
+{
+ QTest::addColumn<QByteArray>("dataFromClientToServer");
+ QTest::addColumn<bool>("alwaysCache");
+ QTest::addColumn<tst_QNetworkReply::RunSimpleRequestReturn>("requestReturn");
+ QTest::addColumn<bool>("useDevice");
+ QTest::newRow("with-bytearray") << QByteArray("Body 1") << false << Success << false;
+ QTest::newRow("with-bytearray2") << QByteArray("Body 2") << false << Success << false;
+ QTest::newRow("with-bytearray3") << QByteArray("Body 3") << false << Success << false;
+ QTest::newRow("with-bytearray-cache") << QByteArray("Body 1") << true << Failure << false;
+ QTest::newRow("with-bytearray-cache2") << QByteArray("Body 2") << true << Failure << false;
+ QTest::newRow("with-bytearray-cache3") << QByteArray("Body 3") << true << Failure << false;
+ QTest::newRow("with-device") << QByteArray("Body 1") << false << Success << true;
+ QTest::newRow("with-device2") << QByteArray("Body 2") << false << Success << true;
+ QTest::newRow("with-device3") << QByteArray("Body 3") << false << Success << true;
+ QTest::newRow("with-device-cache") << QByteArray("Body 1") << true << Failure << true;
+ QTest::newRow("with-device-cache2") << QByteArray("Body 2") << true << Failure << true;
+ QTest::newRow("with-device-cache3") << QByteArray("Body 3") << true << Failure << true;
+}
+
+void tst_QNetworkReply::getWithAndWithoutBodyFromHttp()
+{
+ QFETCH(QByteArray, dataFromClientToServer);
+ QFETCH(bool, alwaysCache);
+ QFETCH(tst_QNetworkReply::RunSimpleRequestReturn, requestReturn);
+ QFETCH(bool, useDevice);
+
+ QBuffer buff;
+ buff.setData(dataFromClientToServer);
+ buff.open(QIODevice::ReadOnly);
+
+ QNetworkAccessManager qnam;
+ MyMemoryCache *memoryCache = new MyMemoryCache(&qnam);
+ qnam.setCache(memoryCache);
+
+ const int sizeOfDataFromServerToClient =3;
+ QByteArray dataFromServerToClient1 = QByteArray("aaa");
+ QByteArray dataFromServerToClient2 = QByteArray("bbb");
+ QByteArray dataFromServerToClient3 = QByteArray("ccc");
+
+ QByteArray baseHttpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: ");
+ baseHttpResponse += QByteArray::number(sizeOfDataFromServerToClient);
+ baseHttpResponse += "\r\n\r\n";
+
+ MiniHttpServer server(baseHttpResponse + dataFromServerToClient1);
+ server.doClose = true;
+
+ QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
+
+ // Send request without body
+ QNetworkReplyPtr reply(manager.get(request));
+ QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply));
+ QByteArray content = reply->readAll();
+ QCOMPARE(content, dataFromServerToClient1);
+
+ if (alwaysCache) {
+ request.setAttribute(QNetworkRequest::CacheLoadControlAttribute,
+ QNetworkRequest::AlwaysCache);
+ }
+
+ server.dataToTransmit = baseHttpResponse + dataFromServerToClient2;
+
+ // Send request with body
+ QNetworkReplyPtr reply2;
+ if (useDevice)
+ reply2.reset(manager.get(request, &buff));
+ else
+ reply2.reset(manager.get(request, dataFromClientToServer));
+
+ QVERIFY2(waitForFinish(reply2) == requestReturn, msgWaitForFinished(reply2));
+ content = reply2->readAll();
+
+ if (alwaysCache)
+ QVERIFY(content.isEmpty());
+ else
+ QCOMPARE(content, dataFromServerToClient2);
+
+ QCOMPARE(reply2->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(), false);
+
+ if (alwaysCache) {
+ request.setAttribute(QNetworkRequest::CacheLoadControlAttribute,
+ QNetworkRequest::PreferNetwork);
+ }
+
+ server.dataToTransmit = baseHttpResponse + dataFromServerToClient3;
+
+ // Send another request without a body
+ QNetworkReplyPtr reply3(manager.get(request));
+ QVERIFY2(waitForFinish(reply3) == Success, msgWaitForFinished(reply3));
+ content = reply3->readAll();
+ QCOMPARE(content, dataFromServerToClient3);
+ QCOMPARE(reply3->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(), false);
+}
+
+void tst_QNetworkReply::getWithBodyRedirected_data()
+{
+ QTest::addColumn<QByteArray>("dataFromClientToServer");
+ QTest::addColumn<bool>("useDevice");
+ QTest::addColumn<int>("status");
+ QTest::newRow("with-bytearray - 301") << QByteArray("Body 1") << false << 301;
+ QTest::newRow("with-bytearray2 - 301") << QByteArray("Body 2") << false << 301;
+ QTest::newRow("with-bytearray3 - 301") << QByteArray("Body 3") << false << 301;
+ QTest::newRow("with-device - 301") << QByteArray("Body 1") << true << 301;
+ QTest::newRow("with-device2 - 301") << QByteArray("Body 2") << true << 301;
+ QTest::newRow("with-device3 - 301") << QByteArray("Body 3") << true << 301;
+ QTest::newRow("with-bytearray - 302") << QByteArray("Body 1") << false << 302;
+ QTest::newRow("with-bytearray2 - 302") << QByteArray("Body 2") << false << 302;
+ QTest::newRow("with-bytearray3 - 302") << QByteArray("Body 3") << false << 302;
+ QTest::newRow("with-device - 302") << QByteArray("Body 1") << true << 302;
+ QTest::newRow("with-device2 - 302") << QByteArray("Body 2") << true << 302;
+ QTest::newRow("with-device3 - 302") << QByteArray("Body 3") << true << 302;
+ QTest::newRow("with-bytearray - 307") << QByteArray("Body 1") << false << 307;
+ QTest::newRow("with-bytearray2 - 307") << QByteArray("Body 2") << false << 307;
+ QTest::newRow("with-bytearray3 - 307") << QByteArray("Body 3") << false << 307;
+ QTest::newRow("with-device - 307") << QByteArray("Body 1") << true << 307;
+ QTest::newRow("with-device2 - 307") << QByteArray("Body 2") << true << 307;
+ QTest::newRow("with-device3 - 307") << QByteArray("Body 3") << true << 307;
+ QTest::newRow("with-bytearray - 308") << QByteArray("Body 1") << false << 308;
+ QTest::newRow("with-bytearray2 - 308") << QByteArray("Body 2") << false << 308;
+ QTest::newRow("with-bytearray3 - 308") << QByteArray("Body 3") << false << 308;
+ QTest::newRow("with-device - 308") << QByteArray("Body 1") << true << 308;
+ QTest::newRow("with-device2 - 308") << QByteArray("Body 2") << true << 308;
+ QTest::newRow("with-device3 - 308") << QByteArray("Body 3") << true << 308;
+}
+
+void tst_QNetworkReply::getWithBodyRedirected()
+{
+ QFETCH(QByteArray, dataFromClientToServer);
+ QFETCH(bool, useDevice);
+ QFETCH(int, status);
+
+ QBuffer buff;
+ buff.setData(dataFromClientToServer);
+ buff.open(QIODevice::ReadOnly);
+
+ QUrl localhost = QUrl("http://localhost");
+
+ // Setup server to which the second server will redirect to
+ MiniHttpServer server2(httpEmpty200Response);
+
+ QUrl redirectUrl = QUrl(localhost);
+ redirectUrl.setPort(server2.serverPort());
+
+ QByteArray redirectReply;
+ switch (status) {
+ case 301: redirectReply =
+ foundReplyStr().arg(QString(redirectUrl.toEncoded())).toLatin1(); break;
+ case 302: redirectReply =
+ movedReplyStr().arg(QString(redirectUrl.toEncoded())).toLatin1(); break;
+ case 307: redirectReply =
+ tempRedirectReplyStr().arg(QString(redirectUrl.toEncoded())).toLatin1(); break;
+ case 308: redirectReply =
+ permRedirectReplyStr().arg(QString(redirectUrl.toEncoded())).toLatin1(); break;
+ default: QFAIL("Unexpected status code"); break;
+ }
+
+ // Setup redirect server
+ MiniHttpServer server(redirectReply);
+
+ localhost.setPort(server.serverPort());
+ QNetworkRequest request(localhost);
+ request.setAttribute(QNetworkRequest::RedirectPolicyAttribute,
+ QNetworkRequest::NoLessSafeRedirectPolicy);
+
+ QNetworkReplyPtr reply;
+ if (useDevice)
+ reply.reset(manager.get(request, &buff));
+ else
+ reply.reset(manager.get(request, dataFromClientToServer));
+
+ QSignalSpy redSpy(reply.data(), SIGNAL(redirected(QUrl)));
+ QSignalSpy finSpy(reply.data(), SIGNAL(finished()));
+
+ QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply));
+
+ // Redirected and finished should be emitted exactly once
+ QCOMPARE(redSpy.size(), 1);
+ QCOMPARE(finSpy.size(), 1);
+
+ // Original URL should not be changed after redirect
+ QCOMPARE(request.url(), localhost);
+
+ // Verify Redirect url
+ QList<QVariant> args = redSpy.takeFirst();
+ QCOMPARE(args.at(0).toUrl(), redirectUrl);
+
+ // Reply url is set to the redirect url
+ QCOMPARE(reply->url(), redirectUrl);
+ QCOMPARE(reply->error(), QNetworkReply::NoError);
+ QVERIFY(validateRedirectedResponseHeaders(reply));
+
+ // Verify that the message body has arrived to the server
+ if (status > 302) {
+ QVERIFY(server2.contentLength != 0);
+ QCOMPARE(server2.contentLength, dataFromClientToServer.size());
+ QCOMPARE(server2.receivedData.right(dataFromClientToServer.size()), dataFromClientToServer);
+ } else {
+ // In these cases the message body should not reach the server
+ QVERIFY(server2.contentLength == 0);
+ }
+}
+
#if QT_CONFIG(networkproxy)
void tst_QNetworkReply::headFromHttp_data()
{
@@ -2008,7 +2302,7 @@ void tst_QNetworkReply::headFromHttp_data()
QString httpServer = QtNetworkSettings::httpServerName();
//testing proxies, mainly for the 407 response from http proxy
- for (int i = 0; i < proxies.count(); ++i) {
+ for (int i = 0; i < proxies.size(); ++i) {
QTest::newRow("rfc" + proxies.at(i).tag)
<< rfcsize
<< QUrl("http://" + httpServer + "/qtest/rfc3252.txt")
@@ -2290,9 +2584,9 @@ void tst_QNetworkReply::putToFtp()
QSignalSpy spy(r, SIGNAL(downloadProgress(qint64,qint64)));
while (!r->isFinished()) {
QTestEventLoop::instance().enterLoop(10);
- if (count == spy.count() && !r->isFinished())
+ if (count == spy.size() && !r->isFinished())
break;
- count = spy.count();
+ count = spy.size();
}
QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
@@ -2407,6 +2701,48 @@ void tst_QNetworkReply::putToHttpSynchronous()
QCOMPARE(uploadedData, data);
}
+void tst_QNetworkReply::putWithoutBody_data()
+{
+ QTest::addColumn<bool>("client_data");
+
+ QTest::newRow("client_has_data") << true;
+ QTest::newRow("client_does_not_have_data") << false;
+}
+
+void tst_QNetworkReply::putWithoutBody()
+{
+ QFETCH(bool, client_data);
+
+ QBuffer buff;
+
+ if (client_data) {
+ buff.setData("Dummy data from client to server");
+ buff.open(QIODevice::ReadOnly);
+ }
+
+ QByteArray dataFromServerToClient = QByteArray("Some ridiculous dummy data");
+ QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: ");
+ httpResponse += QByteArray::number(dataFromServerToClient.size());
+ httpResponse += "\r\n\r\n";
+ httpResponse += dataFromServerToClient;
+
+ MiniHttpServer server(httpResponse);
+ server.doClose = true;
+
+ QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
+ request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
+
+ QNetworkReplyPtr reply;
+ if (client_data)
+ reply.reset(manager.put(request, &buff));
+ else
+ reply.reset(manager.put(request, nullptr));
+
+ QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply));
+ QCOMPARE(server.foundContentLength, client_data);
+}
+
+
void tst_QNetworkReply::postToHttp_data()
{
putToFile_data();
@@ -2724,8 +3060,8 @@ void tst_QNetworkReply::postToHttpMultipart()
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);
+ QVERIFY(multiPart->boundary().size() > 20); // check that there is randomness after the "boundary_.oOo._" string
+ QVERIFY(multiPart->boundary().size() < 70);
QByteArray replyData = reply->readAll();
expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n");
@@ -2776,6 +3112,47 @@ void tst_QNetworkReply::multipartSkipIndices() // QTBUG-32534
multiPart->deleteLater();
}
+void tst_QNetworkReply::postWithoutBody_data()
+{
+ QTest::addColumn<bool>("client_data");
+
+ QTest::newRow("client_has_data") << true;
+ QTest::newRow("client_does_not_have_data") << false;
+}
+
+void tst_QNetworkReply::postWithoutBody()
+{
+ QFETCH(bool, client_data);
+
+ QBuffer buff;
+
+ if (client_data) {
+ buff.setData("Dummy data from client to server");
+ buff.open(QIODevice::ReadOnly);
+ }
+
+ QByteArray dataFromServerToClient = QByteArray("Some ridiculous dummy data");
+ QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: ");
+ httpResponse += QByteArray::number(dataFromServerToClient.size());
+ httpResponse += "\r\n\r\n";
+ httpResponse += dataFromServerToClient;
+
+ MiniHttpServer server(httpResponse);
+ server.doClose = true;
+
+ QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
+ request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
+
+ QNetworkReplyPtr reply;
+ if (client_data)
+ reply.reset(manager.post(request, &buff));
+ else
+ reply.reset(manager.post(request, nullptr));
+
+ QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply));
+ QCOMPARE(server.foundContentLength, client_data);
+}
+
void tst_QNetworkReply::putToHttpMultipart_data()
{
postToHttpMultipart_data();
@@ -2812,8 +3189,8 @@ void tst_QNetworkReply::putToHttpMultipart()
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);
+ QVERIFY(multiPart->boundary().size() > 20); // check that there is randomness after the "boundary_.oOo._" string
+ QVERIFY(multiPart->boundary().size() < 70);
QByteArray replyData = reply->readAll();
expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n");
@@ -3030,8 +3407,8 @@ void tst_QNetworkReply::postToHttpsMultipart()
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);
+ QVERIFY(multiPart->boundary().size() > 20); // check that there is randomness after the "boundary_.oOo._" string
+ QVERIFY(multiPart->boundary().size() < 70);
QByteArray replyData = reply->readAll();
expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n");
@@ -3167,7 +3544,7 @@ void tst_QNetworkReply::connectToIPv6Address()
if (!QtNetworkSettings::hasIPv6())
QSKIP("system doesn't support ipv6!");
- QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: ");
+ QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\ncontent-length: ");
httpResponse += QByteArray::number(dataToSend.size());
httpResponse += "\r\n\r\n";
httpResponse += dataToSend;
@@ -3182,7 +3559,7 @@ void tst_QNetworkReply::connectToIPv6Address()
QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply));
QByteArray content = reply->readAll();
//qDebug() << server.receivedData;
- QByteArray hostinfo = "\r\nHost: " + hostfield + ':' + QByteArray::number(server.serverPort()) + "\r\n";
+ QByteArray hostinfo = "\r\nhost: " + hostfield + ':' + QByteArray::number(server.serverPort()) + "\r\n";
QVERIFY(server.receivedData.contains(hostinfo));
QCOMPARE(content, dataToSend);
QCOMPARE(reply->url(), request.url());
@@ -3344,6 +3721,18 @@ void tst_QNetworkReply::ioGetFromFile()
QCOMPARE(reader.data, data);
}
+void tst_QNetworkReply::ioGetFromFileUrl()
+{
+ // This immediately fails on non-windows platforms:
+ QNetworkRequest request(QUrl("file://unc-server/some/path"));
+ QNetworkReplyPtr reply(manager.get(request));
+ QSignalSpy finishedSpy(reply.get(), &QNetworkReply::finished);
+ // QTBUG-105618: This would, on non-Windows platforms, never happen because the signal
+ // was emitted before the constructor finished, leaving no chance at all to connect to the
+ // signal
+ QVERIFY(finishedSpy.wait());
+}
+
void tst_QNetworkReply::ioGetFromFtp_data()
{
if (!ftpSupported)
@@ -3361,7 +3750,9 @@ void tst_QNetworkReply::ioGetFromFtp()
{
QFETCH(QString, fileName);
QFile reference(fileName);
- reference.open(QIODevice::ReadOnly); // will fail for bigfile
+ const bool ok = reference.open(QIODevice::ReadOnly); // will fail for bigfile
+ if (fileName != "bigfile")
+ QVERIFY(ok);
QNetworkRequest request("ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/" + fileName);
QNetworkReplyPtr reply(manager.get(request));
@@ -3386,7 +3777,7 @@ void tst_QNetworkReply::ioGetFromFtpWithReuse()
QSKIP("FTP is not supported");
QString fileName = testDataDir + "/rfc3252.txt";
QFile reference(fileName);
- reference.open(QIODevice::ReadOnly);
+ QVERIFY(reference.open(QIODevice::ReadOnly));
QNetworkRequest request(QUrl("ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt"));
@@ -3516,7 +3907,7 @@ void tst_QNetworkReply::ioGetFromHttpWithAuth_data()
QTest::addColumn<int>("expectedAuth");
QFile reference(testDataDir + "/rfc3252.txt");
- reference.open(QIODevice::ReadOnly);
+ QVERIFY(reference.open(QIODevice::ReadOnly));
QByteArray referenceData = reference.readAll();
QString httpServer = QtNetworkSettings::httpServerName();
QTest::newRow("basic")
@@ -3590,7 +3981,7 @@ void tst_QNetworkReply::ioGetFromHttpWithAuth()
QCOMPARE(reader1.data, expectedData);
QCOMPARE(reader2.data, expectedData);
- QCOMPARE(authspy.count(), (expectedAuth ? 1 : 0));
+ QCOMPARE(authspy.size(), (expectedAuth ? 1 : 0));
expectedAuth = qMax(0, expectedAuth - 1);
}
@@ -3611,7 +4002,7 @@ void tst_QNetworkReply::ioGetFromHttpWithAuth()
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
QCOMPARE(reader.data, expectedData);
- QCOMPARE(authspy.count(), (expectedAuth ? 1 : 0));
+ QCOMPARE(authspy.size(), (expectedAuth ? 1 : 0));
expectedAuth = qMax(0, expectedAuth - 1);
}
@@ -3628,7 +4019,7 @@ void tst_QNetworkReply::ioGetFromHttpWithAuth()
// bad credentials in a synchronous request should just fail
QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError);
} else {
- QCOMPARE(authspy.count(), 0);
+ QCOMPARE(authspy.size(), 0);
// we cannot use a data reader here, since that connects to the readyRead signal,
// just use readAll()
@@ -3654,7 +4045,7 @@ void tst_QNetworkReply::ioGetFromHttpWithAuth()
// bad credentials in a synchronous request should just fail
QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError);
} else {
- QCOMPARE(authspy.count(), 0);
+ QCOMPARE(authspy.size(), 0);
// we cannot use a data reader here, since that connects to the readyRead signal,
// just use readAll()
@@ -3680,7 +4071,7 @@ void tst_QNetworkReply::ioGetFromHttpWithAuthSynchronous()
QNetworkReplyPtr replySync(manager.get(request));
QVERIFY(replySync->isFinished()); // synchronous
QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError);
- QCOMPARE(authspy.count(), 0);
+ QCOMPARE(authspy.size(), 0);
QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 401);
}
@@ -3721,7 +4112,7 @@ void tst_QNetworkReply::ioGetFromHttpWithProxyAuth()
QCOMPARE(reader1.data, referenceData);
QCOMPARE(reader2.data, referenceData);
- QCOMPARE(authspy.count(), 1);
+ QCOMPARE(authspy.size(), 1);
}
reference.seek(0);
@@ -3744,7 +4135,7 @@ void tst_QNetworkReply::ioGetFromHttpWithProxyAuth()
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
QCOMPARE(reader.data, reference.readAll());
- QCOMPARE(authspy.count(), 0);
+ QCOMPARE(authspy.size(), 0);
}
// now check with synchronous calls:
@@ -3757,7 +4148,7 @@ void tst_QNetworkReply::ioGetFromHttpWithProxyAuth()
QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
QNetworkReplyPtr replySync(manager.get(request));
QVERIFY(replySync->isFinished()); // synchronous
- QCOMPARE(authspy.count(), 0);
+ QCOMPARE(authspy.size(), 0);
// we cannot use a data reader here, since that connects to the readyRead signal,
// just use readAll()
@@ -3785,7 +4176,7 @@ void tst_QNetworkReply::ioGetFromHttpWithProxyAuthSynchronous()
manager.setProxy(QNetworkProxy()); // reset
QVERIFY(replySync->isFinished()); // synchronous
QCOMPARE(replySync->error(), QNetworkReply::ProxyAuthenticationRequiredError);
- QCOMPARE(authspy.count(), 0);
+ QCOMPARE(authspy.size(), 0);
QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 407);
}
@@ -3817,7 +4208,7 @@ void tst_QNetworkReply::ioGetFromHttpWithSocksProxy()
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
QCOMPARE(reader.data, reference.readAll());
- QCOMPARE(authspy.count(), 0);
+ QCOMPARE(authspy.size(), 0);
}
// set an invalid proxy just to make sure that we can't load
@@ -3841,10 +4232,9 @@ void tst_QNetworkReply::ioGetFromHttpWithSocksProxy()
QVERIFY(reader.data.isEmpty());
QVERIFY(int(reply->error()) > 0);
- QEXPECT_FAIL("", "QTcpSocket doesn't return enough information yet", Continue);
QCOMPARE(int(reply->error()), int(QNetworkReply::ProxyConnectionRefusedError));
- QCOMPARE(authspy.count(), 0);
+ QCOMPARE(authspy.size(), 0);
}
}
#endif // QT_CONFIG(networkproxy)
@@ -3872,7 +4262,7 @@ void tst_QNetworkReply::ioGetFromHttpsWithSslErrors()
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
QCOMPARE(reader.data, reference.readAll());
- QCOMPARE(sslspy.count(), 1);
+ QCOMPARE(sslspy.size(), 1);
QVERIFY(!storedSslConfiguration.isNull());
QVERIFY(!reply->sslConfiguration().isNull());
@@ -3900,7 +4290,7 @@ void tst_QNetworkReply::ioGetFromHttpsWithIgnoreSslErrors()
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
QCOMPARE(reader.data, reference.readAll());
- QCOMPARE(sslspy.count(), 1);
+ QCOMPARE(sslspy.size(), 1);
QVERIFY(!storedSslConfiguration.isNull());
QVERIFY(!reply->sslConfiguration().isNull());
@@ -3923,7 +4313,7 @@ void tst_QNetworkReply::ioGetFromHttpsWithSslHandshakeError()
QCOMPARE(waitForFinish(reply), int(Failure));
QCOMPARE(reply->error(), QNetworkReply::SslHandshakeFailedError);
- QCOMPARE(sslspy.count(), 0);
+ QCOMPARE(sslspy.size(), 0);
}
#endif
@@ -3981,11 +4371,11 @@ void tst_QNetworkReply::ioGetFromHttpBrokenServer()
QCOMPARE(waitForFinish(reply), int(Failure));
QCOMPARE(reply->url(), request.url());
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QVERIFY(reply->error() != QNetworkReply::NoError);
}
-void tst_QNetworkReply::ioGetFromHttpStatus100_data()
+void tst_QNetworkReply::ioGetFromHttpStatusInformational_data()
{
QTest::addColumn<QByteArray>("dataToSend");
QTest::addColumn<int>("statusCode");
@@ -3996,9 +4386,25 @@ void tst_QNetworkReply::ioGetFromHttpStatus100_data()
QTest::newRow("minimal+404") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 204 No Content\r\n\r\n") << 204;
QTest::newRow("with_headers") << QByteArray("HTTP/1.1 100 Continue\r\nBla: x\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200;
QTest::newRow("with_headers2") << QByteArray("HTTP/1.1 100 Continue\nBla: x\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200;
+
+ QTest::newRow("normal-custom") << QByteArray("HTTP/1.1 133 Custom\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200;
+ QTest::newRow("minimal-custom") << QByteArray("HTTP/1.1 133 Custom\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200;
+ QTest::newRow("minimal2-custom") << QByteArray("HTTP/1.1 133 Custom\n\nHTTP/1.0 200 OK\r\n\r\n") << 200;
+ QTest::newRow("minimal3-custom") << QByteArray("HTTP/1.1 133 Custom\n\nHTTP/1.0 200 OK\n\n") << 200;
+ QTest::newRow("minimal+404-custom") << QByteArray("HTTP/1.1 133 Custom\n\nHTTP/1.0 204 No Content\r\n\r\n") << 204;
+ QTest::newRow("with_headers-custom") << QByteArray("HTTP/1.1 133 Custom\r\nBla: x\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200;
+ QTest::newRow("with_headers2-custom") << QByteArray("HTTP/1.1 133 Custom\nBla: x\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200;
+
+ QTest::newRow("normal-custom2") << QByteArray("HTTP/1.1 179 Custom2\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200;
+ QTest::newRow("minimal-custom2") << QByteArray("HTTP/1.1 179 Custom2\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200;
+ QTest::newRow("minimal2-custom2") << QByteArray("HTTP/1.1 179 Custom2\n\nHTTP/1.0 200 OK\r\n\r\n") << 200;
+ QTest::newRow("minimal3-custom2") << QByteArray("HTTP/1.1 179 Custom2\n\nHTTP/1.0 200 OK\n\n") << 200;
+ QTest::newRow("minimal+404-custom2") << QByteArray("HTTP/1.1 179 Custom2\n\nHTTP/1.0 204 No Content\r\n\r\n") << 204;
+ QTest::newRow("with_headers-custom2") << QByteArray("HTTP/1.1 179 Custom2\r\nBla: x\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200;
+ QTest::newRow("with_headers2-custom2") << QByteArray("HTTP/1.1 179 Custom2\nBla: x\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200;
}
-void tst_QNetworkReply::ioGetFromHttpStatus100()
+void tst_QNetworkReply::ioGetFromHttpStatusInformational()
{
QFETCH(QByteArray, dataToSend);
QFETCH(int, statusCode);
@@ -4317,15 +4723,15 @@ void tst_QNetworkReply::ioGetWithManyProxies_data()
// Tests that fail:
- // HTTP request with FTP caching proxy
- proxyList.clear();
- proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121);
- QTest::newRow("http-on-ftp")
- << proxyList << QNetworkProxy()
- << "http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt"
- << QNetworkReply::ProxyNotFoundError;
-
if (ftpSupported) {
+ // HTTP request with FTP caching proxy
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121);
+ QTest::newRow("http-on-ftp")
+ << proxyList << QNetworkProxy()
+ << "http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt"
+ << QNetworkReply::ProxyNotFoundError;
+
// FTP request with HTTP caching proxy
proxyList.clear();
proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy,
@@ -4356,13 +4762,15 @@ void tst_QNetworkReply::ioGetWithManyProxies_data()
<< "https://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt"
<< QNetworkReply::ProxyNotFoundError;
- // HTTPS with FTP caching proxy
- proxyList.clear();
- proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121);
- QTest::newRow("https-on-ftp")
- << proxyList << QNetworkProxy()
- << "https://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt"
- << QNetworkReply::ProxyNotFoundError;
+ if (ftpSupported) {
+ // HTTPS with FTP caching proxy
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121);
+ QTest::newRow("https-on-ftp")
+ << proxyList << QNetworkProxy()
+ << "https://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt"
+ << QNetworkReply::ProxyNotFoundError;
+ }
#endif
// Complex requests:
@@ -4385,15 +4793,17 @@ void tst_QNetworkReply::ioGetWithManyProxies_data()
<< "http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt"
<< QNetworkReply::NoError;
- // HTTP request with FTP + HTTP + SOCKS
- proxyList.clear();
- proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121)
- << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129)
- << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1081);
- QTest::newRow("http-on-ftp+http+socks")
- << proxyList << proxyList.at(1) // second proxy should be used
- << "http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt"
- << QNetworkReply::NoError;
+ if (ftpSupported) {
+ // HTTP request with FTP + HTTP + SOCKS
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121)
+ << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129)
+ << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1081);
+ QTest::newRow("http-on-ftp+http+socks")
+ << proxyList << proxyList.at(1) // second proxy should be used
+ << "http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt"
+ << QNetworkReply::NoError;
+ }
// HTTP request with NoProxy + HTTP
proxyList.clear();
@@ -4405,15 +4815,15 @@ void tst_QNetworkReply::ioGetWithManyProxies_data()
<< QNetworkReply::NoError;
// HTTP request with FTP + NoProxy
- proxyList.clear();
- proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121)
- << QNetworkProxy(QNetworkProxy::NoProxy);
- QTest::newRow("http-on-ftp+noproxy")
- << proxyList << proxyList.at(1) // second proxy should be used
- << "http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt"
- << QNetworkReply::NoError;
-
if (ftpSupported) {
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121)
+ << QNetworkProxy(QNetworkProxy::NoProxy);
+ QTest::newRow("http-on-ftp+noproxy")
+ << proxyList << proxyList.at(1) // second proxy should be used
+ << "http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt"
+ << QNetworkReply::NoError;
+
// FTP request with HTTP Caching + FTP
proxyList.clear();
proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy,
@@ -4436,15 +4846,17 @@ void tst_QNetworkReply::ioGetWithManyProxies_data()
<< "https://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt"
<< QNetworkReply::NoError;
- // HTTPS request with FTP + HTTP C + HTTP T
- proxyList.clear();
- proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121)
- << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129)
- << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::httpProxyServerName(), 3129);
- QTest::newRow("https-on-ftp+httpcaching+http")
- << proxyList << proxyList.at(2) // skip the first two
- << "https://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt"
- << QNetworkReply::NoError;
+ if (ftpSupported) {
+ // HTTPS request with FTP + HTTP C + HTTP T
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121)
+ << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129)
+ << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::httpProxyServerName(), 3129);
+ QTest::newRow("https-on-ftp+httpcaching+http")
+ << proxyList << proxyList.at(2) // skip the first two
+ << "https://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt"
+ << QNetworkReply::NoError;
+ }
#endif
}
@@ -4499,16 +4911,16 @@ void tst_QNetworkReply::ioGetWithManyProxies()
// now verify that the proxies worked:
QFETCH(QNetworkProxy, proxyUsed);
if (proxyUsed.type() == QNetworkProxy::NoProxy) {
- QCOMPARE(authspy.count(), 0);
+ QCOMPARE(authspy.size(), 0);
} else {
if (QByteArray(QTest::currentDataTag()).startsWith("ftp-"))
return; // No authentication with current FTP or with FTP proxies
- QCOMPARE(authspy.count(), 1);
+ QCOMPARE(authspy.size(), 1);
QCOMPARE(qvariant_cast<QNetworkProxy>(authspy.at(0).at(0)), proxyUsed);
}
} else {
// request failed
- QCOMPARE(authspy.count(), 0);
+ QCOMPARE(authspy.size(), 0);
}
}
#endif // QT_CONFIG(networkproxy)
@@ -4676,6 +5088,10 @@ void tst_QNetworkReply::ioPutToFileFromProcess()
QByteArray contents = file.readAll();
QCOMPARE(contents, data);
+ if (process.state() == QProcess::Running)
+ QVERIFY(process.waitForFinished());
+ QCOMPARE(process.exitCode(), 0);
+
#endif // QT_CONFIG(process)
}
@@ -4814,7 +5230,7 @@ void tst_QNetworkReply::ioPostToHttpFromSocket_data()
QTest::addColumn<int>("authenticationRequiredCount");
QTest::addColumn<int>("proxyAuthenticationRequiredCount");
- for (int i = 0; i < proxies.count(); ++i)
+ for (int i = 0; i < proxies.size(); ++i)
for (int auth = 0; auth < 2; ++auth) {
QUrl url;
if (auth)
@@ -4892,8 +5308,8 @@ void tst_QNetworkReply::ioPostToHttpFromSocket()
QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
- QTEST(int(authenticationRequiredSpy.count()), "authenticationRequiredCount");
- QTEST(int(proxyAuthenticationRequiredSpy.count()), "proxyAuthenticationRequiredCount");
+ QTEST(int(authenticationRequiredSpy.size()), "authenticationRequiredCount");
+ QTEST(int(proxyAuthenticationRequiredSpy.size()), "proxyAuthenticationRequiredCount");
}
void tst_QNetworkReply::ioPostToHttpFromSocketSynchronous_data()
@@ -5365,13 +5781,9 @@ void tst_QNetworkReply::emitAllUploadProgressSignals()
QNetworkRequest catchAllSignalsRequest(normalRequest);
catchAllSignalsRequest.setAttribute(QNetworkRequest::EmitAllUploadProgressSignalsAttribute, true);
- QList<QNetworkRequest> requests;
- requests << normalRequest << catchAllSignalsRequest;
-
QList<int> signalCount;
- foreach (const QNetworkRequest &request, requests) {
-
+ for (const QNetworkRequest &request : {normalRequest, catchAllSignalsRequest}) {
sourceFile.seek(0);
QNetworkReplyPtr reply(manager.post(request, &sourceFile));
QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
@@ -5392,7 +5804,7 @@ void tst_QNetworkReply::emitAllUploadProgressSignals()
QVERIFY(!QTestEventLoop::instance().timeout());
incomingSocket->close();
- signalCount.append(spy.count());
+ signalCount.append(spy.size());
reply->deleteLater();
}
server.close();
@@ -5438,7 +5850,7 @@ void tst_QNetworkReply::ioPostToHttpEmptyUploadProgress()
QVERIFY(!QTestEventLoop::instance().timeout());
// final check: only 1 uploadProgress has been emitted
- QCOMPARE(spy.length(), 1);
+ QCOMPARE(spy.size(), 1);
QList<QVariant> args = spy.last();
QVERIFY(!args.isEmpty());
QCOMPARE(args.at(0).toLongLong(), buffer.size());
@@ -5476,7 +5888,7 @@ void tst_QNetworkReply::lastModifiedHeaderForHttp()
QDateTime header = reply->header(QNetworkRequest::LastModifiedHeader).toDateTime();
QDateTime realDate = QDateTime::fromString("2007-05-22T12:04:57", Qt::ISODate);
- realDate.setTimeSpec(Qt::UTC);
+ realDate.setTimeZone(QTimeZone::UTC);
QCOMPARE(header, realDate);
}
@@ -5609,7 +6021,7 @@ void tst_QNetworkReply::downloadProgress()
QVERIFY(!QTestEventLoop::instance().timeout());
QVERIFY(reply->isFinished());
- QVERIFY(spy.count() > 0);
+ QVERIFY(spy.size() > 0);
//final progress should have equal current & total
QList<QVariant> args = spy.takeLast();
@@ -5655,14 +6067,14 @@ void tst_QNetworkReply::uploadProgress()
QVERIFY(server.hasPendingConnections());
QTcpSocket *receiver = server.nextPendingConnection();
- if (finished.count() == 0) {
+ if (finished.size() == 0) {
// it's not finished yet, so wait for it to be
QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply));
}
delete receiver;
- QVERIFY(finished.count() > 0);
- QVERIFY(spy.count() > 0);
+ QVERIFY(finished.size() > 0);
+ QVERIFY(spy.size() > 0);
QList<QVariant> args = spy.last();
QCOMPARE(args.at(0).toInt(), data.size());
@@ -5944,8 +6356,8 @@ void tst_QNetworkReply::nestedEventLoops()
QTestEventLoop::instance().enterLoop(20);
QVERIFY2(!QTestEventLoop::instance().timeout(), "Network timeout");
- QCOMPARE(finishedspy.count(), 1);
- QCOMPARE(errorspy.count(), 0);
+ QCOMPARE(finishedspy.size(), 1);
+ QCOMPARE(errorspy.size(), 0);
}
#if QT_CONFIG(networkproxy)
@@ -5978,7 +6390,7 @@ void tst_QNetworkReply::httpProxyCommands()
manager.setProxy(proxy);
QNetworkRequest request(url);
- request.setRawHeader("User-Agent", "QNetworkReplyAutoTest/1.0");
+ request.setRawHeader("user-agent", "QNetworkReplyAutoTest/1.0");
QNetworkReplyPtr reply(manager.get(request));
// wait for the finished signal
@@ -5991,14 +6403,15 @@ void tst_QNetworkReply::httpProxyCommands()
// 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.size());
QCOMPARE(receivedHeader, expectedCommand);
//QTBUG-17223 - make sure the user agent from the request is sent to proxy server even for CONNECT
- int uapos = proxyServer.receivedData.indexOf("User-Agent");
+ const QByteArray cUserAgent = "user-agent: ";
+ int uapos = proxyServer.receivedData.toLower().indexOf(cUserAgent) + cUserAgent.size();
int uaend = proxyServer.receivedData.indexOf("\r\n", uapos);
QByteArray uaheader = proxyServer.receivedData.mid(uapos, uaend - uapos);
- QCOMPARE(uaheader, QByteArray("User-Agent: QNetworkReplyAutoTest/1.0"));
+ QCOMPARE(uaheader, QByteArray("QNetworkReplyAutoTest/1.0"));
}
class ProxyChangeHelper : public QObject
@@ -6035,14 +6448,6 @@ struct QThreadCleanup
}
};
-struct QDeleteLaterCleanup
-{
- static inline void cleanup(QObject *o)
- {
- o->deleteLater();
- }
-};
-
#if QT_CONFIG(networkproxy)
void tst_QNetworkReply::httpProxyCommandsSynchronous()
{
@@ -6054,7 +6459,7 @@ void tst_QNetworkReply::httpProxyCommandsSynchronous()
// the server thread, because the client is never returning to the
// event loop
QScopedPointer<QThread, QThreadCleanup> serverThread(new QThread);
- QScopedPointer<MiniHttpServer, QDeleteLaterCleanup> proxyServer(new MiniHttpServer(responseToSend, false, serverThread.data()));
+ QScopedPointer<MiniHttpServer, QScopedPointerDeleteLater> proxyServer(new MiniHttpServer(responseToSend, false, serverThread.data()));
QNetworkProxy proxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer->serverPort());
manager.setProxy(proxy);
@@ -6075,7 +6480,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.size());
QCOMPARE(receivedHeader, expectedCommand);
}
@@ -6172,9 +6577,9 @@ void tst_QNetworkReply::authorizationError()
QCOMPARE(waitForFinish(reply), int(Failure));
QFETCH(int, errorSignalCount);
- QCOMPARE(errorSpy.count(), errorSignalCount);
+ QCOMPARE(errorSpy.size(), errorSignalCount);
QFETCH(int, finishedSignalCount);
- QCOMPARE(finishedSpy.count(), finishedSignalCount);
+ QCOMPARE(finishedSpy.size(), finishedSignalCount);
QFETCH(int, error);
QCOMPARE(reply->error(), QNetworkReply::NetworkError(error));
@@ -6212,7 +6617,6 @@ void tst_QNetworkReply::httpConnectionCount()
}
QVERIFY(server->listen());
- QCoreApplication::instance()->processEvents();
QUrl url("http://127.0.0.1:" + QString::number(server->serverPort()) + QLatin1Char('/'));
if (encrypted)
@@ -6223,7 +6627,7 @@ void tst_QNetworkReply::httpConnectionCount()
QUrl urlCopy = url;
urlCopy.setPath(u'/' + QString::number(i)); // Differentiate the requests a bit
QNetworkRequest request(urlCopy);
- request.setAttribute(QNetworkRequest::Http2AllowedAttribute, http2Enabled);
+ request.setAttribute(QNetworkRequest::Http2CleartextAllowedAttribute, http2Enabled);
QNetworkReply* reply = manager.get(request);
reply->setParent(server.data());
if (encrypted)
@@ -6231,26 +6635,40 @@ void tst_QNetworkReply::httpConnectionCount()
}
int pendingConnectionCount = 0;
- QElapsedTimer timer;
- timer.start();
- while(pendingConnectionCount <= 20) {
- QTestEventLoop::instance().enterLoop(1);
+ using namespace std::chrono_literals;
+ const auto newPendingConnection = [&server]() { return server->hasPendingConnections(); };
+ // If we have http2 enabled then the second connection will take a little
+ // longer to be established because we will wait for the first one to finish
+ // to see if we should upgrade:
+ const int rampDown = http2Enabled ? 2 : 1;
+ while (pendingConnectionCount <= 6) {
+ if (!QTest::qWaitFor(newPendingConnection, pendingConnectionCount >= rampDown ? 3s : 7s))
+ break;
QTcpSocket *socket = server->nextPendingConnection();
- while (socket != 0) {
- if (pendingConnectionCount == 0) {
- // respond to the first connection so we know to transition to HTTP/1.1 when using
- // HTTP/2
- socket->write(httpEmpty200Response);
+ while (socket) {
+ if (pendingConnectionCount == 0 && http2Enabled) {
+ // Respond to the first connection so we know to transition to HTTP/1.1 when using
+ // HTTP/2.
+ // Because of some internal state machinery we need to wait until the request has
+ // actually been written to the server before we can reply.
+ auto connection = std::make_shared<QMetaObject::Connection>();
+ auto replyOnRequest = [=, buffer = QByteArray()]() mutable {
+ buffer += socket->readAll();
+ if (!buffer.contains("\r\n\r\n"))
+ return;
+ socket->write(httpEmpty200Response);
+ QObject::disconnect(*connection);
+ };
+ *connection = QObject::connect(socket, &QTcpSocket::readyRead, socket,
+ std::move(replyOnRequest));
+ if (socket->bytesAvailable()) // If we already have data, check it now
+ emit socket->readyRead();
}
pendingConnectionCount++;
socket->setParent(server.data());
socket = server->nextPendingConnection();
}
-
- // at max. wait 10 sec
- if (timer.elapsed() > 10000)
- break;
}
QCOMPARE(pendingConnectionCount, 6);
@@ -6533,7 +6951,7 @@ void tst_QNetworkReply::encrypted()
QTestEventLoop::instance().enterLoop(20);
QVERIFY(!QTestEventLoop::instance().timeout());
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
reply->deleteLater();
}
@@ -6562,7 +6980,7 @@ void tst_QNetworkReply::abortOnEncrypted()
});
QSignalSpy spyEncrypted(reply, &QNetworkReply::encrypted);
- QTRY_COMPARE(spyEncrypted.count(), 1);
+ QTRY_COMPARE(spyEncrypted.size(), 1);
// Wait for the socket to be closed again in order to be sure QTcpSocket::readyRead would have been emitted.
QTRY_VERIFY(server.socket != nullptr);
@@ -6756,7 +7174,20 @@ void tst_QNetworkReply::getAndThenDeleteObject()
// see https://bugs.webkit.org/show_bug.cgi?id=38935
void tst_QNetworkReply::symbianOpenCDataUrlCrash()
{
- QString requestUrl("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAWCAYAAAA1vze2AAAAB3RJTUUH2AUSEgolrgBvVQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAARnQU1BAACxjwv8YQUAAAHlSURBVHja5VbNShxBEK6ZaXtnHTebQPA1gngNmfaeq+QNPIlIXkC9iQdJxJNvEHLN3VkxhxxE8gTmEhAVddXZ6Z3f9Ndriz89/sHmkBQUVVT1fB9d9c3uOERUKTunIdn3HzstxGpYBDS4wZk7TAJj/wlJ90J+jnuygqs8svSj+/rGHBos3rE18XBvfU3no7NzlJfUaY/5whAwl8Lr/WDUv4ODxTMb+P5xLExe5LmO559WqTX/MQR4WZYEAtSePS4pE0qSnuhnRUcBU5Gm2k9XljU4Z26I3NRxBrd80rj2fh+KNE0FY4xevRgTjREvPFpasAK8Xli6MUbbuKw3afAGgSBXozo5u4hkmncAlkl5wx8iMGbdyQjnCFEiEwGiosj1UQA/x2rVddiVoi+l4IxE0PTDnx+mrQBvvnx9cFz3krhVvuhzFn579/aq/n5rW8fbtTqiWhIQZEo17YBvbkxOXNVndnYpTvod7AtiuN2re0+siwcB9oH8VxxrNwQQAhzyRs30n7wTI2HIN2g2QtQwjjhJIQatOq7E8bIVCLwzpl83Lvtvl+NohWWlE8UZTWEMAGCcR77fHKhPnZF5tYie6dfdxCphACmLPM+j8bYfmTryg64kV9Vh3mV8jP0b/4wO/YUPiT/8i0MLf55lSQAAAABJRU5ErkJggg==");
+ QString requestUrl("data:image/"
+ "png;base64,"
+ "iVBORw0KGgoAAAANSUhEUgAAABkAAAAWCAYAAAA1vze2AAAAB3RJTUUH2AUSEgolrgBvVQAAAAl"
+ "wSFlzAAALEwAACxMBAJqcGAAAAARnQU1BAACxjwv8YQUAAAHlSURBVHja5VbNShxBEK6ZaXtnHT"
+ "ebQPA1gngNmfaeq+QNPIlIXkC9iQdJxJNvEHLN3VkxhxxE8gTmEhAVddXZ6Z3f9Ndriz89/"
+ "sHmkBQUVVT1fB9d9c3uOERUKTunIdn3HzstxGpYBDS4wZk7TAJj/wlJ90J+jnuygqs8svSj+/"
+ "rGHBos3rE18XBvfU3no7NzlJfUaY/5whAwl8Lr/WDUv4ODxTMb+P5xLExe5LmO559WqTX/"
+ "MQR4WZYEAtSePS4pE0qSnuhnRUcBU5Gm2k9XljU4Z26I3NRxBrd80rj2fh+"
+ "KNE0FY4xevRgTjREvPFpasAK8Xli6MUbbuKw3afAGgSBXozo5u4hkmncAlkl5wx8iMGbdyQjnCF"
+ "EiEwGiosj1UQA/x2rVddiVoi+l4IxE0PTDnx+mrQBvvnx9cFz3krhVvuhzFn579/aq/"
+ "n5rW8fbtTqiWhIQZEo17YBvbkxOXNVndnYpTvod7AtiuN2re0+"
+ "siwcB9oH8VxxrNwQQAhzyRs30n7wTI2HIN2g2QtQwjjhJIQatOq7E8bIVCLwzpl83Lvtvl+"
+ "NohWWlE8UZTWEMAGCcR77fHKhPnZF5tYie6dfdxCphACmLPM+j8bYfmTryg64kV9Vh3mV8jP0b/"
+ "4wO/YUPiT/8i0MLf55lSQAAAABJRU5ErkJggg==");
QUrl url = QUrl::fromEncoded(requestUrl.toLatin1());
QNetworkRequest req(url);
QNetworkReplyPtr reply;
@@ -7101,7 +7532,7 @@ void tst_QNetworkReply::compressedHttpReplyBrokenGzip()
QCOMPARE(waitForFinish(reply), int(Failure));
- QCOMPARE(reply->error(), QNetworkReply::ProtocolFailure);
+ QCOMPARE(reply->error(), QNetworkReply::UnknownContentError);
}
// TODO add similar test for FTP
@@ -7145,9 +7576,9 @@ void tst_QNetworkReply::qtbug4121unknownAuthentication()
QTestEventLoop::instance().enterLoop(10);
QVERIFY(!QTestEventLoop::instance().timeout());
- QCOMPARE(authSpy.count(), 0);
- QCOMPARE(finishedSpy.count(), 1);
- QCOMPARE(errorSpy.count(), 1);
+ QCOMPARE(authSpy.size(), 0);
+ QCOMPARE(finishedSpy.size(), 1);
+ QCOMPARE(errorSpy.size(), 1);
QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
}
@@ -7158,7 +7589,7 @@ void tst_QNetworkReply::authenticationCacheAfterCancel_data()
QTest::addColumn<QNetworkProxy>("proxy");
QTest::addColumn<bool>("proxyAuth");
QTest::addColumn<QUrl>("url");
- for (int i = 0; i < proxies.count(); ++i) {
+ for (int i = 0; i < proxies.size(); ++i) {
QTest::newRow("http" + proxies.at(i).tag)
<< proxies.at(i).proxy
<< proxies.at(i).requiresAuthentication
@@ -7241,8 +7672,8 @@ void tst_QNetworkReply::authenticationCacheAfterCancel()
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(reply->error(), QNetworkReply::ProxyAuthenticationRequiredError);
- QCOMPARE(authSpy.count(), 0);
- QCOMPARE(proxyAuthSpy.count(), 1);
+ QCOMPARE(authSpy.size(), 0);
+ QCOMPARE(proxyAuthSpy.size(), 1);
proxyAuthSpy.clear();
//should fail due to bad credentials
@@ -7256,8 +7687,8 @@ void tst_QNetworkReply::authenticationCacheAfterCancel()
// Work round known quirk in the old test server (danted -v < v1.1.19):
if (reply->error() != QNetworkReply::HostNotFoundError)
QCOMPARE(reply->error(), QNetworkReply::ProxyAuthenticationRequiredError);
- QCOMPARE(authSpy.count(), 0);
- QVERIFY(proxyAuthSpy.count() > 0);
+ QCOMPARE(authSpy.size(), 0);
+ QVERIFY(proxyAuthSpy.size() > 0);
proxyAuthSpy.clear();
// QTBUG-23136 workaround (needed even with danted v1.1.19):
@@ -7282,10 +7713,10 @@ void tst_QNetworkReply::authenticationCacheAfterCancel()
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
- QVERIFY(authSpy.count() > 0);
+ QVERIFY(authSpy.size() > 0);
authSpy.clear();
if (proxyAuth) {
- QVERIFY(proxyAuthSpy.count() > 0);
+ QVERIFY(proxyAuthSpy.size() > 0);
proxyAuthSpy.clear();
}
@@ -7298,11 +7729,11 @@ void tst_QNetworkReply::authenticationCacheAfterCancel()
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
- QVERIFY(authSpy.count() > 0);
+ QVERIFY(authSpy.size() > 0);
authSpy.clear();
if (proxyAuth) {
//should be supplied from cache
- QCOMPARE(proxyAuthSpy.count(), 0);
+ QCOMPARE(proxyAuthSpy.size(), 0);
proxyAuthSpy.clear();
}
@@ -7316,11 +7747,11 @@ void tst_QNetworkReply::authenticationCacheAfterCancel()
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(reply->error(), QNetworkReply::NoError);
- QVERIFY(authSpy.count() > 0);
+ QVERIFY(authSpy.size() > 0);
authSpy.clear();
if (proxyAuth) {
//should be supplied from cache
- QCOMPARE(proxyAuthSpy.count(), 0);
+ QCOMPARE(proxyAuthSpy.size(), 0);
proxyAuthSpy.clear();
}
@@ -7332,11 +7763,11 @@ void tst_QNetworkReply::authenticationCacheAfterCancel()
QCOMPARE(reply->error(), QNetworkReply::NoError);
//should be supplied from cache
- QCOMPARE(authSpy.count(), 0);
+ QCOMPARE(authSpy.size(), 0);
authSpy.clear();
if (proxyAuth) {
//should be supplied from cache
- QCOMPARE(proxyAuthSpy.count(), 0);
+ QCOMPARE(proxyAuthSpy.size(), 0);
proxyAuthSpy.clear();
}
@@ -7438,8 +7869,8 @@ void tst_QNetworkReply::httpWithNoCredentialUsage()
QNetworkReplyPtr reply(manager.get(request));
QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply));
// credentials in URL, so don't expect authentication signal
- QCOMPARE(authSpy.count(), 0);
- QCOMPARE(finishedSpy.count(), 1);
+ QCOMPARE(authSpy.size(), 0);
+ QCOMPARE(finishedSpy.size(), 1);
finishedSpy.clear();
}
@@ -7449,8 +7880,8 @@ void tst_QNetworkReply::httpWithNoCredentialUsage()
QNetworkReplyPtr reply(manager.get(request));
QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply));
// credentials in cache, so don't expect authentication signal
- QCOMPARE(authSpy.count(), 0);
- QCOMPARE(finishedSpy.count(), 1);
+ QCOMPARE(authSpy.size(), 0);
+ QCOMPARE(finishedSpy.size(), 1);
finishedSpy.clear();
}
@@ -7467,9 +7898,9 @@ void tst_QNetworkReply::httpWithNoCredentialUsage()
QVERIFY(!QTestEventLoop::instance().timeout());
// We check if authenticationRequired was emitted, however we do not anything in it so it should be 401
- QCOMPARE(authSpy.count(), 1);
- QCOMPARE(finishedSpy.count(), 1);
- QCOMPARE(errorSpy.count(), 1);
+ QCOMPARE(authSpy.size(), 1);
+ QCOMPARE(finishedSpy.size(), 1);
+ QCOMPARE(errorSpy.size(), 1);
QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
}
@@ -7754,8 +8185,8 @@ void tst_QNetworkReply::qtbug45581WrongReplyStatusCode()
QCOMPARE(reply->readAll(), expectedContent);
- QCOMPARE(finishedSpy.count(), 0);
- QCOMPARE(sslErrorsSpy.count(), 0);
+ QCOMPARE(finishedSpy.size(), 0);
+ QCOMPARE(sslErrorsSpy.size(), 0);
QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), expectedContent.size());
@@ -7844,8 +8275,8 @@ void tst_QNetworkReply::synchronousRequest()
QSignalSpy sslErrorsSpy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply, 0));
QVERIFY(reply->isFinished());
- QCOMPARE(finishedSpy.count(), 0);
- QCOMPARE(sslErrorsSpy.count(), 0);
+ QCOMPARE(finishedSpy.size(), 0);
+ QCOMPARE(sslErrorsSpy.size(), 0);
QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toString(), mimeType);
@@ -7854,7 +8285,7 @@ void tst_QNetworkReply::synchronousRequest()
if (expected.startsWith("file:")) {
QString path = expected.mid(5);
QFile file(path);
- file.open(QIODevice::ReadOnly);
+ QVERIFY(file.open(QIODevice::ReadOnly));
expectedContent = file.readAll();
} else if (expected.startsWith("data:")) {
expectedContent = expected.mid(5).toUtf8();
@@ -7884,7 +8315,7 @@ void tst_QNetworkReply::synchronousRequestSslFailure()
runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply, 0);
QVERIFY(reply->isFinished());
QCOMPARE(reply->error(), QNetworkReply::SslHandshakeFailedError);
- QCOMPARE(sslErrorsSpy.count(), 0);
+ QCOMPARE(sslErrorsSpy.size(), 0);
}
#endif
@@ -8048,10 +8479,10 @@ void tst_QNetworkReply::varyingCacheExpiry()
server.doClose = false;
QUrl urls[4] = {
- u"http://localhost"_qs,
- u"http://localhost"_qs,
- u"http://localhost"_qs,
- u"http://localhost"_qs,
+ u"http://localhost"_s,
+ u"http://localhost"_s,
+ u"http://localhost"_s,
+ u"http://localhost"_s,
};
for (size_t i = 0; i < std::size(urls); ++i)
urls[i].setPort(servers[i].serverPort());
@@ -8103,6 +8534,61 @@ void tst_QNetworkReply::varyingCacheExpiry()
QVERIFY(success);
}
+class Qtbug25280Server : public MiniHttpServer
+{
+public:
+ Qtbug25280Server(QByteArray qba) : MiniHttpServer(qba, false) {}
+ QSet<QTcpSocket*> receivedSockets;
+ void reply() override
+ {
+ // Save sockets in a list
+ receivedSockets.insert((QTcpSocket*)sender());
+ qobject_cast<QTcpSocket*>(sender())->write(dataToTransmit);
+ //qDebug() << "count=" << receivedSockets.count();
+ }
+};
+
+void tst_QNetworkReply::amountOfHttp1ConnectionsQtbug25280_data()
+{
+ QTest::addColumn<int>("amount");
+ QTest::addRow("default") << 6;
+ QTest::addRow("minimize") << 1;
+ QTest::addRow("increase") << 12;
+}
+
+// Also kind of QTBUG-8468
+void tst_QNetworkReply::amountOfHttp1ConnectionsQtbug25280()
+{
+ QFETCH(const int, amount);
+ QNetworkAccessManager manager; // function local instance
+ Qtbug25280Server server(tst_QNetworkReply::httpEmpty200Response);
+ server.doClose = false;
+ server.multiple = true;
+ QUrl url(QLatin1String("http://127.0.0.1")); // not "localhost" to prevent "Happy Eyeballs"
+ // from skewing the counting
+ url.setPort(server.serverPort());
+ std::optional<QHttp1Configuration> http1Configuration;
+ if (amount != 6) // don't set if it's the default
+ http1Configuration.emplace().setNumberOfConnectionsPerHost(amount);
+ constexpr int NumRequests = 200; // send a lot more than we have sockets
+ int finished = 0;
+ std::array<std::unique_ptr<QNetworkReply>, NumRequests> replies;
+ for (auto &reply : replies) {
+ QNetworkRequest request(url);
+ if (http1Configuration)
+ request.setHttp1Configuration(*http1Configuration);
+ reply.reset(manager.get(request));
+ QObject::connect(reply.get(), &QNetworkReply::finished,
+ [&finished] { ++finished; });
+ }
+ QTRY_COMPARE_WITH_TIMEOUT(finished, NumRequests, 60'000);
+ for (const auto &reply : replies) {
+ QCOMPARE(reply->error(), QNetworkReply::NoError);
+ QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
+ }
+ QCOMPARE(server.receivedSockets.size(), amount);
+}
+
void tst_QNetworkReply::dontInsertPartialContentIntoTheCache()
{
QByteArray reply206 =
@@ -8131,7 +8617,7 @@ void tst_QNetworkReply::dontInsertPartialContentIntoTheCache()
QVERIFY(server.totalConnections > 0);
QCOMPARE(reply->readAll().constData(), "load");
- QCOMPARE(memoryCache->m_insertedUrls.count(), 0);
+ QCOMPARE(memoryCache->m_insertedUrls.size(), 0);
}
void tst_QNetworkReply::httpUserAgent()
@@ -8148,7 +8634,7 @@ void tst_QNetworkReply::httpUserAgent()
QVERIFY(reply->isFinished());
QCOMPARE(reply->error(), QNetworkReply::NoError);
- QVERIFY(server.receivedData.contains("\r\nUser-Agent: abcDEFghi\r\n"));
+ QVERIFY(server.receivedData.contains("\r\nuser-agent: abcDEFghi\r\n"));
}
void tst_QNetworkReply::synchronousAuthenticationCache()
@@ -8168,7 +8654,7 @@ void tst_QNetworkReply::synchronousAuthenticationCache()
"Content-Type: text/plain\r\n"
"\r\n"
"auth";
- QRegularExpression rx("Authorization: Basic ([^\r\n]*)\r\n");
+ QRegularExpression rx("authorization: Basic ([^\r\n]*)\r\n");
QRegularExpressionMatch match = rx.match(receivedData);
if (match.hasMatch()) {
if (QByteArray::fromBase64(match.captured(1).toLatin1()) == "login:password") {
@@ -8189,7 +8675,7 @@ void tst_QNetworkReply::synchronousAuthenticationCache()
// the server thread, because the client is never returning to the
// event loop
QScopedPointer<QThread, QThreadCleanup> serverThread(new QThread);
- QScopedPointer<MiniHttpServer, QDeleteLaterCleanup> server(new MiniAuthServer(serverThread.data()));
+ QScopedPointer<MiniHttpServer, QScopedPointerDeleteLater> server(new MiniAuthServer(serverThread.data()));
server->doClose = true;
//1) URL without credentials, we are not authenticated
@@ -8328,31 +8814,33 @@ void tst_QNetworkReply::ftpAuthentication()
void tst_QNetworkReply::emitErrorForAllReplies() // QTBUG-36890
{
// port 100 is not well-known and should be closed
- QList<QUrl> urls = QList<QUrl>() << QUrl("http://localhost:100/request1")
- << QUrl("http://localhost:100/request2")
- << QUrl("http://localhost:100/request3");
- QList<QNetworkReply *> replies;
- QList<QSignalSpy *> errorSpies;
- QList<QSignalSpy *> finishedSpies;
- for (int a = 0; a < urls.count(); ++a) {
- QNetworkRequest request(urls.at(a));
+ const QUrl urls[] = {
+ QUrl("http://localhost:100/request1"),
+ QUrl("http://localhost:100/request2"),
+ QUrl("http://localhost:100/request3"),
+ };
+ constexpr auto NUrls = std::size(urls);
+
+ std::unique_ptr<QNetworkReply, QScopedPointerDeleteLater> replies[NUrls];
+ std::optional<QSignalSpy> errorSpies[NUrls];
+ std::optional<QSignalSpy> finishedSpies[NUrls];
+
+ for (size_t i = 0; i < NUrls; ++i) {
+ QNetworkRequest request(urls[i]);
QNetworkReply *reply = manager.get(request);
- replies.append(reply);
- QSignalSpy *errorSpy = new QSignalSpy(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)));
- errorSpies.append(errorSpy);
- QSignalSpy *finishedSpy = new QSignalSpy(reply, SIGNAL(finished()));
- finishedSpies.append(finishedSpy);
+ replies[i].reset(reply);
+ errorSpies[i].emplace(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)));
+ finishedSpies[i].emplace(reply, SIGNAL(finished()));
QObject::connect(reply, SIGNAL(finished()), SLOT(emitErrorForAllRepliesSlot()));
}
+
QTestEventLoop::instance().enterLoop(10);
QVERIFY(!QTestEventLoop::instance().timeout());
- for (int a = 0; a < urls.count(); ++a) {
- QVERIFY(replies.at(a)->isFinished());
- QCOMPARE(errorSpies.at(a)->count(), 1);
- errorSpies.at(a)->deleteLater();
- QCOMPARE(finishedSpies.at(a)->count(), 1);
- finishedSpies.at(a)->deleteLater();
- replies.at(a)->deleteLater();
+
+ for (size_t i = 0; i < NUrls; ++i) {
+ QVERIFY(replies[i]->isFinished());
+ QCOMPARE(errorSpies[i]->size(), 1);
+ QCOMPARE(finishedSpies[i]->size(), 1);
}
}
@@ -8400,7 +8888,7 @@ public:
return ret;
}
virtual bool atEnd() const override { return buffer.atEnd(); }
- virtual qint64 size() const override { return data.length(); }
+ virtual qint64 size() const override { return data.size(); }
qint64 bytesAvailable() const override
{
return buffer.bytesAvailable() + QIODevice::bytesAvailable();
@@ -8421,9 +8909,9 @@ protected slots:
void tst_QNetworkReply::putWithRateLimiting()
{
QFile reference(testDataDir + "/rfc3252.txt");
- reference.open(QIODevice::ReadOnly);
+ QVERIFY(reference.open(QIODevice::ReadOnly));
QByteArray data = reference.readAll();
- QVERIFY(data.length() > 0);
+ QVERIFY(data.size() > 0);
QUrl url = QUrl::fromUserInput("http://" + QtNetworkSettings::httpServerName()+ "/qtest/cgi-bin/echo.cgi?");
@@ -8438,7 +8926,7 @@ void tst_QNetworkReply::putWithRateLimiting()
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
QByteArray uploadedData = reply->readAll();
- QCOMPARE(uploadedData.length(), data.length());
+ QCOMPARE(uploadedData.size(), data.size());
QCOMPARE(uploadedData, data);
}
@@ -8470,8 +8958,8 @@ void tst_QNetworkReply::ioHttpSingleRedirect()
QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply));
// Redirected and finished should be emitted exactly once
- QCOMPARE(redSpy.count(), 1);
- QCOMPARE(finSpy.count(), 1);
+ QCOMPARE(redSpy.size(), 1);
+ QCOMPARE(finSpy.size(), 1);
// Original URL should not be changed after redirect
QCOMPARE(request.url(), localhost);
@@ -8517,8 +9005,8 @@ void tst_QNetworkReply::ioHttpChangeMaxRedirects()
QCOMPARE(waitForFinish(reply), int(Failure));
- QCOMPARE(redSpy.count(), request.maximumRedirectsAllowed());
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(redSpy.size(), request.maximumRedirectsAllowed());
+ QCOMPARE(spy.size(), 1);
QCOMPARE(reply->error(), QNetworkReply::TooManyRedirectsError);
// Increase max redirects to allow successful completion
@@ -8529,7 +9017,7 @@ void tst_QNetworkReply::ioHttpChangeMaxRedirects()
QVERIFY2(waitForFinish(reply2) == Success, msgWaitForFinished(reply2));
- QCOMPARE(redSpy2.count(), 2);
+ QCOMPARE(redSpy2.size(), 2);
QCOMPARE(reply2->url(), server3Url);
QCOMPARE(reply2->error(), QNetworkReply::NoError);
QVERIFY(validateRedirectedResponseHeaders(reply2));
@@ -8662,8 +9150,8 @@ void tst_QNetworkReply::ioHttpRedirectPolicy()
QSignalSpy redirectSpy(reply.data(), SIGNAL(redirected(QUrl)));
QSignalSpy finishedSpy(reply.data(), SIGNAL(finished()));
QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply));
- QCOMPARE(finishedSpy.count(), 1);
- QCOMPARE(redirectSpy.count(), redirectCount);
+ QCOMPARE(finishedSpy.size(), 1);
+ QCOMPARE(redirectSpy.size(), redirectCount);
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), statusCode);
QVERIFY(validateRedirectedResponseHeaders(reply) || statusCode != 200);
}
@@ -8746,7 +9234,7 @@ void tst_QNetworkReply::ioHttpRedirectPolicyErrors()
QSignalSpy spy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError)));
QCOMPARE(waitForFinish(reply), int(Failure));
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QCOMPARE(reply->error(), expectedError);
}
@@ -8796,7 +9284,7 @@ void tst_QNetworkReply::ioHttpUserVerifiedRedirect()
QSignalSpy finishedSpy(reply.data(), SIGNAL(finished()));
waitForFinish(reply);
- QCOMPARE(finishedSpy.count(), 1);
+ QCOMPARE(finishedSpy.size(), 1);
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), statusCode);
QVERIFY(validateRedirectedResponseHeaders(reply) || statusCode != 200);
}
@@ -8808,7 +9296,7 @@ void tst_QNetworkReply::ioHttpCookiesDuringRedirect()
const QString cookieHeader = QStringLiteral("Set-Cookie: hello=world; Path=/;\r\n");
QString redirect = tempRedirectReplyStr();
// Insert 'cookieHeader' before the final \r\n
- redirect.insert(redirect.length() - 2, cookieHeader);
+ redirect.insert(redirect.size() - 2, cookieHeader);
QUrl url("http://localhost/");
url.setPort(target.serverPort());
@@ -8825,7 +9313,7 @@ void tst_QNetworkReply::ioHttpCookiesDuringRedirect()
manager.setRedirectPolicy(oldRedirectPolicy);
QVERIFY(waitForFinish(reply) == Success);
- QVERIFY(target.receivedData.contains("\r\nCookie: hello=world\r\n"));
+ QVERIFY(target.receivedData.contains("\r\ncookie: hello=world\r\n"));
QVERIFY(validateRedirectedResponseHeaders(reply));
}
@@ -8868,6 +9356,64 @@ void tst_QNetworkReply::ioHttpRedirect()
QVERIFY(validateRedirectedResponseHeaders(reply));
}
+/*
+ Test that, if we load a redirect from cache, we don't treat the request to
+ the destination of the redirect as a redirect.
+
+ If it was treated as a redirect the finished() signal was never emitted!
+*/
+void tst_QNetworkReply::ioHttpRedirectWithCache()
+{
+ // Disallow caching the result so that the second request must also send the request
+ QByteArray http200ResponseNoCache = "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/plain\r\n"
+ "Cache-Control: no-cache\r\n"
+ "\r\nHello";
+
+ MiniHttpServer target(http200ResponseNoCache, false);
+ QUrl targetUrl("http://localhost/");
+ targetUrl.setPort(target.serverPort());
+
+ // A cache-able redirect reply
+ QString redirectReply = QStringLiteral("HTTP/1.1 308\r\n"
+ "Content-Type: text/plain\r\n"
+ "location: %1\r\n"
+ "Cache-Control: max-age=3600\r\n"
+ "\r\nYou're being redirected").arg(targetUrl.toString());
+ MiniHttpServer redirectServer(redirectReply.toLatin1(), false);
+ QUrl url("http://localhost/");
+ url.setPort(redirectServer.serverPort());
+
+ QTemporaryDir tempDir(QDir::tempPath() + "/tmp_cache_28035");
+ QVERIFY2(tempDir.isValid(), qPrintable(tempDir.errorString()));
+ tempDir.setAutoRemove(true);
+
+ QNetworkDiskCache *diskCache = new QNetworkDiskCache();
+ diskCache->setCacheDirectory(tempDir.path());
+ // Manager takes ownership of the cache:
+ manager.setCache(diskCache);
+ QCOMPARE(diskCache->cacheSize(), 0);
+
+ // Send the first request, we end up caching the redirect reply
+ QNetworkRequest request(url);
+ QNetworkReplyPtr reply(manager.get(request));
+
+ QCOMPARE(waitForFinish(reply), int(Success));
+ QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
+ QVERIFY(validateRedirectedResponseHeaders(reply));
+
+ QVERIFY(diskCache->cacheSize() != 0);
+
+ // Now for the second request, we will use the cache, and we test that the finished()
+ // signal is still emitted.
+ request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
+ reply.reset(manager.get(request));
+
+ QCOMPARE(waitForFinish(reply), int(Success));
+ QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
+ QVERIFY(validateRedirectedResponseHeaders(reply));
+}
+
void tst_QNetworkReply::ioHttpRedirectFromLocalToRemote()
{
QUrl targetUrl("http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt");
@@ -9013,8 +9559,8 @@ void tst_QNetworkReply::ioHttpRedirectMultipartPost()
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);
+ QVERIFY(multiPart->boundary().size() > 20); // check that there is randomness after the "boundary_.oOo._" string
+ QVERIFY(multiPart->boundary().size() < 70);
QByteArray replyData = reply->readAll();
expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n");
@@ -9177,9 +9723,9 @@ public slots:
//qDebug() << m_receivedData.left(m_receivedData.indexOf("\r\n\r\n"));
m_receivedData = m_receivedData.mid(m_receivedData.indexOf("\r\n\r\n")+4); // check only actual data
}
- if (m_receivedData.length() > 0 && !m_expectedData.startsWith(m_receivedData)) {
+ if (m_receivedData.size() > 0 && !m_expectedData.startsWith(m_receivedData)) {
// We had received some data but it is corrupt!
- qDebug() << "CORRUPT" << m_receivedData.count();
+ qDebug() << "CORRUPT" << m_receivedData.size();
#if 0 // Use this to track down the pattern of the corruption and conclude the source
QFile a("/tmp/corrupt");
@@ -9301,8 +9847,12 @@ void tst_QNetworkReply::autoDeleteRepliesAttribute_data()
{
QTest::addColumn<QUrl>("destination");
- QTest::newRow("http") << QUrl("http://QInvalidDomain.qt/test");
- QTest::newRow("https") << QUrl("https://QInvalidDomain.qt/test");
+ QUrl webServerUrl = QtNetworkSettings::httpServerIp().toString();
+ webServerUrl.setPath("/notfound");
+ webServerUrl.setScheme("http");
+ QTest::newRow("http") << webServerUrl;
+ webServerUrl.setScheme("https");
+ QTest::newRow("https") << webServerUrl;
if (ftpSupported)
QTest::newRow("ftp") << QUrl("ftp://QInvalidDomain.qt/test");
QTest::newRow("file") << QUrl("file:///thisfolderdoesn'texist/probably.txt");
@@ -9325,7 +9875,7 @@ void tst_QNetworkReply::autoDeleteRepliesAttribute()
QSignalSpy finishedSpy(reply, &QNetworkReply::finished);
QSignalSpy destroyedSpy(reply, &QObject::destroyed);
QVERIFY(finishedSpy.wait());
- QCOMPARE(destroyedSpy.count(), 0);
+ QCOMPARE(destroyedSpy.size(), 0);
QVERIFY(destroyedSpy.wait());
}
{
@@ -9336,7 +9886,7 @@ void tst_QNetworkReply::autoDeleteRepliesAttribute()
QSignalSpy finishedSpy(reply, &QNetworkReply::finished);
QSignalSpy destroyedSpy(reply, &QObject::destroyed);
QVERIFY(finishedSpy.wait());
- QCOMPARE(destroyedSpy.count(), 0);
+ QCOMPARE(destroyedSpy.size(), 0);
QVERIFY(destroyedSpy.wait());
}
// Now repeated, but without the attribute to make sure it does not get deleted automatically.
@@ -9350,10 +9900,10 @@ void tst_QNetworkReply::autoDeleteRepliesAttribute()
QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished);
QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed);
QVERIFY(finishedSpy.wait());
- QCOMPARE(destroyedSpy.count(), 0);
+ QCOMPARE(destroyedSpy.size(), 0);
QCoreApplication::processEvents();
QCoreApplication::processEvents();
- QCOMPARE(destroyedSpy.count(), 0);
+ QCOMPARE(destroyedSpy.size(), 0);
}
{
// Post
@@ -9362,10 +9912,10 @@ void tst_QNetworkReply::autoDeleteRepliesAttribute()
QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished);
QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed);
QVERIFY(finishedSpy.wait());
- QCOMPARE(destroyedSpy.count(), 0);
+ QCOMPARE(destroyedSpy.size(), 0);
QCoreApplication::processEvents();
QCoreApplication::processEvents();
- QCOMPARE(destroyedSpy.count(), 0);
+ QCOMPARE(destroyedSpy.size(), 0);
}
}
@@ -9386,7 +9936,7 @@ void tst_QNetworkReply::autoDeleteReplies()
QSignalSpy finishedSpy(reply, &QNetworkReply::finished);
QSignalSpy destroyedSpy(reply, &QObject::destroyed);
QVERIFY(finishedSpy.wait());
- QCOMPARE(destroyedSpy.count(), 0);
+ QCOMPARE(destroyedSpy.size(), 0);
QVERIFY(destroyedSpy.wait());
}
{
@@ -9396,7 +9946,7 @@ void tst_QNetworkReply::autoDeleteReplies()
QSignalSpy finishedSpy(reply, &QNetworkReply::finished);
QSignalSpy destroyedSpy(reply, &QObject::destroyed);
QVERIFY(finishedSpy.wait());
- QCOMPARE(destroyedSpy.count(), 0);
+ QCOMPARE(destroyedSpy.size(), 0);
QVERIFY(destroyedSpy.wait());
}
// Here we repeat the test, but override the auto-deletion in the QNetworkRequest
@@ -9411,10 +9961,10 @@ void tst_QNetworkReply::autoDeleteReplies()
QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished);
QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed);
QVERIFY(finishedSpy.wait());
- QCOMPARE(destroyedSpy.count(), 0);
+ QCOMPARE(destroyedSpy.size(), 0);
QCoreApplication::processEvents();
QCoreApplication::processEvents();
- QCOMPARE(destroyedSpy.count(), 0);
+ QCOMPARE(destroyedSpy.size(), 0);
}
{
// Post
@@ -9424,10 +9974,10 @@ void tst_QNetworkReply::autoDeleteReplies()
QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished);
QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed);
QVERIFY(finishedSpy.wait());
- QCOMPARE(destroyedSpy.count(), 0);
+ QCOMPARE(destroyedSpy.size(), 0);
QCoreApplication::processEvents();
QCoreApplication::processEvents();
- QCOMPARE(destroyedSpy.count(), 0);
+ QCOMPARE(destroyedSpy.size(), 0);
}
// Now we repeat the test with autoDeleteReplies set to false
cleanup.dismiss();
@@ -9439,10 +9989,10 @@ void tst_QNetworkReply::autoDeleteReplies()
QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished);
QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed);
QVERIFY(finishedSpy.wait());
- QCOMPARE(destroyedSpy.count(), 0);
+ QCOMPARE(destroyedSpy.size(), 0);
QCoreApplication::processEvents();
QCoreApplication::processEvents();
- QCOMPARE(destroyedSpy.count(), 0);
+ QCOMPARE(destroyedSpy.size(), 0);
}
{
// Post
@@ -9451,140 +10001,137 @@ void tst_QNetworkReply::autoDeleteReplies()
QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished);
QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed);
QVERIFY(finishedSpy.wait());
- QCOMPARE(destroyedSpy.count(), 0);
+ QCOMPARE(destroyedSpy.size(), 0);
QCoreApplication::processEvents();
QCoreApplication::processEvents();
- QCOMPARE(destroyedSpy.count(), 0);
+ QCOMPARE(destroyedSpy.size(), 0);
}
}
-void tst_QNetworkReply::getWithTimeout()
+void tst_QNetworkReply::requestWithTimeout_data()
{
- MiniHttpServer server(tst_QNetworkReply::httpEmpty200Response, false);
-
- QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
- QNetworkReplyPtr reply(manager.get(request));
- QSignalSpy spy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError)));
-
- QCOMPARE(waitForFinish(reply), int(Success));
-
- QCOMPARE(spy.count(), 0);
- QVERIFY(reply->error() == QNetworkReply::NoError);
-
- request.setTransferTimeout(1000);
- server.stopTransfer = true;
+ using Operation = QNetworkAccessManager::Operation;
+ QTest::addColumn<Operation>("method");
+ QTest::addColumn<int>("reqInt");
+ QTest::addColumn<std::chrono::milliseconds>("reqChrono");
+ QTest::addColumn<int>("mgrInt");
+ QTest::addColumn<std::chrono::milliseconds>("mgrChrono");
- QNetworkReplyPtr reply2(manager.get(request));
- QSignalSpy spy2(reply2.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError)));
-
- QCOMPARE(waitForFinish(reply2), int(Failure));
-
- QCOMPARE(spy2.count(), 1);
- QVERIFY(reply2->error() == QNetworkReply::OperationCanceledError);
-
- request.setTransferTimeout(0);
- manager.setTransferTimeout(1000);
+ QTest::addRow("get_req_int") << Operation::GetOperation << 500 << 0ms << 0 << 0ms;
+ QTest::addRow("get_req_chrono") << Operation::GetOperation << 0 << 500ms << 0 << 0ms;
+ QTest::addRow("get_mgr_int") << Operation::GetOperation << 0 << 0ms << 500 << 0ms;
+ QTest::addRow("get_mgr_chrono") << Operation::GetOperation << 0 << 0ms << 0 << 500ms;
- QNetworkReplyPtr reply3(manager.get(request));
- QSignalSpy spy3(reply3.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError)));
-
- QCOMPARE(waitForFinish(reply3), int(Failure));
-
- QCOMPARE(spy3.count(), 1);
- QVERIFY(reply3->error() == QNetworkReply::OperationCanceledError);
-
- manager.setTransferTimeout(0);
+ QTest::addRow("post_req_int") << Operation::PostOperation << 500 << 0ms << 0 << 0ms;
+ QTest::addRow("post_req_chrono") << Operation::PostOperation << 0 << 500ms << 0 << 0ms;
+ QTest::addRow("post_mgr_int") << Operation::PostOperation << 0 << 0ms << 500 << 0ms;
+ QTest::addRow("post_mgr_chrono") << Operation::PostOperation << 0 << 0ms << 0 << 500ms;
}
-void tst_QNetworkReply::postWithTimeout()
+void tst_QNetworkReply::requestWithTimeout()
{
+ QFETCH(QNetworkAccessManager::Operation, method);
+ QFETCH(int, reqInt);
+ QFETCH(int, mgrInt);
+ QFETCH(std::chrono::milliseconds, reqChrono);
+ QFETCH(std::chrono::milliseconds, mgrChrono);
+ const auto data = "some data"_ba;
+ // Manager instance remains between case runs => always reset it's transferTimeout to
+ // ensure setting its transferTimeout in this case has effect
+ manager.setTransferTimeout(0ms);
+ auto cleanup = qScopeGuard([this] { manager.setTransferTimeout(0ms); });
+
MiniHttpServer server(tst_QNetworkReply::httpEmpty200Response, false);
+ server.stopTransfer = true;
QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
request.setRawHeader("Content-Type", "application/octet-stream");
- QByteArray postData("Just some nonsense");
- QNetworkReplyPtr reply(manager.post(request, postData));
- QSignalSpy spy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError)));
-
- QCOMPARE(waitForFinish(reply), int(Success));
-
- QCOMPARE(spy.count(), 0);
- QVERIFY(reply->error() == QNetworkReply::NoError);
-
- request.setTransferTimeout(1000);
- server.stopTransfer = true;
-
- QNetworkReplyPtr reply2(manager.post(request, postData));
- QSignalSpy spy2(reply2.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError)));
-
- QCOMPARE(waitForFinish(reply2), int(Failure));
+ if (reqInt > 0)
+ request.setTransferTimeout(reqInt);
+ if (reqChrono > 0ms)
+ request.setTransferTimeout(reqChrono);
+ if (mgrInt > 0)
+ manager.setTransferTimeout(mgrInt);
+ if (mgrChrono > 0ms)
+ manager.setTransferTimeout(mgrChrono);
- QCOMPARE(spy2.count(), 1);
- QVERIFY(reply2->error() == QNetworkReply::OperationCanceledError);
-
- request.setTransferTimeout(0);
- manager.setTransferTimeout(1000);
-
- QNetworkReplyPtr reply3(manager.post(request, postData));
- QSignalSpy spy3(reply3.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError)));
-
- QCOMPARE(waitForFinish(reply3), int(Failure));
-
- QCOMPARE(spy3.count(), 1);
- QVERIFY(reply3->error() == QNetworkReply::OperationCanceledError);
+ QNetworkReplyPtr reply;
+ if (method == QNetworkAccessManager::GetOperation)
+ reply.reset(manager.get(request));
+ else if (method == QNetworkAccessManager::PostOperation)
+ reply.reset(manager.post(request, data));
+ QVERIFY(reply);
- manager.setTransferTimeout(0);
+ QSignalSpy spy(reply.data(), &QNetworkReply::errorOccurred);
+ QCOMPARE(waitForFinish(reply), int(Failure));
+ QCOMPARE(spy.size(), 1);
+ QCOMPARE(reply->error(), QNetworkReply::OperationCanceledError);
}
void tst_QNetworkReply::moreActivitySignals_data()
{
QTest::addColumn<QUrl>("url");
QTest::addColumn<bool>("useipv6");
- QTest::addRow("local4") << QUrl("http://127.0.0.1") << false;
- QTest::addRow("local6") << QUrl("http://[::1]") << true;
+ QTest::addColumn<bool>("postWithData");
+ QTest::addRow("local4") << QUrl("http://127.0.0.1") << false << false;
+ QTest::addRow("local6") << QUrl("http://[::1]") << true << false;
if (qEnvironmentVariable("QTEST_ENVIRONMENT").split(' ').contains("ci")) {
// On CI server
- QTest::addRow("localDns") << QUrl("http://localhost") << false; // will find v6
+ QTest::addRow("localDns") << QUrl("http://localhost") << false << false; // will find v6
} else {
// For manual testing
- QTest::addRow("localDns4") << QUrl("http://localhost") << true; // will find both v4 and v6
- QTest::addRow("localDns6") << QUrl("http://localhost") << false; // will find both v4 and v6
+ QTest::addRow("localDns4") << QUrl("http://localhost") << true << false; // will find both v4 and v6
+ QTest::addRow("localDns6") << QUrl("http://localhost") << false << false; // will find both v4 and v6
}
+ QTest::addRow("post-with-data") << QUrl("http://[::1]") << true << true;
}
void tst_QNetworkReply::moreActivitySignals()
{
QFETCH(QUrl, url);
QFETCH(bool, useipv6);
+ QFETCH(bool, postWithData);
MiniHttpServer server(tst_QNetworkReply::httpEmpty200Response, false, nullptr/*thread*/, useipv6);
server.doClose = false;
url.setPort(server.serverPort());
QNetworkRequest request(url);
- QNetworkReplyPtr reply(manager.get(request));
- QSignalSpy spy1(reply.data(), SIGNAL(socketConnecting()));
+ QNetworkReplyPtr reply;
+ if (postWithData) {
+ request.setRawHeader("Content-Type", "text/plain");
+ reply.reset(manager.post(request, "Hello, world!"));
+ } else {
+ reply.reset(manager.get(request));
+ }
+ QSignalSpy spy1(reply.data(), SIGNAL(socketStartedConnecting()));
QSignalSpy spy2(reply.data(), SIGNAL(requestSent()));
QSignalSpy spy3(reply.data(), SIGNAL(metaDataChanged()));
QSignalSpy spy4(reply.data(), SIGNAL(finished()));
spy1.wait();
- QCOMPARE(spy1.count(), 1);
+ QCOMPARE(spy1.size(), 1);
spy2.wait();
- QCOMPARE(spy2.count(), 1);
+ QCOMPARE(spy2.size(), 1);
spy3.wait();
- QCOMPARE(spy3.count(), 1);
+ QCOMPARE(spy3.size(), 1);
spy4.wait();
- QCOMPARE(spy4.count(), 1);
+ QCOMPARE(spy4.size(), 1);
QVERIFY(reply->error() == QNetworkReply::NoError);
- // Second request will not send socketConnecting because of keep-alive, so don't check it.
- QNetworkReplyPtr secondreply(manager.get(request));
+ // Second request will not send socketStartedConnecting because of keep-alive, so don't check it.
+ QNetworkReplyPtr secondreply;
+ if (postWithData) {
+ request.setRawHeader("Content-Type", "text/plain");
+ secondreply.reset(manager.post(request, "Hello, world!"));
+ } else {
+ secondreply.reset(manager.get(request));
+ }
QSignalSpy secondspy2(secondreply.data(), SIGNAL(requestSent()));
QSignalSpy secondspy3(secondreply.data(), SIGNAL(metaDataChanged()));
QSignalSpy secondspy4(secondreply.data(), SIGNAL(finished()));
secondspy2.wait();
- QCOMPARE(secondspy2.count(), 1);
+ QCOMPARE(secondspy2.size(), 1);
secondspy3.wait();
- QCOMPARE(secondspy3.count(), 1);
+ QCOMPARE(secondspy3.size(), 1);
secondspy4.wait();
- QCOMPARE(secondspy4.count(), 1);
+ QCOMPARE(secondspy4.size(), 1);
QVERIFY(secondreply->error() == QNetworkReply::NoError);
}
@@ -9593,25 +10140,53 @@ void tst_QNetworkReply::contentEncoding_data()
QTest::addColumn<QByteArray>("encoding");
QTest::addColumn<QByteArray>("body");
QTest::addColumn<QByteArray>("expected");
+ QTest::addColumn<bool>("decompress");
+ const QByteArray helloWorld = "hello world";
+
+ const QByteArray gzipBody = QByteArray::fromBase64("H4sIAAAAAAAAA8tIzcnJVyjPL8pJAQCFEUoNCwAAAA==");
QTest::newRow("gzip-hello-world")
<< QByteArray("gzip")
- << QByteArray::fromBase64("H4sIAAAAAAAAA8tIzcnJVyjPL8pJAQCFEUoNCwAAAA==")
- << QByteArray("hello world");
+ << gzipBody
+ << helloWorld
+ << true;
+ QTest::newRow("gzip-hello-world-no-decompress")
+ << QByteArray("gzip")
+ << gzipBody
+ << helloWorld
+ << false;
+ const QByteArray deflateBody = QByteArray::fromBase64("eJzLSM3JyVcozy/KSQEAGgsEXQ==");
QTest::newRow("deflate-hello-world")
- << QByteArray("deflate") << QByteArray::fromBase64("eJzLSM3JyVcozy/KSQEAGgsEXQ==")
- << QByteArray("hello world");
+ << QByteArray("deflate") << deflateBody
+ << helloWorld
+ << true;
+ QTest::newRow("deflate-hello-world-no-decompress")
+ << QByteArray("deflate") << deflateBody
+ << helloWorld
+ << false;
#if QT_CONFIG(brotli)
+ const QByteArray brotliBody = QByteArray::fromBase64("DwWAaGVsbG8gd29ybGQD");
QTest::newRow("brotli-hello-world")
- << QByteArray("br") << QByteArray::fromBase64("DwWAaGVsbG8gd29ybGQD")
- << QByteArray("hello world");
+ << QByteArray("br") << brotliBody
+ << helloWorld
+ << true;
+ QTest::newRow("brotli-hello-world-no-decompress")
+ << QByteArray("br") << brotliBody
+ << helloWorld
+ << false;
#endif
#if defined(QT_BUILD_INTERNAL) && QT_CONFIG(zstd)
+ const QByteArray zstdBody = QByteArray::fromBase64("KLUv/QRYWQAAaGVsbG8gd29ybGRoaR6y");
QTest::newRow("zstandard-hello-world")
- << QByteArray("zstd") << QByteArray::fromBase64("KLUv/QRYWQAAaGVsbG8gd29ybGRoaR6y")
- << QByteArray("hello world");
+ << QByteArray("zstd") << zstdBody
+ << helloWorld
+ << true;
+ QTest::newRow("zstandard-hello-world-no-decompress")
+ << QByteArray("zstd") << zstdBody
+ << helloWorld
+ << false;
#else
qDebug("Note: ZStandard testdata is only available for developer builds.");
#endif
@@ -9621,12 +10196,19 @@ void tst_QNetworkReply::contentEncoding()
{
QFETCH(QByteArray, encoding);
QFETCH(QByteArray, body);
+ QFETCH(bool, decompress);
QString header("HTTP/1.0 200 OK\r\nContent-Encoding: %1\r\nContent-Length: %2\r\n\r\n");
header = header.arg(encoding, QString::number(body.size()));
MiniHttpServer server(header.toLatin1() + body);
QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
+ if (!decompress) {
+ // This disables decompression of the received content:
+ request.setRawHeader("accept-encoding", QLatin1String("%1").arg(encoding).toLatin1());
+ // This disables the zerocopy optimization
+ request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 0);
+ }
QNetworkReplyPtr reply(manager.get(request));
QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply));
@@ -9635,7 +10217,7 @@ void tst_QNetworkReply::contentEncoding()
{
// Check that we included the content encoding method in our Accept-Encoding header
const QByteArray &receivedData = server.receivedData;
- int start = receivedData.indexOf("Accept-Encoding");
+ int start = receivedData.indexOf("accept-encoding");
QVERIFY(start != -1);
int end = receivedData.indexOf("\r\n", start);
QVERIFY(end != -1);
@@ -9647,10 +10229,14 @@ void tst_QNetworkReply::contentEncoding()
QVERIFY2(list.contains(encoding), acceptedEncoding.data());
}
- QFETCH(QByteArray, expected);
-
- QCOMPARE(reply->bytesAvailable(), expected.size());
- QCOMPARE(reply->readAll(), expected);
+ if (decompress) {
+ QFETCH(QByteArray, expected);
+ QCOMPARE(reply->bytesAvailable(), expected.size());
+ QCOMPARE(reply->readAll(), expected);
+ } else {
+ QCOMPARE(reply->bytesAvailable(), body.size());
+ QCOMPARE(reply->readAll(), body);
+ }
}
void tst_QNetworkReply::contentEncodingBigPayload_data()
@@ -9664,7 +10250,7 @@ void tst_QNetworkReply::contentEncodingBigPayload_data()
QTest::addRow("gzip-4GB") << QByteArray("gzip") << (":/4G.gz") << fourGiB;
#if QT_CONFIG(brotli)
- QTest::addRow("brotli-4GB") << QByteArray("br") << (testDataDir + "./4G.br") << fourGiB;
+ QTest::addRow("brotli-4GB") << QByteArray("br") << (testDataDir + "/4G.br") << fourGiB;
#endif
#if defined(QT_BUILD_INTERNAL) && QT_CONFIG(zstd)
QTest::addRow("zstd-4GB") << QByteArray("zstd") << (":/4G.zst") << fourGiB;
@@ -9789,6 +10375,192 @@ void tst_QNetworkReply::downloadProgressWithContentEncoding()
QCOMPARE(bytesReceived, expected.size());
}
+void tst_QNetworkReply::contentEncodingError_data()
+{
+ QTest::addColumn<QByteArray>("encoding");
+ QTest::addColumn<QString>("path");
+ QTest::addColumn<QNetworkReply::NetworkError>("expectedError");
+
+ QTest::addRow("archive-bomb") << QByteArray("gzip") << (":/4G.gz")
+ << QNetworkReply::UnknownContentError;
+}
+
+void tst_QNetworkReply::contentEncodingError()
+{
+ QFETCH(QString, path);
+ QFile compressedFile(path);
+ QVERIFY(compressedFile.open(QIODevice::ReadOnly));
+ QByteArray body = compressedFile.readAll();
+
+ QFETCH(QByteArray, encoding);
+ QString header("HTTP/1.0 200 OK\r\nContent-Encoding: %1\r\nContent-Length: %2\r\n\r\n");
+ header = header.arg(encoding, QString::number(body.size()));
+
+ MiniHttpServer server(header.toLatin1() + body);
+
+ QNetworkRequest request(
+ QUrl(QLatin1String("http://localhost:%1").arg(QString::number(server.serverPort()))));
+ QNetworkReplyPtr reply(manager.get(request));
+
+ QTRY_VERIFY2_WITH_TIMEOUT(reply->isFinished(), qPrintable(reply->errorString()), 15000);
+ QTEST(reply->error(), "expectedError");
+}
+
+// When this test is failing it will appear flaky because it relies on the
+// timing of delivery from one socket to another in the OS.
+// + we have to send all the data at once, so the readyRead emissions are
+// compressed into a single emission, so we cannot artificially time it with
+// waits and sleeps.
+void tst_QNetworkReply::compressedReadyRead()
+{
+ // There were historically an issue where a mix of signal compression and
+ // data decompression made it so we accidentally didn't emit the final
+ // readyRead signal before emitting finished(). Test this here to make sure
+ // it happens:
+ const QByteArray gzipPayload =
+ QByteArray::fromBase64("H4sIAAAAAAAAA8tIzcnJVyjPL8pJAQCFEUoNCwAAAA==");
+ const QByteArray expected = "hello world";
+
+ QString header("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: %1\r\n\r\n");
+ header = header.arg(gzipPayload.size());
+ MiniHttpServer server(header.toLatin1()); // only send header automatically
+ server.doClose = false; // don't close and delete client socket right away
+
+ QNetworkRequest request(
+ QUrl(QLatin1String("http://localhost:%1").arg(QString::number(server.serverPort()))));
+ QNetworkReplyPtr reply(manager.get(request));
+
+ QObject::connect(reply.get(), &QNetworkReply::metaDataChanged, reply.get(),
+ [&server, &gzipPayload]() {
+ // Client received headers, now send data:
+ // We do this awkward write,flush,write dance to try to
+ // make sure the data does not all arrive at the same
+ // time. By design we send the final "=" byte by itself
+ qsizetype boundary = gzipPayload.size() - 1;
+ server.client->write(gzipPayload.sliced(0, boundary));
+ server.client->flush();
+ // Let the server take care of deleting the client once
+ // the rest of the data is written:
+ server.doClose = true;
+ server.client->write(gzipPayload.sliced(boundary));
+ });
+
+ QByteArray received;
+ QObject::connect(reply.get(), &QNetworkReply::readyRead, reply.get(),
+ [reply = reply.get(), &received]() {
+ received += reply->readAll();
+ });
+ QTRY_VERIFY(reply->isFinished());
+ QCOMPARE(received, expected);
+}
+
+void tst_QNetworkReply::notFoundWithCompression_data()
+{
+ contentEncoding_data();
+}
+
+void tst_QNetworkReply::notFoundWithCompression()
+{
+ QFETCH(QByteArray, encoding);
+ QFETCH(QByteArray, body);
+ QString header("HTTP/1.0 404 OK\r\nContent-Encoding: %1\r\nContent-Length: %2\r\n\r\n");
+ header = header.arg(encoding, QString::number(body.size()));
+
+ MiniHttpServer server(header.toLatin1() + body);
+
+ QNetworkRequest request(
+ QUrl(QLatin1String("http://localhost:%1").arg(QString::number(server.serverPort()))));
+ QNetworkReplyPtr reply(manager.get(request));
+
+ QTRY_VERIFY2_WITH_TIMEOUT(reply->isFinished(), qPrintable(reply->errorString()), 15000);
+ QCOMPARE(reply->error(), QNetworkReply::ContentNotFoundError);
+
+ QFETCH(QByteArray, expected);
+ QCOMPARE(reply->readAll(), expected);
+}
+
+void tst_QNetworkReply::qtbug68821proxyError_data()
+{
+ QTest::addColumn<QString>("proxyHost");
+ QTest::addColumn<QString>("scheme");
+ QTest::addColumn<QNetworkReply::NetworkError>("error");
+
+ QTest::newRow("invalidhost+http") << "this-host-will-never-exist.qt-project.org"
+ << "http" << QNetworkReply::ProxyNotFoundError;
+ QTest::newRow("localhost+http") << "localhost"
+ << "http" << QNetworkReply::ProxyConnectionRefusedError;
+#ifndef QT_NO_SSL
+ QTest::newRow("invalidhost+https") << "this-host-will-never-exist.qt-project.org"
+ << "https" << QNetworkReply::ProxyNotFoundError;
+ QTest::newRow("localhost+https") << "localhost"
+ << "https" << QNetworkReply::ProxyConnectionRefusedError;
+#endif
+}
+
+void tst_QNetworkReply::qtbug68821proxyError()
+{
+ auto getUnusedPort = []() -> std::optional<quint16> {
+ QTcpServer probeServer;
+ if (!probeServer.listen())
+ return std::nullopt;
+ // If we can listen on it, it was unused, and hopefully is also
+ // still unused after we stop listening.
+ return probeServer.serverPort();
+ };
+
+ auto proxyPort = getUnusedPort();
+ QVERIFY(proxyPort);
+
+ QFETCH(QString, proxyHost);
+ QNetworkProxy proxy(QNetworkProxy::HttpProxy, proxyHost, proxyPort.value());
+
+ manager.setProxy(proxy);
+
+ QFETCH(QString, scheme);
+ QNetworkReply *reply = manager.get(QNetworkRequest(QUrl(scheme + "://example.com")));
+ QSignalSpy spy(reply, &QNetworkReply::errorOccurred);
+ QVERIFY(spy.isValid());
+
+ QVERIFY(spy.wait(15000));
+
+ QFETCH(QNetworkReply::NetworkError, error);
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.at(0).at(0), error);
+}
+
+void tst_QNetworkReply::abortAndError()
+{
+ const QByteArray response =
+ R"(HTTP/1.0 500 Internal Server Error
+Content-Length: 12
+Content-Type: text/plain
+
+Hello World!)"_ba;
+
+ MiniHttpServer server(response);
+
+ QNetworkAccessManager manager;
+ QNetworkRequest req(QUrl("http://127.0.0.1:" + QString::number(server.serverPort())));
+ std::unique_ptr<QNetworkReply> reply(manager.post(req, "my data goes here"_ba));
+ QSignalSpy errorSignal(reply.get(), &QNetworkReply::errorOccurred);
+ QSignalSpy finishedSignal(reply.get(), &QNetworkReply::finished);
+
+ reply->abort();
+
+ // We don't want to print this warning in this case because it is impossible
+ // for users to avoid it.
+ QTest::failOnWarning("QNetworkReplyImplPrivate::error: Internal problem, this method must only "
+ "be called once.");
+ // Process any signals from the http thread:
+ QTest::qWait(1s);
+ if (QTest::currentTestFailed())
+ return;
+
+ QCOMPARE(finishedSignal.count(), 1);
+ QCOMPARE(errorSignal.count(), 1);
+ QCOMPARE(reply->error(), QNetworkReply::OperationCanceledError);
+}
+
// NOTE: This test must be last testcase in tst_qnetworkreply!
void tst_QNetworkReply::parentingRepliesToTheApp()
{