summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp152
1 files changed, 149 insertions, 3 deletions
diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
index d236ef0490..d22850ba4e 100644
--- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
+++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
@@ -491,6 +491,10 @@ private Q_SLOTS:
void ioHttpRedirect_data();
void ioHttpRedirect();
void ioHttpRedirectFromLocalToRemote();
+ void ioHttpRedirectPost_data();
+ void ioHttpRedirectPost();
+ void ioHttpRedirectMultipartPost_data();
+ void ioHttpRedirectMultipartPost();
#ifndef QT_NO_SSL
void putWithServerClosingConnectionImmediately();
#endif
@@ -542,7 +546,7 @@ static void setupSslServer(QSslSocket* serverSocket)
}
#endif
-// Does not work for POST/PUT!
+// Does not work for PUT! Limited support for POST.
class MiniHttpServer: public QTcpServer
{
Q_OBJECT
@@ -557,6 +561,10 @@ public:
bool multiple;
int totalConnections;
+ bool hasContent = false;
+ int contentRead = 0;
+ int contentLength = 0;
+
MiniHttpServer(const QByteArray &data, bool ssl = false, QThread *thread = 0, bool useipv6 = false)
: dataToTransmit(data), doClose(true), doSsl(ssl), ipv6(useipv6),
multiple(false), totalConnections(0)
@@ -633,6 +641,18 @@ private:
this, SLOT(slotError(QAbstractSocket::SocketError)));
}
+ void parseContentLength()
+ {
+ int index = receivedData.indexOf("Content-Length:");
+ 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;
+ contentLength = num.toInt(&ok);
+ if (!ok)
+ contentLength = -1;
+ }
+
private slots:
#ifndef QT_NO_SSL
void slotSslErrors(const QList<QSslError>& errors)
@@ -654,12 +674,20 @@ public slots:
{
Q_ASSERT(!client.isNull());
receivedData += client->readAll();
- int doubleEndlPos = receivedData.indexOf("\r\n\r\n");
+ const int doubleEndlPos = receivedData.indexOf("\r\n\r\n");
if (doubleEndlPos != -1) {
+ const int endOfHeader = doubleEndlPos + 4;
+ hasContent = receivedData.startsWith("POST");
+ if (hasContent && contentLength == 0)
+ parseContentLength();
+ contentRead = receivedData.length() - endOfHeader;
+ if (hasContent && contentRead < contentLength)
+ return;
+
// multiple requests incoming. remove the bytes of the current one
if (multiple)
- receivedData.remove(0, doubleEndlPos+4);
+ receivedData.remove(0, endOfHeader);
reply();
}
@@ -8518,6 +8546,124 @@ void tst_QNetworkReply::ioHttpRedirectFromLocalToRemote()
QCOMPARE(reply->readAll(), reference.readAll());
}
+void tst_QNetworkReply::ioHttpRedirectPost_data()
+{
+ QTest::addColumn<QString>("status");
+ QTest::addColumn<QByteArray>("data");
+ QTest::addColumn<QString>("contentType");
+
+ QByteArray data;
+ data = "hello world";
+ QTest::addRow("307") << "307 Temporary Redirect" << data << "text/plain";
+ QString permanentRedirect = "308 Permanent Redirect";
+ QTest::addRow("308") << permanentRedirect << data << "text/plain";
+
+ // Some data from ::putToFile_data
+ data = "";
+ QTest::newRow("empty") << permanentRedirect << data << "application/octet-stream";
+
+ data = QByteArray("abcd\0\1\2\abcd",12);
+ QTest::newRow("with-nul") << permanentRedirect << data << "application/octet-stream";
+
+ data = QByteArray(4097, '\4');
+ QTest::newRow("4k+1") << permanentRedirect << data << "application/octet-stream";
+
+ data = QByteArray(128*1024+1, '\177');
+ QTest::newRow("128k+1") << permanentRedirect << data << "application/octet-stream";
+
+ data = QByteArray(2*1024*1024+1, '\177');
+ QTest::newRow("2MB+1") << permanentRedirect << data << "application/octet-stream";
+}
+
+void tst_QNetworkReply::ioHttpRedirectPost()
+{
+ QFETCH(QString, status);
+ QFETCH(QByteArray, data);
+ QFETCH(QString, contentType);
+
+ QUrl targetUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
+
+ QString redirectReply = QStringLiteral("HTTP/1.1 %1\r\n"
+ "Content-Type: text/plain\r\n"
+ "location: %2\r\n"
+ "\r\n").arg(status, targetUrl.toString());
+ MiniHttpServer redirectServer(redirectReply.toLatin1());
+ QUrl url("http://localhost/");
+ url.setPort(redirectServer.serverPort());
+ QNetworkRequest request(url);
+ request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, contentType);
+ auto oldRedirectPolicy = manager.redirectPolicy();
+ manager.setRedirectPolicy(QNetworkRequest::RedirectPolicy::NoLessSafeRedirectPolicy);
+
+ QNetworkReplyPtr reply(manager.post(request, data));
+ // Restore previous policy:
+ manager.setRedirectPolicy(oldRedirectPolicy);
+
+ QCOMPARE(waitForFinish(reply), int(Success));
+ QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
+}
+
+void tst_QNetworkReply::ioHttpRedirectMultipartPost_data()
+{
+ postToHttpMultipart_data();
+}
+
+void tst_QNetworkReply::ioHttpRedirectMultipartPost()
+{
+ // Note: This code is heavily based on postToHttpMultipart
+ QFETCH(QUrl, url);
+
+ static QSet<QByteArray> boundaries;
+
+ QNetworkReplyPtr reply;
+
+ QFETCH(QHttpMultiPart *, multiPart);
+ QFETCH(QByteArray, expectedReplyData);
+ QFETCH(QByteArray, contentType);
+
+ QString redirectReply = tempRedirectReplyStr().arg(url.toString());
+ MiniHttpServer redirectServer(redirectReply.toLatin1());
+ QUrl redirectUrl("http://localhost/");
+ redirectUrl.setPort(redirectServer.serverPort());
+ QNetworkRequest request(redirectUrl);
+
+ // Restore policy when we leave this scope:
+ struct PolicyRestorer
+ {
+ QNetworkAccessManager &qnam;
+ QNetworkRequest::RedirectPolicy policy;
+ PolicyRestorer(QNetworkAccessManager &qnam)
+ : qnam(qnam), policy(qnam.redirectPolicy())
+ { qnam.setRedirectPolicy(QNetworkRequest::RedirectPolicy::NoLessSafeRedirectPolicy); }
+ ~PolicyRestorer() { qnam.setRedirectPolicy(policy); }
+ } policyRestorer(manager);
+
+ // hack for testing the setting of the content-type header by hand:
+ if (contentType == "custom") {
+ QByteArray contentType("multipart/custom; boundary=\"" + multiPart->boundary() + "\"");
+ request.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
+ }
+
+ QVERIFY2(! boundaries.contains(multiPart->boundary()), "boundary '" + multiPart->boundary() + "' has been created twice");
+ boundaries.insert(multiPart->boundary());
+
+ RUN_REQUEST(runMultipartRequest(request, reply, multiPart, "POST"));
+ multiPart->deleteLater();
+
+ QCOMPARE(reply->url(), url);
+ QCOMPARE(reply->error(), QNetworkReply::NoError);
+
+ QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 OK
+
+ QVERIFY(multiPart->boundary().count() > 20); // check that there is randomness after the "boundary_.oOo._" string
+ QVERIFY(multiPart->boundary().count() < 70);
+ QByteArray replyData = reply->readAll();
+
+ expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n");
+// QEXPECT_FAIL("nested", "the server does not understand nested multipart messages", Continue); // see above
+ QCOMPARE(replyData, expectedReplyData);
+}
+
#ifndef QT_NO_SSL
class PutWithServerClosingConnectionImmediatelyHandler: public QObject