summaryrefslogtreecommitdiffstats
path: root/src/network/access/qhsts_p.h
diff options
context:
space:
mode:
authorTimur Pocheptsov <timur.pocheptsov@qt.io>2017-01-23 12:26:55 +0100
committerTimur Pocheptsov <timur.pocheptsov@qt.io>2017-01-24 20:33:20 +0000
commitd2758b2f1dd88d273ff70864a0dd03a7c4e9dc78 (patch)
tree0f6e4fe0d1ac3289ce1a3d6ae53722560a05829c /src/network/access/qhsts_p.h
parentbd78f57463c381203099d7939c9d37cba0341713 (diff)
Refactor HSTS cache implementation
The original monstrosity is not needed at all. It was born only to implement RFC6797's description of the host matching algorithm (starting from superdomains and moving to subdomains). Actually, it does not really matter how we find known host - it can be a congruent match first instead, and then we proceed with superdomains. This way I can use QMap and my tests so far show it actually works faster (both insertion and lookup), also the code is cleaner now. Also, introduce the new class QHstsPolicy that essentially allows to mark a host as known host and conveniently encapsulates host name/expiration date/ subdomains policy. Add a public API providing access to HSTS policies, so that client code can pre-set or read back discovered known hosts (to implement persistent HSTS storage, for example). We support server-driven HSTS - this means client code is allowed to provide policies as hints to QNetworkAccessManager, but these policies can be overridden by HTTP responses with 'Strict-Transport-Security' headers. Change-Id: I64d250b6dc78bcb01003fadeded5302471d1389e Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Diffstat (limited to 'src/network/access/qhsts_p.h')
-rw-r--r--src/network/access/qhsts_p.h81
1 files changed, 28 insertions, 53 deletions
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