diff options
author | Liang Qi <liang.qi@qt.io> | 2017-10-23 09:24:00 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2017-10-23 09:40:54 +0200 |
commit | 32f50225c4913de1af145ef2da9a11ffffac3ded (patch) | |
tree | c2ecd51223706f3ad1234af883af9fdf33d846a2 /src/network/access | |
parent | 88e6f8cff2974c46b1262f3a1a61e1440c664e0c (diff) | |
parent | 9c58dd15885d813aeb5d83d2869c0f3a3ee5fcfe (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.cpp | 2 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkconnectionchannel.cpp | 8 | ||||
-rw-r--r-- | src/network/access/qnetworkcookiejar.cpp | 2 | ||||
-rw-r--r-- | src/network/access/qnetworkreplyhttpimpl.cpp | 88 | ||||
-rw-r--r-- | src/network/access/qnetworkreplyhttpimpl_p.h | 4 |
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); |