diff options
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/access/qhttpnetworkconnection.cpp | 11 | ||||
-rw-r--r-- | src/network/access/qnetworkreplyhttpimpl.cpp | 28 |
2 files changed, 31 insertions, 8 deletions
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 327eaf91bc..fd3cbbe36e 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -552,12 +552,11 @@ QUrl QHttpNetworkConnectionPrivate::parseRedirectResponse(QAbstractSocket *socke if (redirectUrl.scheme() == QLatin1String("http") || redirectUrl.scheme() == QLatin1String("https")) { switch (reply->request().redirectsPolicy()) { case QNetworkRequest::NoLessSafeRedirectsPolicy: - // Check if we're doing an unsecure redirect (https -> http) - if (priorUrl.scheme() == QLatin1String("https") - && redirectUrl.scheme() == QLatin1String("http")) { - emitReplyError(socket, reply, QNetworkReply::InsecureRedirectError); - return QUrl(); - } + // Here we could handle https->http redirects as InsecureProtocolError. + // However, if HSTS is enabled and redirectUrl.host() is a known STS + // host, then we'll replace its scheme and this won't downgrade protocol, + // after all. We cannot access QNAM's STS cache from here, so delegate + // this check to QNetworkReplyHttpImpl. break; case QNetworkRequest::SameOriginRedirectsPolicy: if (priorUrl.host() != redirectUrl.host() diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 7d863ef53c..ece08acc6b 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -1135,16 +1135,40 @@ void QNetworkReplyHttpImplPrivate::onRedirected(const QUrl &redirectUrl, int htt if (isFinished) return; + const QString schemeBefore(url.scheme()); if (httpRequest.isFollowRedirects()) // update the reply's url as it could've changed url = redirectUrl; - redirectRequest = createRedirectRequest(originalRequest, redirectUrl, maxRedirectsRemaining); + if (managerPrivate->stsEnabled && managerPrivate->stsCache.isKnownHost(url)) { + // RFC6797, 8.3: + // The UA MUST replace the URI scheme with "https" [RFC2818], + // and if the URI contains an explicit port component of "80", + // then the UA MUST convert the port component to be "443", or + // if the URI contains an explicit port component that is not + // equal to "80", the port component value MUST be preserved; + // otherwise, if the URI does not contain an explicit port + // component, the UA MUST NOT add one. + url.setScheme(QLatin1String("https")); + if (url.port() == 80) + url.setPort(443); + } + + const bool isLessSafe = schemeBefore == QLatin1String("https") + && url.scheme() == QLatin1String("http"); + if (httpRequest.redirectsPolicy() == QNetworkRequest::NoLessSafeRedirectsPolicy + && isLessSafe) { + error(QNetworkReply::InsecureRedirectError, + QCoreApplication::translate("QHttp", "Insecure redirect")); + return; + } + + redirectRequest = createRedirectRequest(originalRequest, url, maxRedirectsRemaining); operation = getRedirectOperation(operation, httpStatus); if (httpRequest.redirectsPolicy() != QNetworkRequest::UserVerifiedRedirectsPolicy) followRedirect(); - emit q->redirected(redirectUrl); + emit q->redirected(url); } void QNetworkReplyHttpImplPrivate::followRedirect() |