summaryrefslogtreecommitdiffstats
path: root/src/network/access/qnetworkreplyhttpimpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/access/qnetworkreplyhttpimpl.cpp')
-rw-r--r--src/network/access/qnetworkreplyhttpimpl.cpp90
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())