From 306ebe03ea13c6e0ac8de46e46d0859384954567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Fri, 12 Jun 2020 15:37:06 +0200 Subject: Http: Fix POST-to-GET redirects still uploading or transmitting CL CL = Content-Length The uploadByteDevice was kept after a redirect which caused the internals to assume that we had to upload the data. Even if this was not the case we still transmitted the Content-Length header from the first request which was now stored in two places. Fixes: QTBUG-84162 Pick-to: 5.15 Change-Id: Ic86b1ef0766ffcc50beeed96c1c915b721d40209 Reviewed-by: Timur Pocheptsov --- .../access/qnetworkreply/tst_qnetworkreply.cpp | 74 +++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) (limited to 'tests/auto/network/access/qnetworkreply') diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index 2f1e97f853..aeb5c367da 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -492,6 +492,8 @@ private Q_SLOTS: void ioHttpRedirectMultipartPost(); void ioHttpRedirectDelete(); void ioHttpRedirectCustom(); + void ioHttpRedirectWithUploadDevice_data(); + void ioHttpRedirectWithUploadDevice(); #ifndef QT_NO_SSL void putWithServerClosingConnectionImmediately(); #endif @@ -715,7 +717,8 @@ public slots: if (doubleEndlPos != -1) { const int endOfHeader = doubleEndlPos + 4; - hasContent = receivedData.startsWith("POST") || receivedData.startsWith("PUT"); + hasContent = receivedData.startsWith("POST") || receivedData.startsWith("PUT") + || receivedData.startsWith("CUSTOM_WITH_PAYLOAD"); if (hasContent && contentLength == 0) parseContentLength(); contentRead = receivedData.length() - endOfHeader; @@ -8780,6 +8783,75 @@ void tst_QNetworkReply::ioHttpRedirectCustom() QVERIFY2(target.receivedData.startsWith("CUSTOM"), "Target server called with the wrong method"); } +void tst_QNetworkReply::ioHttpRedirectWithUploadDevice_data() +{ + QTest::addColumn("method"); + QTest::addColumn("status"); + QTest::addColumn("keepMethod"); + + QTest::addRow("post-301") << QByteArray("POST") << "301 Moved Permanently" << false; + QTest::addRow("post-307") << QByteArray("POST") << "307 Temporary Redirect" << true; + + const QByteArray customVerb = QByteArray("CUSTOM_WITH_PAYLOAD"); + QTest::addRow("custom-301") << customVerb << "301 Moved Permanently" << false; + QTest::addRow("custom-307") << customVerb << "307 Temporary Redirect" << true; +} + +/* + Tests that we properly disregard the upload device when redirecting + and changing method to GET, and that it gets reset properly when + redirecting (without changing method) for POST and a custom method. +*/ +void tst_QNetworkReply::ioHttpRedirectWithUploadDevice() +{ + QFETCH(QByteArray, method); + QFETCH(QString, status); + QFETCH(bool, keepMethod); + + MiniHttpServer target(httpEmpty200Response, false); + QUrl targetUrl("http://localhost/"); + targetUrl.setPort(target.serverPort()); + + 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::ContentTypeHeader, QByteArray("text/plain")); + auto oldRedirectPolicy = manager.redirectPolicy(); + manager.setRedirectPolicy(QNetworkRequest::RedirectPolicy::NoLessSafeRedirectPolicy); + + QByteArray data = "Hello world"; + QBuffer buffer(&data); + + QNetworkReplyPtr reply; + if (method == "POST") + reply.reset(manager.post(request, &buffer)); + else + reply.reset(manager.sendCustomRequest(request, method, &buffer)); + // Restore previous policy: + manager.setRedirectPolicy(oldRedirectPolicy); + + QCOMPARE(waitForFinish(reply), int(Success)); + QByteArray expectedMethod = method; + if (!keepMethod) + expectedMethod = "GET"; + QVERIFY2(target.receivedData.startsWith(expectedMethod), "Target server called with the wrong method"); + if (keepMethod) { // keepMethod also means we resend the data + QVERIFY2(target.receivedData.endsWith(data), "Target server didn't receive the data"); + } else { + // 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"); + } +} + #ifndef QT_NO_SSL class PutWithServerClosingConnectionImmediatelyHandler: public QObject -- cgit v1.2.3