summaryrefslogtreecommitdiffstats
path: root/src/network/access
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2017-10-23 09:24:00 +0200
committerLiang Qi <liang.qi@qt.io>2017-10-23 09:40:54 +0200
commit32f50225c4913de1af145ef2da9a11ffffac3ded (patch)
treec2ecd51223706f3ad1234af883af9fdf33d846a2 /src/network/access
parent88e6f8cff2974c46b1262f3a1a61e1440c664e0c (diff)
parent9c58dd15885d813aeb5d83d2869c0f3a3ee5fcfe (diff)
Merge remote-tracking branch 'origin/5.9' into 5.10
Conflicts: src/plugins/platforms/direct2d/direct2d.pro src/plugins/platforms/ios/qiosclipboard.mm src/plugins/platforms/windows/windows.pro Change-Id: Idffa03b3990bd642784f528821c5446b2e1008ef
Diffstat (limited to 'src/network/access')
-rw-r--r--src/network/access/qhttpmultipart.cpp2
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp8
-rw-r--r--src/network/access/qnetworkcookiejar.cpp2
-rw-r--r--src/network/access/qnetworkreplyhttpimpl.cpp88
-rw-r--r--src/network/access/qnetworkreplyhttpimpl_p.h4
5 files changed, 80 insertions, 24 deletions
diff --git a/src/network/access/qhttpmultipart.cpp b/src/network/access/qhttpmultipart.cpp
index 303c145394..58d306d5f9 100644
--- a/src/network/access/qhttpmultipart.cpp
+++ b/src/network/access/qhttpmultipart.cpp
@@ -476,6 +476,8 @@ bool QHttpMultiPartIODevice::isSequential() const
bool QHttpMultiPartIODevice::reset()
{
+ // Reset QIODevice's data
+ QIODevice::reset();
for (int a = 0; a < multiPart->parts.count(); a++)
if (!multiPart->parts[a].d->reset())
return false;
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 52dd86cd1e..2dc3f80998 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -607,8 +607,14 @@ void QHttpNetworkConnectionChannel::handleStatus()
if (redirectUrl.isValid())
reply->setRedirectUrl(redirectUrl);
- if (qobject_cast<QHttpNetworkConnection *>(connection))
+ if ((statusCode == 307 || statusCode == 308) && !resetUploadData()) {
+ // Couldn't reset the upload data, which means it will be unable to POST the data -
+ // this would lead to a long wait until it eventually failed and then retried.
+ // Instead of doing that we fail here instead, resetUploadData will already have emitted
+ // a ContentReSendError, so we're done.
+ } else if (qobject_cast<QHttpNetworkConnection *>(connection)) {
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
+ }
break;
}
case 401: // auth required
diff --git a/src/network/access/qnetworkcookiejar.cpp b/src/network/access/qnetworkcookiejar.cpp
index 232c2b47a5..f62a03b11d 100644
--- a/src/network/access/qnetworkcookiejar.cpp
+++ b/src/network/access/qnetworkcookiejar.cpp
@@ -140,7 +140,7 @@ void QNetworkCookieJar::setAllCookies(const QList<QNetworkCookie> &cookieList)
static inline bool isParentPath(const QString &path, const QString &reference)
{
- if (path.startsWith(reference)) {
+ if ((path.isEmpty() && reference == QLatin1String("/")) || path.startsWith(reference)) {
//The cookie-path and the request-path are identical.
if (path.length() == reference.length())
return true;
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
index c1575bc812..1e68ee52dc 100644
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
@@ -165,6 +165,16 @@ static QHash<QByteArray, QByteArray> parseHttpOptionHeader(const QByteArray &hea
}
}
+#if QT_CONFIG(bearermanagement)
+static bool isSessionNeeded(const QUrl &url)
+{
+ // Connections to the local machine does not require a session
+ QString host = url.host().toLower();
+ return !QHostAddress(host).isLoopback() && host != QLatin1String("localhost")
+ && host != QSysInfo::machineHostName().toLower();
+}
+#endif // bearer management
+
QNetworkReplyHttpImpl::QNetworkReplyHttpImpl(QNetworkAccessManager* const manager,
const QNetworkRequest& request,
QNetworkAccessManager::Operation& operation,
@@ -1109,10 +1119,15 @@ QNetworkAccessManager::Operation QNetworkReplyHttpImplPrivate::getRedirectOperat
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;
}
- // For now, we're always returning GET for anything other than HEAD
+ // Use GET for everything else.
return QNetworkAccessManager::GetOperation;
}
@@ -1187,11 +1202,30 @@ void QNetworkReplyHttpImplPrivate::followRedirect()
{
Q_Q(QNetworkReplyHttpImpl);
+ rawHeaders.clear();
cookedHeaders.clear();
if (managerPrivate->thread)
managerPrivate->thread->disconnect();
+#if QT_CONFIG(bearermanagement)
+ // If the original request didn't need a session (i.e. it was to localhost)
+ // then we might not have a session open, to which to redirect, if the
+ // new URL is remote. When this happens, we need to open the session now:
+ if (managerPrivate && isSessionNeeded(url)) {
+ if (auto session = managerPrivate->getNetworkSession()) {
+ if (session->state() != QNetworkSession::State::Connected || !session->isOpen()) {
+ startWaitForSession(session);
+ // Need to set 'request' to the redirectRequest so that when QNAM restarts
+ // the request after the session starts it will not repeat the previous request.
+ request = redirectRequest;
+ // Return now, QNAM will start the request when the session has started.
+ return;
+ }
+ }
+ }
+#endif // bearer management
+
QMetaObject::invokeMethod(q, "start", Qt::QueuedConnection,
Q_ARG(QNetworkRequest, redirectRequest));
}
@@ -1776,10 +1810,8 @@ bool QNetworkReplyHttpImplPrivate::start(const QNetworkRequest &newHttpRequest)
}
// This is not ideal.
- const QString host = url.host();
- if (host == QLatin1String("localhost") ||
- QHostAddress(host).isLoopback()) {
- // Don't need an open session for localhost access.
+ if (!isSessionNeeded(url)) {
+ // Don't need to check for an open session if we don't need one.
postRequest(newHttpRequest);
return true;
}
@@ -1803,6 +1835,34 @@ bool QNetworkReplyHttpImplPrivate::start(const QNetworkRequest &newHttpRequest)
#endif
}
+#if QT_CONFIG(bearermanagement)
+bool QNetworkReplyHttpImplPrivate::startWaitForSession(QSharedPointer<QNetworkSession> &session)
+{
+ Q_Q(QNetworkReplyHttpImpl);
+ state = WaitingForSession;
+
+ if (session) {
+ QObject::connect(session.data(), SIGNAL(error(QNetworkSession::SessionError)),
+ q, SLOT(_q_networkSessionFailed()), Qt::QueuedConnection);
+
+ if (!session->isOpen()) {
+ QVariant isBackground = request.attribute(QNetworkRequest::BackgroundRequestAttribute,
+ QVariant::fromValue(false));
+ session->setSessionProperty(QStringLiteral("ConnectInBackground"), isBackground);
+ session->open();
+ }
+ return true;
+ }
+ const Qt::ConnectionType connection = synchronous ? Qt::DirectConnection : Qt::QueuedConnection;
+ qWarning("Backend is waiting for QNetworkSession to connect, but there is none!");
+ QMetaObject::invokeMethod(q, "_q_error", connection,
+ Q_ARG(QNetworkReply::NetworkError, QNetworkReply::NetworkSessionFailedError),
+ Q_ARG(QString, QCoreApplication::translate("QNetworkReply", "Network session error.")));
+ QMetaObject::invokeMethod(q, "_q_finished", connection);
+ return false;
+}
+#endif // QT_CONFIG(bearermanagement)
+
void QNetworkReplyHttpImplPrivate::_q_startOperation()
{
Q_Q(QNetworkReplyHttpImpl);
@@ -1830,24 +1890,8 @@ void QNetworkReplyHttpImplPrivate::_q_startOperation()
// backend failed to start because the session state is not Connected.
// QNetworkAccessManager will call reply->backend->start() again for us when the session
// state changes.
- state = WaitingForSession;
-
- if (session) {
- QObject::connect(session.data(), SIGNAL(error(QNetworkSession::SessionError)),
- q, SLOT(_q_networkSessionFailed()), Qt::QueuedConnection);
-
- if (!session->isOpen()) {
- session->setSessionProperty(QStringLiteral("ConnectInBackground"), isBackground);
- session->open();
- }
- } else {
- qWarning("Backend is waiting for QNetworkSession to connect, but there is none!");
- QMetaObject::invokeMethod(q, "_q_error", synchronous ? Qt::DirectConnection : Qt::QueuedConnection,
- Q_ARG(QNetworkReply::NetworkError, QNetworkReply::NetworkSessionFailedError),
- Q_ARG(QString, QCoreApplication::translate("QNetworkReply", "Network session error.")));
- QMetaObject::invokeMethod(q, "_q_finished", synchronous ? Qt::DirectConnection : Qt::QueuedConnection);
+ if (!startWaitForSession(session))
return;
- }
} else if (session) {
QObject::connect(session.data(), SIGNAL(stateChanged(QNetworkSession::State)),
q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)),
diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h
index 26b16e8386..9d47f65ce7 100644
--- a/src/network/access/qnetworkreplyhttpimpl_p.h
+++ b/src/network/access/qnetworkreplyhttpimpl_p.h
@@ -161,6 +161,10 @@ signals:
class QNetworkReplyHttpImplPrivate: public QNetworkReplyPrivate
{
+#if QT_CONFIG(bearermanagement)
+ bool startWaitForSession(QSharedPointer<QNetworkSession> &session);
+#endif
+
public:
static QHttpNetworkRequest::Priority convert(const QNetworkRequest::Priority& prio);