diff options
Diffstat (limited to 'src/network/access/qnetworkaccessmanager.cpp')
-rw-r--r-- | src/network/access/qnetworkaccessmanager.cpp | 175 |
1 files changed, 168 insertions, 7 deletions
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 6d5b2400f1..0a6270d417 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -45,6 +45,8 @@ #include "qnetworkcookie.h" #include "qnetworkcookiejar.h" #include "qabstractnetworkcache.h" +#include "qhstspolicy.h" +#include "qhsts_p.h" #include "QtNetwork/qnetworksession.h" #include "QtNetwork/private/qsharednetworksession_p.h" @@ -693,6 +695,80 @@ void QNetworkAccessManager::setCookieJar(QNetworkCookieJar *cookieJar) } /*! + \since 5.9 + + If \a enabled is \c true, QNetworkAccessManager follows the HTTP Strict Transport + Security policy (HSTS, RFC6797). When processing a request, QNetworkAccessManager + automatically replaces the "http" scheme with "https" and uses a secure transport + for HSTS hosts. If it's set explicitly, port 80 is replaced by port 443. + + When HSTS is enabled, for each HTTP response containing HSTS header and + received over a secure transport, QNetworkAccessManager will update its HSTS + cache, either remembering a host with a valid policy or removing a host with + an expired or disabled HSTS policy. + + \sa isStrictTransportSecurityEnabled() +*/ +void QNetworkAccessManager::setStrictTransportSecurityEnabled(bool enabled) +{ + Q_D(QNetworkAccessManager); + d->stsEnabled = enabled; +} + +/*! + \since 5.9 + + Returns true if HTTP Strict Transport Security (HSTS) was enabled. By default + HSTS is disabled. + + \sa setStrictTransportSecurityEnabled() +*/ +bool QNetworkAccessManager::isStrictTransportSecurityEnabled() const +{ + Q_D(const QNetworkAccessManager); + return d->stsEnabled; +} + +/*! + \since 5.9 + + Adds HTTP Strict Transport Security policies into HSTS cache. + + \note An expired policy will remove a known host from the cache, if previously + present. + + \note While processing HTTP responses, QNetworkAccessManager can also update + the HSTS cache, removing or updating exitsting policies or introducing new + known hosts. The current implementation thus is server-driven, client code + can provide QNetworkAccessManager with previously known or discovered + policies, but this information can be overridden by "Strict-Transport-Security" + response headers. + + \sa addStrictTransportSecurityHosts(), QHstsPolicy +*/ + +void QNetworkAccessManager::addStrictTransportSecurityHosts(const QVector<QHstsPolicy> &knownHosts) +{ + Q_D(QNetworkAccessManager); + d->stsCache.updateFromPolicies(knownHosts); +} + +/*! + \since 5.9 + + Returns the list of HTTP Strict Transport Security policies. This list can + differ from what was initially set via addStrictTransportSecurityHosts() if + HSTS cache was updated from a "Strict-Transport-Security" response header. + + \sa addStrictTransportSecurityHosts(), QHstsPolicy +*/ +QVector<QHstsPolicy> QNetworkAccessManager::strictTransportSecurityHosts() const +{ + Q_D(const QNetworkAccessManager); + return d->stsCache.policies(); +} + +/*! Posts a request to obtain the network headers for \a request and returns a new QNetworkReply object which will contain such headers. @@ -1079,6 +1155,45 @@ void QNetworkAccessManager::connectToHost(const QString &hostName, quint16 port) } /*! + \since 5.9 + + Sets the manager's redirect policy to be the \a policy specified. This policy + will affect all subsequent requests created by the manager. + + Use this function to enable or disable HTTP redirects on the manager's level. + + \note When creating a request QNetworkRequest::RedirectAttributePolicy has + the highest priority, next by priority is QNetworkRequest::FollowRedirectsAttribute. + Finally, the manager's policy has the lowest priority. + + For backwards compatibility the default value is QNetworkRequest::ManualRedirectPolicy. + This may change in the future and some type of auto-redirect policy will become + the default; clients relying on manual redirect handling are encouraged to set + this policy explicitly in their code. + + \sa redirectPolicy(), QNetworkRequest::RedirectPolicy, + QNetworkRequest::FollowRedirectsAttribute +*/ +void QNetworkAccessManager::setRedirectPolicy(QNetworkRequest::RedirectPolicy policy) +{ + Q_D(QNetworkAccessManager); + d->redirectPolicy = policy; +} + +/*! + \since 5.9 + + Returns the redirect policy that is used when creating new requests. + + \sa setRedirectPolicy(), QNetworkRequest::RedirectPolicy +*/ +QNetworkRequest::RedirectPolicy QNetworkAccessManager::redirectPolicy() const +{ + Q_D(const QNetworkAccessManager); + return d->redirectPolicy; +} + +/*! \since 4.7 Sends a custom request to the server identified by the URL of \a request. @@ -1147,9 +1262,9 @@ QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &r /*! Returns a new QNetworkReply object to handle the operation \a op - and request \a req. The device \a outgoingData is always 0 for Get and - Head requests, but is the value passed to post() and put() in - those operations (the QByteArray variants will pass a QBuffer + and request \a originalReq. The device \a outgoingData is always 0 + for Get and Head requests, but is the value passed to post() and + put() in those operations (the QByteArray variants will pass a QBuffer object). The default implementation calls QNetworkCookieJar::cookiesForUrl() @@ -1159,11 +1274,20 @@ QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &r The returned object must be in an open state. */ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Operation op, - const QNetworkRequest &req, + const QNetworkRequest &originalReq, QIODevice *outgoingData) { Q_D(QNetworkAccessManager); + QNetworkRequest req(originalReq); + if (req.attribute(QNetworkRequest::RedirectPolicyAttribute).isNull() + && req.attribute(QNetworkRequest::FollowRedirectsAttribute).isNull()) { + // We only apply the general manager's policy if: + // - RedirectPolicyAttribute is not set already on request and + // - no FollowRedirectsAttribute is set. + req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, redirectPolicy()); + } + bool isLocalFile = req.url().isLocalFile(); QString scheme = req.url().scheme(); @@ -1251,6 +1375,24 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera || scheme == QLatin1String("https") || scheme == QLatin1String("preconnect-https") #endif ) { +#ifndef QT_NO_SSL + if (isStrictTransportSecurityEnabled() && d->stsCache.isKnownHost(request.url())) { + QUrl stsUrl(request.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. + if (stsUrl.port() == 80) + stsUrl.setPort(443); + stsUrl.setScheme(QLatin1String("https")); + request.setUrl(stsUrl); + } +#endif QNetworkReplyHttpImpl *reply = new QNetworkReplyHttpImpl(this, request, op, outgoingData); #ifndef QT_NO_BEARERMANAGEMENT connect(this, SIGNAL(networkSessionConnected()), @@ -1352,10 +1494,26 @@ QStringList QNetworkAccessManager::supportedSchemesImplementation() const This function is useful for doing auto tests. + \sa clearConnectionCache() */ void QNetworkAccessManager::clearAccessCache() { - QNetworkAccessManagerPrivate::clearCache(this); + QNetworkAccessManagerPrivate::clearAuthenticationCache(this); + QNetworkAccessManagerPrivate::clearConnectionCache(this); +} + +/*! + \since 5.9 + + Flushes the internal cache of network connections. + In contrast to clearAccessCache() the authentication data + is preserved. + + \sa clearAccessCache() +*/ +void QNetworkAccessManager::clearConnectionCache() +{ + QNetworkAccessManagerPrivate::clearConnectionCache(this); } void QNetworkAccessManagerPrivate::_q_replyFinished() @@ -1552,11 +1710,14 @@ QList<QNetworkProxy> QNetworkAccessManagerPrivate::queryProxy(const QNetworkProx } #endif -void QNetworkAccessManagerPrivate::clearCache(QNetworkAccessManager *manager) +void QNetworkAccessManagerPrivate::clearAuthenticationCache(QNetworkAccessManager *manager) { - manager->d_func()->objectCache.clear(); manager->d_func()->authenticationManager->clearCache(); +} +void QNetworkAccessManagerPrivate::clearConnectionCache(QNetworkAccessManager *manager) +{ + manager->d_func()->objectCache.clear(); manager->d_func()->destroyThread(); } |