summaryrefslogtreecommitdiffstats
path: root/src/network/access/qnetworkaccessmanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/access/qnetworkaccessmanager.cpp')
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp189
1 files changed, 182 insertions, 7 deletions
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index 6d5b2400f1..19e9ecc265 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,94 @@ void QNetworkAccessManager::setCookieJar(QNetworkCookieJar *cookieJar)
}
/*!
+ \since 5.9
+
+ Enables HTTP Strict Transport Security (HSTS, RFC6797). When processing a
+ request, QNetworkAccessManager automatically replaces "http" scheme with
+ "https" and uses a secure transport if a host is a known HSTS host.
+ Port 80 if it's set explicitly 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
+ expired/disabled HSTS policy.
+
+ \sa disableStrictTransportSecurity(), strictTransportSecurityEnabled()
+*/
+void QNetworkAccessManager::enableStrictTransportSecurity()
+{
+ Q_D(QNetworkAccessManager);
+ d->stsEnabled = true;
+}
+
+/*!
+ \since 5.9
+
+ Disables HTTP Strict Transport Security (HSTS). HSTS headers in responses would
+ be ignored, no scheme/port mapping is done.
+
+ \sa enableStrictTransportSecurity()
+*/
+void QNetworkAccessManager::disableStrictTransportSecurity()
+{
+ Q_D(QNetworkAccessManager);
+ d->stsEnabled = false;
+}
+
+/*!
+ \since 5.9
+
+ Returns true if HTTP Strict Transport Security (HSTS) was enabled. By default
+ HSTS is disabled.
+
+ \sa enableStrictTransportSecurity
+*/
+bool QNetworkAccessManager::strictTransportSecurityEnabled() 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 QList<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
+*/
+QList<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 +1169,45 @@ void QNetworkAccessManager::connectToHost(const QString &hostName, quint16 port)
}
/*!
+ \since 5.9
+
+ Sets the manager's redirects 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::ManualRedirectsPolicy.
+ 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 redirectsPolicy(), QNetworkRequest::RedirectsPolicy,
+ QNetworkRequest::FollowRedirectsAttribute
+*/
+void QNetworkAccessManager::setRedirectsPolicy(QNetworkRequest::RedirectsPolicy policy)
+{
+ Q_D(QNetworkAccessManager);
+ d->redirectsPolicy = policy;
+}
+
+/*!
+ \since 5.9
+
+ Returns the redirect policy that is used when creating new requests.
+
+ \sa setRedirectsPolicy(), QNetworkRequest::RedirectsPolicy
+*/
+QNetworkRequest::RedirectsPolicy QNetworkAccessManager::redirectsPolicy() const
+{
+ Q_D(const QNetworkAccessManager);
+ return d->redirectsPolicy;
+}
+
+/*!
\since 4.7
Sends a custom request to the server identified by the URL of \a request.
@@ -1147,9 +1276,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 +1288,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::RedirectsPolicyAttribute).isNull()
+ && req.attribute(QNetworkRequest::FollowRedirectsAttribute).isNull()) {
+ // We only apply the general manager's policy if:
+ // - RedirectsPolicyAttribute is not set already on request and
+ // - no FollowRedirectsAttribute is set.
+ req.setAttribute(QNetworkRequest::RedirectsPolicyAttribute, redirectsPolicy());
+ }
+
bool isLocalFile = req.url().isLocalFile();
QString scheme = req.url().scheme();
@@ -1251,6 +1389,24 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
|| scheme == QLatin1String("https") || scheme == QLatin1String("preconnect-https")
#endif
) {
+#ifndef QT_NO_SSL
+ if (strictTransportSecurityEnabled() && 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 +1508,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 +1724,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();
}