summaryrefslogtreecommitdiffstats
path: root/src/network/access
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/access')
-rw-r--r--src/network/access/access.pri6
-rw-r--r--src/network/access/qhsts.cpp180
-rw-r--r--src/network/access/qhsts_p.h81
-rw-r--r--src/network/access/qhstspolicy.cpp218
-rw-r--r--src/network/access/qhstspolicy.h82
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp41
-rw-r--r--src/network/access/qnetworkaccessmanager.h3
7 files changed, 457 insertions, 154 deletions
diff --git a/src/network/access/access.pri b/src/network/access/access.pri
index 766d72590c..13d52ea44a 100644
--- a/src/network/access/access.pri
+++ b/src/network/access/access.pri
@@ -40,7 +40,8 @@ HEADERS += \
access/qhttpmultipart_p.h \
access/qnetworkfile_p.h \
access/qhttp2protocolhandler_p.h \
- access/qhsts_p.h
+ access/qhsts_p.h \
+ access/qhstspolicy.h
SOURCES += \
access/qftp.cpp \
@@ -74,7 +75,8 @@ SOURCES += \
access/qhttpmultipart.cpp \
access/qnetworkfile.cpp \
access/qhttp2protocolhandler.cpp \
- access/qhsts.cpp
+ access/qhsts.cpp \
+ access/qhstspolicy.cpp
mac: LIBS_PRIVATE += -framework Security
diff --git a/src/network/access/qhsts.cpp b/src/network/access/qhsts.cpp
index 2352c3e4f2..5e4f75b0ed 100644
--- a/src/network/access/qhsts.cpp
+++ b/src/network/access/qhsts.cpp
@@ -45,17 +45,8 @@
QT_BEGIN_NAMESPACE
-static bool expired_policy(const QDateTime &expires)
+static bool is_valid_domain_name(const QString &host)
{
- return !expires.isValid() || expires <= QDateTime::currentDateTimeUtc();
-}
-
-static bool has_valid_domain_name(const QUrl &url)
-{
- if (!url.isValid())
- return false;
-
- const QString host(url.host());
if (!host.size())
return false;
@@ -82,117 +73,106 @@ static bool has_valid_domain_name(const QUrl &url)
return true;
}
-QHstsCache::QHstsCache()
-{
- // Top-level domain without any label.
- children.push_back(Domain());
-}
-
void QHstsCache::updateFromHeaders(const QList<QPair<QByteArray, QByteArray>> &headers,
const QUrl &url)
{
- if (!has_valid_domain_name(url))
+ if (!url.isValid())
return;
QHstsHeaderParser parser;
if (parser.parse(headers))
- updateKnownHost(url, parser.expirationDate(), parser.includeSubDomains());
+ updateKnownHost(url.host(), parser.expirationDate(), parser.includeSubDomains());
+}
+
+void QHstsCache::updateFromPolicies(const QList<QHstsPolicy> &policies)
+{
+ for (const auto &policy : policies)
+ updateKnownHost(policy.host(), policy.expiry(), policy.includesSubDomains());
}
-void QHstsCache::updateKnownHost(const QUrl &originalUrl, const QDateTime &expires,
+void QHstsCache::updateKnownHost(const QUrl &url, const QDateTime &expires,
bool includeSubDomains)
{
- if (!has_valid_domain_name(originalUrl))
+ if (!url.isValid())
return;
- // HSTS is a per-host policy, regardless of protocol, port or any of the other
- // details in an URL; so we only want the host part. We still package this as
- // a QUrl since this handles IDNA 2003 (RFC3490) for us, as required by
- // HSTS (RFC6797, section 10).
- QUrl url;
- url.setHost(originalUrl.host());
-
- // 1. Update our hosts:
- QStringList labels(url.host().split(QLatin1Char('.')));
- std::reverse(labels.begin(), labels.end());
-
- size_type domainIndex = 0;
- for (int i = 0, e = labels.size(); i < e; ++i) {
- Q_ASSERT(domainIndex < children.size());
- auto &subDomains = children[domainIndex].labels;
- const auto &label = labels[i];
- auto pos = std::lower_bound(subDomains.begin(), subDomains.end(), label);
- if (pos == subDomains.end() || pos->label != label) {
- // A new, previously unknown host.
- if (expired_policy(expires)) {
- // Nothing to do at all - we did not know this host previously,
- // we do not have to - since its policy expired.
- return;
- }
-
- pos = subDomains.insert(pos, label);
- domainIndex = children.size();
- pos->domainIndex = domainIndex;
- children.resize(children.size() + (e - i));
+ updateKnownHost(url.host(), expires, includeSubDomains);
+}
- for (int j = i + 1; j < e; ++j) {
- auto &newDomain = children[domainIndex];
- newDomain.labels.push_back(labels[j]);
- newDomain.labels.back().domainIndex = ++domainIndex;
- }
+void QHstsCache::updateKnownHost(const QString &host, const QDateTime &expires,
+ bool includeSubDomains)
+{
+ if (!is_valid_domain_name(host))
+ return;
- break;
+ // HSTS is a per-host policy, regardless of protocol, port or any of the other
+ // details in an URL; so we only want the host part. QUrl::host handles
+ // IDNA 2003 (RFC3490) for us, as required by HSTS (RFC6797, section 10).
+ const HostName hostName(host);
+ const auto pos = knownHosts.find(hostName);
+ const QHstsPolicy newPolicy(expires, includeSubDomains, hostName.name);
+ if (pos == knownHosts.end()) {
+ // A new, previously unknown host.
+ if (newPolicy.isExpired()) {
+ // Nothing to do at all - we did not know this host previously,
+ // we do not have to - since its policy expired.
+ return;
}
- domainIndex = pos->domainIndex;
+ knownHosts.insert(pos, hostName, newPolicy);
+ return;
}
- Q_ASSERT(domainIndex > 0 && domainIndex < children.size());
- children[domainIndex].setHostPolicy(expires, includeSubDomains);
+ if (newPolicy.isExpired())
+ knownHosts.erase(pos);
+ else
+ *pos = std::move(newPolicy);
}
-bool QHstsCache::isKnownHost(const QUrl &originalUrl) const
+bool QHstsCache::isKnownHost(const QUrl &url) const
{
- if (!has_valid_domain_name(originalUrl))
+ if (!url.isValid() || !is_valid_domain_name(url.host()))
return false;
- QUrl url;
- url.setHost(originalUrl.host());
-
- QStringList labels(url.host().split(QLatin1Char('.')));
- std::reverse(labels.begin(), labels.end());
+ /*
+ RFC6797, 8.2. Known HSTS Host Domain Name Matching
+
+ * Superdomain Match
+ If a label-for-label match between an entire Known HSTS Host's
+ domain name and a right-hand portion of the given domain name
+ is found, then this Known HSTS Host's domain name is a
+ superdomain match for the given domain name. There could be
+ multiple superdomain matches for a given domain name.
+ * Congruent Match
+ If a label-for-label match between a Known HSTS Host's domain
+ name and the given domain name is found -- i.e., there are no
+ further labels to compare -- then the given domain name
+ congruently matches this Known HSTS Host.
+
+ We start from the congruent match, and then chop labels and dots and
+ proceed with superdomain match. While RFC6797 recommends to start from
+ superdomain, the result is the same - some valid policy will make a host
+ known.
+ */
+
+ bool superDomainMatch = false;
+ const QString hostNameAsString(url.host());
+ HostName nameToTest(static_cast<QStringRef>(&hostNameAsString));
+ while (nameToTest.fragment.size()) {
+ auto const pos = knownHosts.find(nameToTest);
+ if (pos != knownHosts.end()) {
+ if (pos.value().isExpired())
+ knownHosts.erase(pos);
+ else if (!superDomainMatch || pos.value().includesSubDomains())
+ return true;
+ }
- Q_ASSERT(children.size());
- size_type domainIndex = 0;
- for (int i = 0, e = labels.size(); i < e; ++i) {
- Q_ASSERT(domainIndex < children.size());
- const auto &subDomains = children[domainIndex].labels;
- auto pos = std::lower_bound(subDomains.begin(), subDomains.end(), labels[i]);
- if (pos == subDomains.end() || pos->label != labels[i])
- return false;
+ const int dot = nameToTest.fragment.indexOf(QLatin1Char('.'));
+ if (dot == -1)
+ break;
- Q_ASSERT(pos->domainIndex < children.size());
- domainIndex = pos->domainIndex;
- auto &domain = children[domainIndex];
- if (domain.validateHostPolicy() && (i + 1 == e || domain.includeSubDomains)) {
- /*
- RFC6797, 8.2. Known HSTS Host Domain Name Matching
-
- * Superdomain Match
- If a label-for-label match between an entire Known HSTS Host's
- domain name and a right-hand portion of the given domain name
- is found, then this Known HSTS Host's domain name is a
- superdomain match for the given domain name. There could be
- multiple superdomain matches for a given domain name.
- * Congruent Match
- If a label-for-label match between a Known HSTS Host's domain
- name and the given domain name is found -- i.e., there are no
- further labels to compare -- then the given domain name
- congruently matches this Known HSTS Host.
- */
-
- return true;
- }
+ nameToTest.fragment = nameToTest.fragment.mid(dot + 1);
+ superDomainMatch = true;
}
return false;
@@ -200,10 +180,12 @@ bool QHstsCache::isKnownHost(const QUrl &originalUrl) const
void QHstsCache::clear()
{
- children.resize(1);
- children[0].labels.clear();
- // Top-level is never known:
- Q_ASSERT(!children[0].isKnownHost);
+ knownHosts.clear();
+}
+
+QList<QHstsPolicy> QHstsCache::policies() const
+{
+ return knownHosts.values();
}
// The parser is quite simple: 'nextToken' knowns exactly what kind of tokens
diff --git a/src/network/access/qhsts_p.h b/src/network/access/qhsts_p.h
index f3d5da9d23..5d95f39b96 100644
--- a/src/network/access/qhsts_p.h
+++ b/src/network/access/qhsts_p.h
@@ -51,17 +51,16 @@
// We mean it.
//
+#include <QtNetwork/qhstspolicy.h>
+
#include <QtCore/qbytearray.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qstring.h>
#include <QtCore/qglobal.h>
-#include <QtCore/qvector.h>
#include <QtCore/qlist.h>
#include <QtCore/qpair.h>
#include <QtCore/qurl.h>
-
-#include <algorithm>
-#include <vector>
+#include <QtCore/qmap.h>
QT_BEGIN_NAMESPACE
@@ -69,72 +68,48 @@ class Q_AUTOTEST_EXPORT QHstsCache
{
public:
- QHstsCache();
-
void updateFromHeaders(const QList<QPair<QByteArray, QByteArray>> &headers,
const QUrl &url);
+ void updateFromPolicies(const QList<QHstsPolicy> &hosts);
void updateKnownHost(const QUrl &url, const QDateTime &expires,
bool includeSubDomains);
bool isKnownHost(const QUrl &url) const;
-
void clear();
-private:
-
- using size_type = std::vector<int>::size_type;
-
- struct DomainLabel
- {
- DomainLabel(const QString &name = QString()) : label(name), domainIndex(0) {}
+ QList<QHstsPolicy> policies() const;
- bool operator < (const DomainLabel &rhs) const
- { return label < rhs.label; }
+private:
- QString label;
- size_type domainIndex;
- };
+ void updateKnownHost(const QString &hostName, const QDateTime &expires,
+ bool includeSubDomains);
- struct Domain
+ struct HostName
{
- void setHostPolicy(const QDateTime &expiration, bool subs)
- {
- expirationTime = expiration;
- isKnownHost = expirationTime.isValid()
- && expirationTime > QDateTime::currentDateTimeUtc();
- includeSubDomains = subs;
- }
+ explicit HostName(const QString &n) : name(n) { }
+ explicit HostName(const QStringRef &r) : fragment(r) { }
- bool validateHostPolicy()
+ bool operator < (const HostName &rhs) const
{
- if (!isKnownHost)
- return false;
-
- if (expirationTime > QDateTime::currentDateTimeUtc())
- return true;
-
- isKnownHost = false;
- includeSubDomains = false;
- return false;
+ if (fragment.size()) {
+ if (rhs.fragment.size())
+ return fragment < rhs.fragment;
+ return fragment < QStringRef(&rhs.name);
+ }
+
+ if (rhs.fragment.size())
+ return QStringRef(&name) < rhs.fragment;
+ return name < rhs.name;
}
- bool isKnownHost = false;
- bool includeSubDomains = false;
- QDateTime expirationTime;
- std::vector<DomainLabel> labels;
+ // We use 'name' for a HostName object contained in our dictionary;
+ // we use 'fragment' only during lookup, when chopping the complete host
+ // name, removing subdomain names (such HostName object is 'transient', it
+ // must not outlive the original QString object.
+ QString name;
+ QStringRef fragment;
};
- /*
- Each Domain represents a DNS name or prefix thereof; each entry in its
- std::vector<DomainLabel> labels pairs the next fragment of a DNS name
- with the index into 'children' at which to find another Domain object.
- The root Domain, children[0], has top-level-domain DomainLabel entries,
- such as "com", "org" and "net"; the entry in 'children' at the index it
- pairs with "com" is the Domain entry for .com; if that has "example" in
- its labels, it'll be paired with the index of the entry in 'children'
- that represents example.com; from which, in turn, we can find the
- Domain object for www.example.com, and so on.
- */
- mutable std::vector<Domain> children;
+ mutable QMap<HostName, QHstsPolicy> knownHosts;
};
class Q_AUTOTEST_EXPORT QHstsHeaderParser
diff --git a/src/network/access/qhstspolicy.cpp b/src/network/access/qhstspolicy.cpp
new file mode 100644
index 0000000000..2cec587f4d
--- /dev/null
+++ b/src/network/access/qhstspolicy.cpp
@@ -0,0 +1,218 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qhstspolicy.h"
+
+#include <QtCore/qdatetime.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QHstsPolicy
+ \brief The QHstsPolicy class specifies that a host supports HTTP Strict Transport
+ Security policy (HSTS).
+ \since 5.9
+ \ingroup network
+ \inmodule QtNetwork
+
+ HSTS policy defines a period of time during which QNetworkAccessManager
+ should only access a host in a secure fashion. HSTS policy is defined by
+ RFC6797.
+
+ You can set expiry time and host name for this policy, and control whether it
+ applies to subdomains, either in the constructor or by calling setExpiry(),
+ setHost() and setIncludesSubdomains().
+
+ \sa QNetworkAccessManager::enableStrictTransportSecurity()
+*/
+
+class QHstsPolicyPrivate
+{
+public:
+ QUrl url;
+ QDateTime expiry;
+ bool includeSubDomains = false;
+
+ bool operator == (const QHstsPolicyPrivate &other) const
+ {
+ return url.host() == other.url.host() && expiry == other.expiry
+ && includeSubDomains == other.includeSubDomains;
+ }
+};
+
+/*!
+ Constructs an invalid (expired) policy with empty host name and subdomains
+ not included.
+*/
+QHstsPolicy::QHstsPolicy() : d(new QHstsPolicyPrivate)
+{
+}
+
+/*!
+ Constructs QHstsPolicy with \a expiry (in UTC); \a includeSubDomains parameter
+ defines if this policy must also include subdomains, \a host data is interpreted
+ according to \a mode.
+
+ \sa QUrl::setHost(), QUrl::ParsingMode
+*/
+QHstsPolicy::QHstsPolicy(const QDateTime &expiry, bool includeSubDomains, const QString &host,
+ QUrl::ParsingMode mode)
+ : d(new QHstsPolicyPrivate)
+{
+ d->url.setHost(host, mode);
+ d->expiry = expiry;
+ d->includeSubDomains = includeSubDomains;
+}
+
+/*!
+ Creates a copy of \a other object.
+*/
+QHstsPolicy::QHstsPolicy(const QHstsPolicy &other)
+ : d(new QHstsPolicyPrivate(*other.d))
+{
+}
+
+/*!
+ Destructor.
+*/
+QHstsPolicy::~QHstsPolicy()
+{
+}
+
+/*!
+ Copy-assignment operator, makes a copy of \a other.
+*/
+QHstsPolicy &QHstsPolicy::operator=(const QHstsPolicy &other)
+{
+ *d = *other.d;
+ return *this;
+}
+
+
+/*!
+ Move-assignment operator.
+*/
+QHstsPolicy &QHstsPolicy::operator=(QHstsPolicy &&other) Q_DECL_NOTHROW
+{
+ qSwap(d, other.d);
+ return *this;
+}
+
+/*!
+ Sets a host, \a host data is interpreted according to \a mode parameter.
+
+ \sa host(), QUrl::setHost(), QUrl::ParsingMode
+*/
+void QHstsPolicy::setHost(const QString &host, QUrl::ParsingMode mode)
+{
+ d->url.setHost(host, mode);
+}
+
+/*!
+ Returns a host for a given policy, formatted according to \a options.
+
+ \sa setHost(), QUrl::host(), QUrl::ComponentFormattingOptions
+*/
+QString QHstsPolicy::host(QUrl::ComponentFormattingOptions options) const
+{
+ return d->url.host(options);
+}
+
+/*!
+ Sets the expiration date for the policy (in UTC).
+
+ \sa expiry()
+*/
+void QHstsPolicy::setExpiry(const QDateTime &expiry)
+{
+ d->expiry = expiry;
+}
+
+/*!
+ Returns the expiration date for the policy (in UTC).
+
+ \sa setExpiry()
+*/
+QDateTime QHstsPolicy::expiry() const
+{
+ return d->expiry;
+}
+
+/*!
+ Includes or excludes subdomains for this policy.
+
+ \sa includeSubdomains()
+*/
+void QHstsPolicy::setIncludesSubDomains(bool include)
+{
+ d->includeSubDomains = include;
+}
+
+/*!
+ Returns \c true if this policy also includes subdomains.
+
+ \sa setIncludesSubDomains()
+ */
+bool QHstsPolicy::includesSubDomains() const
+{
+ return d->includeSubDomains;
+}
+
+/*!
+ Returns \c true if the two policies have the same host and expriration date
+ while agreeing on whether to include or exclude subdomains.
+*/
+bool QHstsPolicy::operator==(const QHstsPolicy &other) const
+{
+ return *d == *other.d;
+}
+
+/*!
+ Return \c true if this policy has a valid expiration date and this date
+ is greater than QDateTime::currentGetDateTimeUtc().
+
+ \sa setExpiry(), expiry()
+*/
+bool QHstsPolicy::isExpired() const
+{
+ return !d->expiry.isValid() || d->expiry <= QDateTime::currentDateTimeUtc();
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/access/qhstspolicy.h b/src/network/access/qhstspolicy.h
new file mode 100644
index 0000000000..4260ac278c
--- /dev/null
+++ b/src/network/access/qhstspolicy.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHSTSPOLICY_H
+#define QHSTSPOLICY_H
+
+#include <QtNetwork/qtnetworkglobal.h>
+
+#include <QtCore/qscopedpointer.h>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_NAMESPACE
+
+class QHstsPolicyPrivate;
+class QDateTime;
+class QString;
+class Q_NETWORK_EXPORT QHstsPolicy
+{
+public:
+
+ QHstsPolicy();
+ QHstsPolicy(const QDateTime &expiry, bool includeSubDomains, const QString &host,
+ QUrl::ParsingMode mode = QUrl::DecodedMode);
+ QHstsPolicy(const QHstsPolicy &rhs);
+ QHstsPolicy &operator=(const QHstsPolicy &rhs);
+ QHstsPolicy &operator=(QHstsPolicy &&rhs) Q_DECL_NOTHROW;
+ ~QHstsPolicy();
+
+ void setHost(const QString &host, QUrl::ParsingMode mode = QUrl::DecodedMode);
+ QString host(QUrl::ComponentFormattingOptions options = QUrl::FullyDecoded) const;
+ void setExpiry(const QDateTime &expiry);
+ QDateTime expiry() const;
+ void setIncludesSubDomains(bool include);
+ bool includesSubDomains() const;
+
+ bool operator==(const QHstsPolicy &rhs) const;
+ bool isExpired() const;
+
+private:
+
+ QScopedPointer<QHstsPolicyPrivate> d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QHSTSPOLICY_H
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index 7aa8e61d26..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"
@@ -742,6 +744,45 @@ bool QNetworkAccessManager::strictTransportSecurityEnabled() const
}
/*!
+ \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.
diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h
index 143407fb25..52769627f3 100644
--- a/src/network/access/qnetworkaccessmanager.h
+++ b/src/network/access/qnetworkaccessmanager.h
@@ -61,6 +61,7 @@ class QNetworkReply;
class QNetworkProxy;
class QNetworkProxyFactory;
class QSslError;
+class QHstsPolicy;
#ifndef QT_NO_BEARERMANAGEMENT
class QNetworkConfiguration;
#endif
@@ -123,6 +124,8 @@ public:
void enableStrictTransportSecurity();
void disableStrictTransportSecurity();
bool strictTransportSecurityEnabled() const;
+ void addStrictTransportSecurityHosts(const QList<QHstsPolicy> &knownHosts);
+ QList<QHstsPolicy> strictTransportSecurityHosts() const;
QNetworkReply *head(const QNetworkRequest &request);
QNetworkReply *get(const QNetworkRequest &request);