summaryrefslogtreecommitdiffstats
path: root/tests/auto/network/access/qnetworkreply
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/network/access/qnetworkreply')
-rw-r--r--tests/auto/network/access/qnetworkreply/CMakeLists.txt6
-rw-r--r--tests/auto/network/access/qnetworkreply/echo/main.cpp8
-rw-r--r--tests/auto/network/access/qnetworkreply/test/CMakeLists.txt1
-rw-r--r--tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp932
4 files changed, 748 insertions, 199 deletions
diff --git a/tests/auto/network/access/qnetworkreply/CMakeLists.txt b/tests/auto/network/access/qnetworkreply/CMakeLists.txt
index ee6f4d1ffd..9bfd90cd56 100644
--- a/tests/auto/network/access/qnetworkreply/CMakeLists.txt
+++ b/tests/auto/network/access/qnetworkreply/CMakeLists.txt
@@ -1,5 +1,11 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qnetworkreply LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
add_subdirectory(echo)
add_subdirectory(test)
diff --git a/tests/auto/network/access/qnetworkreply/echo/main.cpp b/tests/auto/network/access/qnetworkreply/echo/main.cpp
index 770b7bc47b..b10eaa745c 100644
--- a/tests/auto/network/access/qnetworkreply/echo/main.cpp
+++ b/tests/auto/network/access/qnetworkreply/echo/main.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtCore/QFile>
@@ -12,11 +12,13 @@ int main(int argc, char **)
}
QFile file;
- file.open(stdin, QFile::ReadWrite);
+ if (!file.open(stdin, QFile::ReadWrite))
+ return 1;
QByteArray data = file.readAll();
file.close();
- file.open(stdout, QFile::WriteOnly);
+ if (!file.open(stdout, QFile::WriteOnly))
+ return 1;
file.write(data);
file.close();
return 0;
diff --git a/tests/auto/network/access/qnetworkreply/test/CMakeLists.txt b/tests/auto/network/access/qnetworkreply/test/CMakeLists.txt
index 583b250932..fa353b2769 100644
--- a/tests/auto/network/access/qnetworkreply/test/CMakeLists.txt
+++ b/tests/auto/network/access/qnetworkreply/test/CMakeLists.txt
@@ -29,6 +29,7 @@ qt_internal_add_test(tst_qnetworkreply
Qt::NetworkPrivate
TESTDATA ${test_data}
QT_TEST_SERVER_LIST "vsftpd" "apache2" "ftp-proxy" "danted" "squid"
+ BUNDLE_ANDROID_OPENSSL_LIBS
)
add_dependencies(tst_qnetworkreply echo)
diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
index 7e35712a87..97e6fa8518 100644
--- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
+++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtNetwork/qtnetworkglobal.h>
@@ -91,6 +91,7 @@ Q_DECLARE_METATYPE(QNetworkProxyQuery)
typedef QSharedPointer<QNetworkReply> QNetworkReplyPtr;
using namespace Qt::StringLiterals;
+using namespace std::chrono_literals;
#if QT_CONFIG(ssl)
QT_BEGIN_NAMESPACE
@@ -128,7 +129,30 @@ class tst_QNetworkReply: public QObject
static QString tempRedirectReplyStr() {
QString s = "HTTP/1.1 307 Temporary Redirect\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
+ "location: %1\r\n"
+ "\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;
@@ -216,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)
@@ -233,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();
@@ -240,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();
@@ -292,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();
@@ -506,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();
@@ -526,6 +560,14 @@ private Q_SLOTS:
void notFoundWithCompression_data();
void notFoundWithCompression();
+ void qhttpPartDebug_data();
+ void qhttpPartDebug();
+
+ void qtbug68821proxyError_data();
+ void qtbug68821proxyError();
+
+ void abortAndError();
+
// NOTE: This test must be last!
void parentingRepliesToTheApp();
private:
@@ -610,7 +652,8 @@ public:
int totalConnections;
bool stopTransfer = false;
- bool hasContent = false;
+ bool checkedContentLength = false;
+ bool foundContentLength = false;
int contentRead = 0;
int contentLength = 0;
@@ -642,6 +685,7 @@ public:
{
contentLength = 0;
receivedData.clear();
+ foundContentLength = false;
}
protected:
@@ -698,8 +742,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;
@@ -739,12 +788,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)
- parseContentLength();
contentRead = receivedData.size() - endOfHeader;
- if (hasContent && contentRead < contentLength)
+
+ if (!checkedContentLength) {
+ parseContentLength();
+ checkedContentLength = true;
+ }
+
+ if (contentRead < contentLength)
return;
// multiple requests incoming. remove the bytes of the current one
@@ -845,7 +896,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;
}
@@ -1988,6 +2039,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()
{
@@ -2406,6 +2704,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();
@@ -2416,7 +2756,7 @@ void tst_QNetworkReply::postToHttp()
QUrl url("http://" + QtNetworkSettings::httpServerName() + "/qtest/cgi-bin/md5sum.cgi");
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
QNetworkReplyPtr reply;
QFETCH(QByteArray, data);
@@ -2443,7 +2783,7 @@ void tst_QNetworkReply::postToHttpSynchronous()
QUrl url("http://" + QtNetworkSettings::httpServerName() + "/qtest/cgi-bin/md5sum.cgi");
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
request.setAttribute(
QNetworkRequest::SynchronousRequestAttribute,
@@ -2504,8 +2844,8 @@ void tst_QNetworkReply::postToHttpMultipart_data()
QHttpMultiPart *customMultiPart = new QHttpMultiPart;
customMultiPart->append(textPart);
- expectedData = "header: Content-Type, value: 'text/plain'\n"
- "header: Content-Disposition, value: 'form-data; name=\"text\"'\n"
+ expectedData = "header: content-type, value: 'text/plain'\n"
+ "header: content-disposition, value: 'form-data; name=\"text\"'\n"
"content: 7 bytes\n"
"\n";
QTest::newRow("text-custom") << url << customMultiPart << expectedData << QByteArray("custom");
@@ -2541,18 +2881,18 @@ void tst_QNetworkReply::postToHttpMultipart_data()
multiPart3->append(textPart);
multiPart3->append(textPart2);
multiPart3->append(textPart3);
- expectedData = "header: Content-Type, value: 'text/plain'\n"
- "header: Content-Disposition, value: 'form-data; name=\"text\"'\n"
+ expectedData = "header: content-type, value: 'text/plain'\n"
+ "header: content-disposition, value: 'form-data; name=\"text\"'\n"
"content: 7 bytes\n"
"\n"
- "header: Content-Type, value: 'text/plain'\n"
- "header: myRawHeader, value: 'myValue'\n"
- "header: Content-Disposition, value: 'form-data; name=\"text2\"'\n"
+ "header: content-type, value: 'text/plain'\n"
+ "header: myrawheader, value: 'myValue'\n"
+ "header: content-disposition, value: 'form-data; name=\"text2\"'\n"
"content: some more bytes\n"
"\n"
- "header: Content-Type, value: 'text/plain'\n"
- "header: Content-Disposition, value: 'form-data; name=\"text3\"'\n"
- "header: Content-Location, value: 'http://my.test.location.tld'\n"
+ "header: content-type, value: 'text/plain'\n"
+ "header: content-disposition, value: 'form-data; name=\"text3\"'\n"
+ "header: content-location, value: 'http://my.test.location.tld'\n"
"content: even more bytes\n\n";
QTest::newRow("text-text-text") << url << multiPart3 << expectedData << QByteArray("alternative");
@@ -2775,6 +3115,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();
@@ -2930,7 +3311,7 @@ void tst_QNetworkReply::postToHttps()
QSslConfiguration conf;
conf.setCaCertificates(certs);
request.setSslConfiguration(conf);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
QNetworkReplyPtr reply;
QFETCH(QByteArray, data);
@@ -2964,7 +3345,7 @@ void tst_QNetworkReply::postToHttpsSynchronous()
QSslConfiguration conf;
conf.setCaCertificates(certs);
request.setSslConfiguration(conf);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
request.setAttribute(
QNetworkRequest::SynchronousRequestAttribute,
@@ -3166,7 +3547,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;
@@ -3181,7 +3562,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());
@@ -3372,7 +3753,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));
@@ -3397,7 +3780,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"));
@@ -3527,7 +3910,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")
@@ -3852,7 +4235,6 @@ 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.size(), 0);
@@ -3996,7 +4378,7 @@ void tst_QNetworkReply::ioGetFromHttpBrokenServer()
QVERIFY(reply->error() != QNetworkReply::NoError);
}
-void tst_QNetworkReply::ioGetFromHttpStatus100_data()
+void tst_QNetworkReply::ioGetFromHttpStatusInformational_data()
{
QTest::addColumn<QByteArray>("dataToSend");
QTest::addColumn<int>("statusCode");
@@ -4007,9 +4389,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);
@@ -4063,7 +4461,7 @@ void tst_QNetworkReply::ioGetFromHttpWithCache_data()
QByteArray reply200 =
"HTTP/1.0 200\r\n"
"Connection: keep-alive\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"Cache-control: no-store\r\n"
"Content-length: 8\r\n"
"\r\n"
@@ -4198,7 +4596,7 @@ void tst_QNetworkReply::ioGetFromHttpWithCache_data()
QByteArray reply206 =
"HTTP/1.0 206\r\n"
"Connection: keep-alive\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"Cache-control: no-cache\r\n"
"Content-Range: bytes 2-6/8\r\n"
"Content-length: 4\r\n"
@@ -4693,6 +5091,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)
}
@@ -4803,7 +5205,7 @@ void tst_QNetworkReply::ioPostToHttpFromFile()
QUrl url("http://" + QtNetworkSettings::httpServerName() + "/qtest/cgi-bin/md5sum.cgi");
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
QNetworkReplyPtr reply(manager.post(request, &sourceFile));
@@ -4880,7 +5282,7 @@ void tst_QNetworkReply::ioPostToHttpFromSocket()
socketpair.endPoints[0]->write(data);
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
manager.setProxy(proxy);
QNetworkReplyPtr reply(manager.post(request, socketpair.endPoints[1]));
@@ -4954,7 +5356,7 @@ void tst_QNetworkReply::ioPostToHttpFromSocketSynchronous()
QUrl url("http://" + QtNetworkSettings::httpServerName() + "/qtest/cgi-bin/md5sum.cgi");
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
request.setAttribute(
QNetworkRequest::SynchronousRequestAttribute,
true);
@@ -4985,7 +5387,7 @@ void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileToEnd()
QUrl url = "http://" + QtNetworkSettings::httpServerName() + "/qtest/protected/cgi-bin/md5sum.cgi";
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
QNetworkReplyPtr reply(manager.post(request, &sourceFile));
connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
@@ -5011,7 +5413,7 @@ void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileFiveBytes()
QUrl url = "http://" + QtNetworkSettings::httpServerName() + "/qtest/protected/cgi-bin/md5sum.cgi";
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
// only send 5 bytes
request.setHeader(QNetworkRequest::ContentLengthHeader, 5);
QVERIFY(request.header(QNetworkRequest::ContentLengthHeader).isValid());
@@ -5042,7 +5444,7 @@ void tst_QNetworkReply::ioPostToHttpFromMiddleOfQBufferFiveBytes()
QUrl url = "http://" + QtNetworkSettings::httpServerName() + "/qtest/protected/cgi-bin/md5sum.cgi";
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
QNetworkReplyPtr reply(manager.post(request, &uploadBuffer));
connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
@@ -5070,7 +5472,7 @@ void tst_QNetworkReply::ioPostToHttpNoBufferFlag()
QUrl url = "http://" + QtNetworkSettings::httpServerName() + "/qtest/protected/cgi-bin/md5sum.cgi";
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
// disallow buffering
request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, true);
request.setHeader(QNetworkRequest::ContentLengthHeader, data.size());
@@ -5155,7 +5557,7 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress()
QUrl url = QUrl(QLatin1String("https://127.0.0.1:") + QString::number(server.serverPort()) + QLatin1Char('/'));
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
QNetworkReplyPtr reply(manager.post(request, sourceFile));
QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
@@ -5309,7 +5711,7 @@ void tst_QNetworkReply::ioPostToHttpUploadProgress()
// create the request
QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort()));
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
QNetworkReplyPtr reply(manager.post(request, &sourceFile));
QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
@@ -5377,18 +5779,14 @@ void tst_QNetworkReply::emitAllUploadProgressSignals()
QUrl url = QUrl(QLatin1String("http://127.0.0.1:") + QString::number(server.serverPort()) + QLatin1Char('/'));
QNetworkRequest normalRequest(url);
- normalRequest.setRawHeader("Content-Type", "application/octet-stream");
+ normalRequest.setRawHeader("content-type", "application/octet-stream");
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)));
@@ -5432,7 +5830,7 @@ void tst_QNetworkReply::ioPostToHttpEmptyUploadProgress()
// create the request
QUrl url = QUrl(QLatin1String("http://127.0.0.1:") + QString::number(server.serverPort()) + QLatin1Char('/'));
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
QNetworkReplyPtr reply(manager.post(request, &buffer));
QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
@@ -5478,7 +5876,11 @@ void tst_QNetworkReply::lastModifiedHeaderForFile()
QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply));
QDateTime header = reply->header(QNetworkRequest::LastModifiedHeader).toDateTime();
- QCOMPARE(header, fileInfo.lastModified());
+ QDateTime expected = fileInfo.lastModified();
+ // remove msecs, HTTP dates don't support it
+ expected = expected.addMSecs(-expected.time().msec());
+
+ QCOMPARE(header.toUTC(), expected.toUTC());
}
void tst_QNetworkReply::lastModifiedHeaderForHttp()
@@ -5784,7 +6186,7 @@ void tst_QNetworkReply::receiveCookiesFromHttp()
QByteArray data = cookieString.toLatin1() + '\n';
QUrl url("http://" + QtNetworkSettings::httpServerName() + "/qtest/cgi-bin/set-cookie.cgi");
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
QNetworkReplyPtr reply;
RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
@@ -5812,7 +6214,7 @@ void tst_QNetworkReply::receiveCookiesFromHttpSynchronous()
QUrl url("http://" + QtNetworkSettings::httpServerName() + "/qtest/cgi-bin/set-cookie.cgi");
QNetworkRequest request(url);
- request.setRawHeader("Content-Type", "application/octet-stream");
+ request.setRawHeader("content-type", "application/octet-stream");
request.setAttribute(
QNetworkRequest::SynchronousRequestAttribute,
true);
@@ -5995,7 +6397,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
@@ -6012,10 +6414,11 @@ void tst_QNetworkReply::httpProxyCommands()
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
@@ -6052,14 +6455,6 @@ struct QThreadCleanup
}
};
-struct QDeleteLaterCleanup
-{
- static inline void cleanup(QObject *o)
- {
- o->deleteLater();
- }
-};
-
#if QT_CONFIG(networkproxy)
void tst_QNetworkReply::httpProxyCommandsSynchronous()
{
@@ -6071,7 +6466,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);
@@ -6229,7 +6624,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)
@@ -6240,7 +6634,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)
@@ -6248,26 +6642,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);
@@ -6773,7 +7181,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;
@@ -7629,7 +8050,7 @@ void tst_QNetworkReply::qtbug28035browserDoesNotLoadQtProjectOrgCorrectly() {
QByteArray getReply =
"HTTP/1.1 200\r\n"
"Connection: keep-alive\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"Cache-control: max-age = 6000\r\n"
"\r\n"
"GET";
@@ -7637,7 +8058,7 @@ void tst_QNetworkReply::qtbug28035browserDoesNotLoadQtProjectOrgCorrectly() {
QByteArray postReply =
"HTTP/1.1 200\r\n"
"Connection: keep-alive\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"Cache-control: max-age = 6000\r\n"
"Content-length: 4\r\n"
"\r\n"
@@ -7646,7 +8067,7 @@ void tst_QNetworkReply::qtbug28035browserDoesNotLoadQtProjectOrgCorrectly() {
QByteArray putReply =
"HTTP/1.1 201\r\n"
"Connection: keep-alive\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"Cache-control: max-age = 6000\r\n"
"\r\n";
@@ -7684,7 +8105,7 @@ void tst_QNetworkReply::qtbug28035browserDoesNotLoadQtProjectOrgCorrectly() {
server.clearHeaderParserState();
server.setDataToTransmit(postReply);
- request.setRawHeader("Content-Type", "text/plain");
+ request.setRawHeader("content-type", "text/plain");
reply.reset(manager.post(request, postData));
QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply));
@@ -7871,7 +8292,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();
@@ -8180,7 +8601,7 @@ void tst_QNetworkReply::dontInsertPartialContentIntoTheCache()
QByteArray reply206 =
"HTTP/1.0 206\r\n"
"Connection: keep-alive\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"Cache-control: no-cache\r\n"
"Content-Range: bytes 2-6/8\r\n"
"Content-length: 4\r\n"
@@ -8220,7 +8641,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()
@@ -8237,16 +8658,16 @@ void tst_QNetworkReply::synchronousAuthenticationCache()
"WWW-Authenticate: Basic realm=\"QNetworkAccessManager Test Realm\"\r\n"
"Content-Length: 4\r\n"
"Connection: close\r\n"
- "Content-Type: text/plain\r\n"
+ "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") {
dataToTransmit =
"HTTP/1.0 200 OK\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"Content-Length: 2\r\n"
"\r\n"
"OK";
@@ -8261,7 +8682,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
@@ -8400,31 +8821,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.size(); ++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.size(); ++a) {
- QVERIFY(replies.at(a)->isFinished());
- QCOMPARE(errorSpies.at(a)->size(), 1);
- errorSpies.at(a)->deleteLater();
- QCOMPARE(finishedSpies.at(a)->size(), 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);
}
}
@@ -8493,7 +8916,7 @@ 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.size() > 0);
@@ -8614,7 +9037,7 @@ void tst_QNetworkReply::ioHttpRedirectErrors_data()
QTest::addColumn<QNetworkReply::NetworkError>("error");
QString tempRedirectReply = QString("HTTP/1.1 307 Temporary Redirect\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"location: http://localhost:%1\r\n\r\n");
QTest::newRow("too-many-redirects") << "http://localhost" << tempRedirectReply << QNetworkReply::TooManyRedirectsError;
@@ -8897,7 +9320,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));
}
@@ -8922,7 +9345,7 @@ void tst_QNetworkReply::ioHttpRedirect()
targetUrl.setPort(target.serverPort());
QString redirectReply = QStringLiteral("HTTP/1.1 %1\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"location: %2\r\n"
"\r\n").arg(status, targetUrl.toString());
MiniHttpServer redirectServer(redirectReply.toLatin1(), false);
@@ -8950,7 +9373,7 @@ 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"
+ "content-type: text/plain\r\n"
"Cache-Control: no-cache\r\n"
"\r\nHello";
@@ -8960,7 +9383,7 @@ void tst_QNetworkReply::ioHttpRedirectWithCache()
// A cache-able redirect reply
QString redirectReply = QStringLiteral("HTTP/1.1 308\r\n"
- "Content-Type: text/plain\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());
@@ -9072,7 +9495,7 @@ void tst_QNetworkReply::ioHttpRedirectPostPut()
QUrl targetUrl("http://" + QtNetworkSettings::httpServerName() + "/qtest/cgi-bin/md5sum.cgi");
QString redirectReply = QStringLiteral("HTTP/1.1 %1\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"location: %2\r\n"
"\r\n").arg(status, targetUrl.toString());
MiniHttpServer redirectServer(redirectReply.toLatin1());
@@ -9226,7 +9649,7 @@ void tst_QNetworkReply::ioHttpRedirectWithUploadDevice()
targetUrl.setPort(target.serverPort());
QString redirectReply = QStringLiteral("HTTP/1.1 %1\r\n"
- "Content-Type: text/plain\r\n"
+ "content-type: text/plain\r\n"
"location: %2\r\n"
"\r\n").arg(status, targetUrl.toString());
MiniHttpServer redirectServer(redirectReply.toLatin1());
@@ -9260,8 +9683,8 @@ void tst_QNetworkReply::ioHttpRedirectWithUploadDevice()
// we shouldn't send Content-Length with not content (esp. for GET)
QVERIFY2(!target.receivedData.contains("Content-Length"),
"Target server should not have received a Content-Length header");
- QVERIFY2(!target.receivedData.contains("Content-Type"),
- "Target server should not have received a Content-Type header");
+ QVERIFY2(!target.receivedData.contains("content-type"),
+ "Target server should not have received a content-type header");
}
}
@@ -9592,82 +10015,64 @@ void tst_QNetworkReply::autoDeleteReplies()
}
}
-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)));
+ 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");
- QCOMPARE(waitForFinish(reply), int(Success));
-
- QCOMPARE(spy.size(), 0);
- QVERIFY(reply->error() == QNetworkReply::NoError);
-
- request.setTransferTimeout(1000);
- server.stopTransfer = true;
-
- QNetworkReplyPtr reply2(manager.get(request));
- QSignalSpy spy2(reply2.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError)));
-
- QCOMPARE(waitForFinish(reply2), int(Failure));
-
- QCOMPARE(spy2.size(), 1);
- QVERIFY(reply2->error() == QNetworkReply::OperationCanceledError);
-
- request.setTransferTimeout(0);
- manager.setTransferTimeout(1000);
-
- QNetworkReplyPtr reply3(manager.get(request));
- QSignalSpy spy3(reply3.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError)));
-
- QCOMPARE(waitForFinish(reply3), int(Failure));
-
- QCOMPARE(spy3.size(), 1);
- QVERIFY(reply3->error() == QNetworkReply::OperationCanceledError);
+ 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;
- 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()
{
- MiniHttpServer server(tst_QNetworkReply::httpEmpty200Response, false);
+ 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); });
- 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.size(), 0);
- QVERIFY(reply->error() == QNetworkReply::NoError);
-
- request.setTransferTimeout(1000);
+ MiniHttpServer server(tst_QNetworkReply::httpEmpty200Response, false);
server.stopTransfer = true;
- QNetworkReplyPtr reply2(manager.post(request, postData));
- QSignalSpy spy2(reply2.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError)));
-
- QCOMPARE(waitForFinish(reply2), int(Failure));
-
- QCOMPARE(spy2.size(), 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));
+ QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
+ request.setRawHeader("content-type", "application/octet-stream");
+ 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(spy3.size(), 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()
@@ -9699,7 +10104,7 @@ void tst_QNetworkReply::moreActivitySignals()
QNetworkRequest request(url);
QNetworkReplyPtr reply;
if (postWithData) {
- request.setRawHeader("Content-Type", "text/plain");
+ request.setRawHeader("content-type", "text/plain");
reply.reset(manager.post(request, "Hello, world!"));
} else {
reply.reset(manager.get(request));
@@ -9720,7 +10125,7 @@ void tst_QNetworkReply::moreActivitySignals()
// 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");
+ request.setRawHeader("content-type", "text/plain");
secondreply.reset(manager.post(request, "Hello, world!"));
} else {
secondreply.reset(manager.get(request));
@@ -9807,7 +10212,7 @@ void tst_QNetworkReply::contentEncoding()
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());
+ request.setRawHeader("accept-encoding", QLatin1String("%1").arg(encoding).toLatin1());
// This disables the zerocopy optimization
request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 0);
}
@@ -9819,7 +10224,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);
@@ -10081,6 +10486,141 @@ void tst_QNetworkReply::notFoundWithCompression()
QCOMPARE(reply->readAll(), expected);
}
+void tst_QNetworkReply::qhttpPartDebug_data()
+{
+ QTest::addColumn<QByteArray>("header_data");
+ QTest::addColumn<QByteArray>("raw_header_data");
+ QTest::addColumn<QList<QByteArray>>("expected_header_values");
+ QTest::addColumn<bool>("overwrite");
+
+ QTest::newRow("header-data-set") << "form-data; name=\"prompt\""_ba << ""_ba
+ << (QList<QByteArray>() << "form-data; name=\"prompt\""_ba) << false;
+ QTest::newRow("raw-header-data-set") << ""_ba << "thisismykeyherebutnotreally"_ba
+ << (QList<QByteArray>() << "thisismykeyherebutnotreally"_ba) << false;
+ QTest::newRow("both-set") << "form-data; name=\"prompt\""_ba
+ << "thisismykeyherebutnotreally"_ba
+ << (QList<QByteArray>()
+ << "form-data; name=\"prompt\""_ba
+ << "thisismykeyherebutnotreally"_ba) << false;
+ QTest::newRow("overwrite") << "form-data; name=\"prompt\""_ba
+ << "thisismykeyherebutnotreally"_ba
+ << (QList<QByteArray>()
+ << "thisismykeyherebutnotreally"_ba
+ << "thisismykeyherebutnotreally"_ba) << true;
+}
+
+void tst_QNetworkReply::qhttpPartDebug()
+{
+ QFETCH(const QByteArray, header_data);
+ QFETCH(const QByteArray, raw_header_data);
+ QFETCH(const QList<QByteArray>, expected_header_values);
+ QFETCH(bool, overwrite);
+
+ QHttpPart httpPart;
+
+ if (!header_data.isEmpty())
+ httpPart.setHeader(QNetworkRequest::ContentDispositionHeader, header_data);
+
+ if (!raw_header_data.isEmpty())
+ httpPart.setRawHeader("Authorization", raw_header_data);
+
+ if (overwrite)
+ httpPart.setRawHeader("Content-Disposition", raw_header_data);
+
+ QByteArray msg;
+ {
+ QBuffer buf(&msg);
+ QVERIFY(buf.open(QIODevice::WriteOnly));
+ QDebug debug(&buf);
+ debug << httpPart;
+ }
+
+ for (const auto &value : expected_header_values)
+ QVERIFY2(msg.contains(value), "Missing header value: " + value);
+}
+
+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()
{