diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-10-24 10:37:17 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2017-10-24 13:40:55 +0200 |
commit | fa9d12f4a20d618caedc77880459fa1af75fd50d (patch) | |
tree | 11bd3cb4541afb924b3ee17f867133e71eb0e090 /src/network/access | |
parent | 895cb4681ee78caaf9b99c88390a74ff1d79ae61 (diff) | |
parent | f174d31667dca184439f520b9624a1471d9556a6 (diff) |
Merge remote-tracking branch 'origin/5.10' into dev
Conflicts:
src/plugins/platforms/windows/qwindowsmousehandler.cpp
src/plugins/platforms/xcb/qxcbimage.cpp
tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
tests/manual/qtabletevent/regular_widgets/main.cpp
Done-with: Friedemann Kleint<Friedemann.Kleint@qt.io>
Done-with: MÃ¥rten Nordheim<marten.nordheim@qt.io>
Change-Id: I5b2499513a92c590ed0756f7d2e93c35a64b7f30
Diffstat (limited to 'src/network/access')
-rw-r--r-- | src/network/access/qhstsstore.cpp | 2 | ||||
-rw-r--r-- | src/network/access/qhttpmultipart.cpp | 2 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkconnectionchannel.cpp | 11 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkreply.cpp | 2 | ||||
-rw-r--r-- | src/network/access/qnetworkcookiejar.cpp | 2 | ||||
-rw-r--r-- | src/network/access/qnetworkreply.cpp | 2 | ||||
-rw-r--r-- | src/network/access/qnetworkreplyhttpimpl.cpp | 89 | ||||
-rw-r--r-- | src/network/access/qnetworkreplyhttpimpl_p.h | 4 |
8 files changed, 86 insertions, 28 deletions
diff --git a/src/network/access/qhstsstore.cpp b/src/network/access/qhstsstore.cpp index 239a52b7a4..6d7f60ba8d 100644 --- a/src/network/access/qhstsstore.cpp +++ b/src/network/access/qhstsstore.cpp @@ -114,7 +114,7 @@ void QHstsStore::synchronize() if (observedPolicies.size()) { beginHstsGroups(); - for (const QHstsPolicy &policy : observedPolicies) { + for (const QHstsPolicy &policy : qAsConst(observedPolicies)) { const QString key(host_name_to_settings_key(policy.host())); // If we fail to write a new, updated policy, we also remove the old one. if (policy.isExpired() || !serializePolicy(key, policy)) 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 f21acc7574..5f75172c90 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -604,14 +604,21 @@ void QHttpNetworkConnectionChannel::handleStatus() case 302: case 303: case 305: - case 307: { + case 307: + case 308: { // Parse the response headers and get the "location" url QUrl redirectUrl = connection->d_func()->parseRedirectResponse(socket, reply); 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/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index 612abb9044..778ba821e8 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -96,7 +96,7 @@ void QHttpNetworkReply::setRedirectUrl(const QUrl &url) bool QHttpNetworkReply::isHttpRedirect(int statusCode) { return (statusCode == 301 || statusCode == 302 || statusCode == 303 - || statusCode == 305 || statusCode == 307); + || statusCode == 305 || statusCode == 307 || statusCode == 308); } qint64 QHttpNetworkReply::contentLength() const 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/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp index cabea86521..11d8f0e3f7 100644 --- a/src/network/access/qnetworkreply.cpp +++ b/src/network/access/qnetworkreply.cpp @@ -297,7 +297,7 @@ QNetworkReplyPrivate::QNetworkReplyPrivate() This signal is emitted if the QNetworkRequest::FollowRedirectsAttribute was set in the request and the server responded with a 3xx status (specifically - 301, 302, 303, 305 or 307 status code) with a valid url in the location + 301, 302, 303, 305, 307 or 308 status code) with a valid url in the location header, indicating a HTTP redirect. The \a url parameter contains the new redirect url as returned by the server in the location header. diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 684fee610c..4ac046ef58 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, @@ -1115,10 +1125,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; } @@ -1193,11 +1208,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)); } @@ -1210,6 +1244,7 @@ void QNetworkReplyHttpImplPrivate::checkForRedirect(const int statusCode) case 302: // Found case 303: // See Other case 307: // Temporary Redirect + case 308: // Permanent Redirect // What do we do about the caching of the HTML note? // The response to a 303 MUST NOT be cached, while the response to // all of the others is cacheable if the headers indicate it to be @@ -1783,10 +1818,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; } @@ -1810,6 +1843,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); @@ -1837,24 +1898,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 91e9207601..8d2bd132b0 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); |