diff options
Diffstat (limited to 'src/network/access/qnetworkreplyhttpimpl.cpp')
-rw-r--r-- | src/network/access/qnetworkreplyhttpimpl.cpp | 90 |
1 files changed, 80 insertions, 10 deletions
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 6f5e68d9c2..5cd0747e34 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -52,6 +52,7 @@ #include "QtCore/qelapsedtimer.h" #include "QtNetwork/qsslconfiguration.h" #include "qhttpthreaddelegate_p.h" +#include "qhsts_p.h" #include "qthread.h" #include "QtCore/qcoreapplication.h" @@ -384,6 +385,12 @@ void QNetworkReplyHttpImpl::ignoreSslErrors() { Q_D(QNetworkReplyHttpImpl); + if (d->managerPrivate && d->managerPrivate->stsEnabled + && d->managerPrivate->stsCache.isKnownHost(url())) { + // We cannot ignore any Security Transport-related errors for this host. + return; + } + d->pendingIgnoreAllSslErrors = true; } @@ -391,6 +398,12 @@ void QNetworkReplyHttpImpl::ignoreSslErrorsImplementation(const QList<QSslError> { Q_D(QNetworkReplyHttpImpl); + if (d->managerPrivate && d->managerPrivate->stsEnabled + && d->managerPrivate->stsCache.isKnownHost(url())) { + // We cannot ignore any Security Transport-related errors for this host. + return; + } + // the pending list is set if QNetworkReply::ignoreSslErrors(const QList<QSslError> &errors) // is called before QNetworkAccessManager::get() (or post(), etc.) d->pendingIgnoreSslErrorsList = errors; @@ -655,8 +668,14 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq } #endif - if (newHttpRequest.attribute(QNetworkRequest::FollowRedirectsAttribute).toBool()) - httpRequest.setFollowRedirects(true); + auto redirectPolicy = QNetworkRequest::ManualRedirectPolicy; + const QVariant value = newHttpRequest.attribute(QNetworkRequest::RedirectPolicyAttribute); + if (value.isValid()) + redirectPolicy = value.value<QNetworkRequest::RedirectPolicy>(); + else if (newHttpRequest.attribute(QNetworkRequest::FollowRedirectsAttribute).toBool()) + redirectPolicy = QNetworkRequest::NoLessSafeRedirectPolicy; + + httpRequest.setRedirectPolicy(redirectPolicy); httpRequest.setPriority(convert(newHttpRequest.priority())); @@ -803,10 +822,11 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq Qt::QueuedConnection); QObject::connect(delegate, SIGNAL(downloadMetaData(QList<QPair<QByteArray,QByteArray> >, int, QString, bool, - QSharedPointer<char>, qint64, bool)), + QSharedPointer<char>, qint64, qint64, + bool)), q, SLOT(replyDownloadMetaData(QList<QPair<QByteArray,QByteArray> >, int, QString, bool, - QSharedPointer<char>, qint64, bool)), + QSharedPointer<char>, qint64, qint64, bool)), Qt::QueuedConnection); QObject::connect(delegate, SIGNAL(downloadProgress(qint64,qint64)), q, SLOT(replyDownloadProgressSlot(qint64,qint64)), @@ -817,12 +837,16 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq QObject::connect(delegate, SIGNAL(redirected(QUrl,int,int)), q, SLOT(onRedirected(QUrl,int,int)), Qt::QueuedConnection); + + QObject::connect(q, SIGNAL(redirectAllowed()), q, SLOT(followRedirect()), + Qt::QueuedConnection); + #ifndef QT_NO_SSL QObject::connect(delegate, SIGNAL(sslConfigurationChanged(QSslConfiguration)), q, SLOT(replySslConfigurationChanged(QSslConfiguration)), Qt::QueuedConnection); #endif - // Those need to report back, therefire BlockingQueuedConnection + // Those need to report back, therefore BlockingQueuedConnection QObject::connect(delegate, SIGNAL(authenticationRequired(QHttpNetworkRequest,QAuthenticator*)), q, SLOT(httpAuthenticationRequired(QHttpNetworkRequest,QAuthenticator*)), Qt::BlockingQueuedConnection); @@ -911,6 +935,7 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq delegate->isPipeliningUsed, QSharedPointer<char>(), delegate->incomingContentLength, + delegate->removedContentLength, delegate->isSpdyUsed); replyDownloadData(delegate->synchronousDownloadData); httpError(delegate->incomingErrorCode, delegate->incomingErrorDetail); @@ -922,6 +947,7 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq delegate->isPipeliningUsed, QSharedPointer<char>(), delegate->incomingContentLength, + delegate->removedContentLength, delegate->isSpdyUsed); replyDownloadData(delegate->synchronousDownloadData); } @@ -1109,22 +1135,53 @@ 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; - QNetworkRequest 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.redirectPolicy() == QNetworkRequest::NoLessSafeRedirectPolicy + && isLessSafe) { + error(QNetworkReply::InsecureRedirectError, + QCoreApplication::translate("QHttp", "Insecure redirect")); + return; + } + + redirectRequest = createRedirectRequest(originalRequest, url, maxRedirectsRemaining); operation = getRedirectOperation(operation, httpStatus); + if (httpRequest.redirectPolicy() != QNetworkRequest::UserVerifiedRedirectPolicy) + followRedirect(); + + emit q->redirected(url); +} + +void QNetworkReplyHttpImplPrivate::followRedirect() +{ + Q_Q(QNetworkReplyHttpImpl); + cookedHeaders.clear(); if (managerPrivate->thread) managerPrivate->thread->disconnect(); - // Recurse QMetaObject::invokeMethod(q, "start", Qt::QueuedConnection, Q_ARG(QNetworkRequest, redirectRequest)); - - emit q->redirected(redirectUrl); } void QNetworkReplyHttpImplPrivate::checkForRedirect(const int statusCode) @@ -1149,7 +1206,9 @@ void QNetworkReplyHttpImplPrivate::checkForRedirect(const int statusCode) void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByteArray,QByteArray> > &hm, int sc, const QString &rp, bool pu, QSharedPointer<char> db, - qint64 contentLength, bool spdyWasUsed) + qint64 contentLength, + qint64 removedContentLength, + bool spdyWasUsed) { Q_Q(QNetworkReplyHttpImpl); Q_UNUSED(contentLength); @@ -1157,6 +1216,15 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByte statusCode = sc; reasonPhrase = rp; +#ifndef QT_NO_SSL + // We parse this header only if we're using secure transport: + // + // RFC6797, 8.1 + // If an HTTP response is received over insecure transport, the UA MUST + // ignore any present STS header field(s). + if (url.scheme() == QLatin1String("https") && managerPrivate->stsEnabled) + managerPrivate->stsCache.updateFromHeaders(hm, url); +#endif // Download buffer if (!db.isNull()) { downloadBufferPointer = db; @@ -1195,6 +1263,8 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByte q->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, statusCode); q->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, reasonPhrase); + if (removedContentLength != -1) + q->setAttribute(QNetworkRequest::OriginalContentLengthAttribute, removedContentLength); // is it a redirection? if (!isHttpRedirectResponse()) |