Fix redirecting all the other methods for HTTP 307 and 308

c4cf90b1f739c47383672de3d66b1d9d5427f5db made POST requests be
redirected properly, but this wasn't enough and should have included
every method/verb.

Change-Id: I37b12dc9fdffcbf2aadbd2360d4fc2584c024939
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
This commit is contained in:
Mårten Nordheim 2017-10-19 12:22:16 +02:00 committed by Liang Qi
parent 7e7683cabb
commit 18f0a45964
2 changed files with 73 additions and 20 deletions

View File

@ -1110,16 +1110,14 @@ QNetworkAccessManager::Operation QNetworkReplyHttpImplPrivate::getRedirectOperat
// HTTP status code can be used to decide if we can redirect with a GET
// operation or not. See http://www.ietf.org/rfc/rfc2616.txt [Sec 10.3] for
// more details
Q_UNUSED(httpStatus);
// We MUST keep using the verb that was used originally when being redirected with 307 or 308.
if (httpStatus == 307 || httpStatus == 308)
return currentOp;
switch (currentOp) {
case QNetworkAccessManager::HeadOperation:
return QNetworkAccessManager::HeadOperation;
case QNetworkAccessManager::PostOperation:
// We MUST keep using POST when being redirected with 307 or 308.
if (statusCode == 307 || statusCode == 308)
return QNetworkAccessManager::PostOperation;
break;
default:
break;
}

View File

@ -491,10 +491,12 @@ private Q_SLOTS:
void ioHttpRedirect_data();
void ioHttpRedirect();
void ioHttpRedirectFromLocalToRemote();
void ioHttpRedirectPost_data();
void ioHttpRedirectPost();
void ioHttpRedirectPostPut_data();
void ioHttpRedirectPostPut();
void ioHttpRedirectMultipartPost_data();
void ioHttpRedirectMultipartPost();
void ioHttpRedirectDelete();
void ioHttpRedirectCustom();
#ifndef QT_NO_SSL
void putWithServerClosingConnectionImmediately();
#endif
@ -546,7 +548,7 @@ static void setupSslServer(QSslSocket* serverSocket)
}
#endif
// Does not work for PUT! Limited support for POST.
// Limited support for POST and PUT.
class MiniHttpServer: public QTcpServer
{
Q_OBJECT
@ -678,7 +680,7 @@ public slots:
if (doubleEndlPos != -1) {
const int endOfHeader = doubleEndlPos + 4;
hasContent = receivedData.startsWith("POST");
hasContent = receivedData.startsWith("POST") || receivedData.startsWith("PUT");
if (hasContent && contentLength == 0)
parseContentLength();
contentRead = receivedData.length() - endOfHeader;
@ -8546,37 +8548,46 @@ void tst_QNetworkReply::ioHttpRedirectFromLocalToRemote()
QCOMPARE(reply->readAll(), reference.readAll());
}
void tst_QNetworkReply::ioHttpRedirectPost_data()
void tst_QNetworkReply::ioHttpRedirectPostPut_data()
{
QTest::addColumn<bool>("usePost");
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";
QTest::addRow("post-307") << true << "307 Temporary Redirect" << data << "text/plain";
QTest::addRow("put-307") << false << "307 Temporary Redirect" << data << "text/plain";
QString permanentRedirect = "308 Permanent Redirect";
QTest::addRow("308") << permanentRedirect << data << "text/plain";
QTest::addRow("post-308") << true << permanentRedirect << data << "text/plain";
QTest::addRow("put-308") << false << permanentRedirect << data << "text/plain";
// Some data from ::putToFile_data
data = "";
QTest::newRow("empty") << permanentRedirect << data << "application/octet-stream";
QTest::newRow("post-empty") << true << permanentRedirect << data << "application/octet-stream";
QTest::newRow("put-empty") << false << permanentRedirect << data << "application/octet-stream";
data = QByteArray("abcd\0\1\2\abcd",12);
QTest::newRow("with-nul") << permanentRedirect << data << "application/octet-stream";
QTest::newRow("post-with-nul") << true << permanentRedirect << data << "application/octet-stream";
QTest::newRow("put-with-nul") << false << permanentRedirect << data << "application/octet-stream";
data = QByteArray(4097, '\4');
QTest::newRow("4k+1") << permanentRedirect << data << "application/octet-stream";
QTest::newRow("post-4k+1") << true << permanentRedirect << data << "application/octet-stream";
QTest::newRow("put-4k+1") << false << permanentRedirect << data << "application/octet-stream";
data = QByteArray(128*1024+1, '\177');
QTest::newRow("128k+1") << permanentRedirect << data << "application/octet-stream";
QTest::newRow("post-128k+1") << true << permanentRedirect << data << "application/octet-stream";
QTest::newRow("put-128k+1") << false << permanentRedirect << data << "application/octet-stream";
data = QByteArray(2*1024*1024+1, '\177');
QTest::newRow("2MB+1") << permanentRedirect << data << "application/octet-stream";
QTest::newRow("post-2MB+1") << true << permanentRedirect << data << "application/octet-stream";
QTest::newRow("put-2MB+1") << false << permanentRedirect << data << "application/octet-stream";
}
void tst_QNetworkReply::ioHttpRedirectPost()
void tst_QNetworkReply::ioHttpRedirectPostPut()
{
QFETCH(bool, usePost);
QFETCH(QString, status);
QFETCH(QByteArray, data);
QFETCH(QString, contentType);
@ -8595,7 +8606,7 @@ void tst_QNetworkReply::ioHttpRedirectPost()
auto oldRedirectPolicy = manager.redirectPolicy();
manager.setRedirectPolicy(QNetworkRequest::RedirectPolicy::NoLessSafeRedirectPolicy);
QNetworkReplyPtr reply(manager.post(request, data));
QNetworkReplyPtr reply(usePost ? manager.post(request, data) : manager.put(request, data));
// Restore previous policy:
manager.setRedirectPolicy(oldRedirectPolicy);
@ -8664,6 +8675,50 @@ void tst_QNetworkReply::ioHttpRedirectMultipartPost()
QCOMPARE(replyData, expectedReplyData);
}
void tst_QNetworkReply::ioHttpRedirectDelete()
{
MiniHttpServer target(httpEmpty200Response, false);
QUrl targetUrl("http://localhost/");
targetUrl.setPort(target.serverPort());
QString redirectReply = tempRedirectReplyStr().arg(targetUrl.toString());
MiniHttpServer redirectServer(redirectReply.toLatin1());
QUrl url("http://localhost/");
url.setPort(redirectServer.serverPort());
QNetworkRequest request(url);
auto oldRedirectPolicy = manager.redirectPolicy();
manager.setRedirectPolicy(QNetworkRequest::RedirectPolicy::NoLessSafeRedirectPolicy);
QNetworkReplyPtr reply(manager.deleteResource(request));
// Restore previous policy:
manager.setRedirectPolicy(oldRedirectPolicy);
QCOMPARE(waitForFinish(reply), int(Success));
QVERIFY2(target.receivedData.startsWith("DELETE"), "Target server called with the wrong method");
}
void tst_QNetworkReply::ioHttpRedirectCustom()
{
MiniHttpServer target(httpEmpty200Response, false);
QUrl targetUrl("http://localhost/");
targetUrl.setPort(target.serverPort());
QString redirectReply = tempRedirectReplyStr().arg(targetUrl.toString());
MiniHttpServer redirectServer(redirectReply.toLatin1());
QUrl url("http://localhost/");
url.setPort(redirectServer.serverPort());
QNetworkRequest request(url);
auto oldRedirectPolicy = manager.redirectPolicy();
manager.setRedirectPolicy(QNetworkRequest::RedirectPolicy::NoLessSafeRedirectPolicy);
QNetworkReplyPtr reply(manager.sendCustomRequest(request, QByteArrayLiteral("CUSTOM")));
// Restore previous policy:
manager.setRedirectPolicy(oldRedirectPolicy);
QCOMPARE(waitForFinish(reply), int(Success));
QVERIFY2(target.receivedData.startsWith("CUSTOM"), "Target server called with the wrong method");
}
#ifndef QT_NO_SSL
class PutWithServerClosingConnectionImmediatelyHandler: public QObject