summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/network/access/qhttpnetworkheader.cpp5
-rw-r--r--src/network/access/qhttpnetworkheader_p.h1
-rw-r--r--src/network/access/qhttpnetworkrequest.cpp5
-rw-r--r--src/network/access/qhttpnetworkrequest_p.h1
-rw-r--r--src/network/access/qnetworkreplyhttpimpl.cpp26
-rw-r--r--tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp74
6 files changed, 111 insertions, 1 deletions
diff --git a/src/network/access/qhttpnetworkheader.cpp b/src/network/access/qhttpnetworkheader.cpp
index 8ad01174b4..98d7dcafe2 100644
--- a/src/network/access/qhttpnetworkheader.cpp
+++ b/src/network/access/qhttpnetworkheader.cpp
@@ -117,6 +117,11 @@ void QHttpNetworkHeaderPrivate::prependHeaderField(const QByteArray &name, const
fields.prepend(qMakePair(name, data));
}
+void QHttpNetworkHeaderPrivate::clearHeaders()
+{
+ fields.clear();
+}
+
bool QHttpNetworkHeaderPrivate::operator==(const QHttpNetworkHeaderPrivate &other) const
{
return (url == other.url);
diff --git a/src/network/access/qhttpnetworkheader_p.h b/src/network/access/qhttpnetworkheader_p.h
index 3adb0ed7f1..83154b9d25 100644
--- a/src/network/access/qhttpnetworkheader_p.h
+++ b/src/network/access/qhttpnetworkheader_p.h
@@ -93,6 +93,7 @@ public:
QList<QByteArray> headerFieldValues(const QByteArray &name) const;
void setHeaderField(const QByteArray &name, const QByteArray &data);
void prependHeaderField(const QByteArray &name, const QByteArray &data);
+ void clearHeaders();
bool operator==(const QHttpNetworkHeaderPrivate &other) const;
};
diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp
index 0b03e6e69e..185435a1f1 100644
--- a/src/network/access/qhttpnetworkrequest.cpp
+++ b/src/network/access/qhttpnetworkrequest.cpp
@@ -286,6 +286,11 @@ void QHttpNetworkRequest::prependHeaderField(const QByteArray &name, const QByte
d->prependHeaderField(name, data);
}
+void QHttpNetworkRequest::clearHeaders()
+{
+ d->clearHeaders();
+}
+
QHttpNetworkRequest &QHttpNetworkRequest::operator=(const QHttpNetworkRequest &other)
{
d = other.d;
diff --git a/src/network/access/qhttpnetworkrequest_p.h b/src/network/access/qhttpnetworkrequest_p.h
index f263e348ef..9944823440 100644
--- a/src/network/access/qhttpnetworkrequest_p.h
+++ b/src/network/access/qhttpnetworkrequest_p.h
@@ -103,6 +103,7 @@ public:
QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue = QByteArray()) const override;
void setHeaderField(const QByteArray &name, const QByteArray &data) override;
void prependHeaderField(const QByteArray &name, const QByteArray &data);
+ void clearHeaders();
Operation operation() const;
void setOperation(Operation operation);
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
index e591340257..f189f5be20 100644
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
@@ -1155,6 +1155,26 @@ void QNetworkReplyHttpImplPrivate::onRedirected(const QUrl &redirectUrl, int htt
redirectRequest = createRedirectRequest(originalRequest, url, maxRedirectsRemaining);
operation = getRedirectOperation(operation, httpStatus);
+ // Clear stale headers, the relevant ones get set again later
+ httpRequest.clearHeaders();
+ if (operation == QNetworkAccessManager::GetOperation
+ || operation == QNetworkAccessManager::HeadOperation) {
+ // possibly changed from not-GET/HEAD to GET/HEAD, make sure to get rid of upload device
+ uploadByteDevice.reset();
+ uploadByteDevicePosition = 0;
+ if (outgoingData) {
+ QObject::disconnect(outgoingData, SIGNAL(readyRead()), q,
+ SLOT(_q_bufferOutgoingData()));
+ QObject::disconnect(outgoingData, SIGNAL(readChannelFinished()), q,
+ SLOT(_q_bufferOutgoingDataFinished()));
+ }
+ outgoingData = nullptr;
+ outgoingDataBuffer.reset();
+ // We need to explicitly unset these headers so they're not reapplied to the httpRequest
+ redirectRequest.setHeader(QNetworkRequest::ContentLengthHeader, QVariant());
+ redirectRequest.setHeader(QNetworkRequest::ContentTypeHeader, QVariant());
+ }
+
if (const QNetworkCookieJar *const cookieJar = manager->cookieJar()) {
auto cookies = cookieJar->cookiesForUrl(url);
if (!cookies.empty()) {
@@ -1435,6 +1455,9 @@ void QNetworkReplyHttpImplPrivate::resetUploadDataSlot(bool *r)
// Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread
void QNetworkReplyHttpImplPrivate::sentUploadDataSlot(qint64 pos, qint64 amount)
{
+ if (!uploadByteDevice) // uploadByteDevice is no longer available
+ return;
+
if (uploadByteDevicePosition + amount != pos) {
// Sanity check, should not happen.
error(QNetworkReply::UnknownNetworkError, QString());
@@ -1449,6 +1472,9 @@ void QNetworkReplyHttpImplPrivate::wantUploadDataSlot(qint64 maxSize)
{
Q_Q(QNetworkReplyHttpImpl);
+ if (!uploadByteDevice) // uploadByteDevice is no longer available
+ return;
+
// call readPointer
qint64 currentUploadDataLength = 0;
char *data = const_cast<char*>(uploadByteDevice->readPointer(maxSize, currentUploadDataLength));
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<QByteArray>("method");
+ QTest::addColumn<QString>("status");
+ QTest::addColumn<bool>("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