| Index: net/base/sdch_dictionary.cc
|
| diff --git a/net/base/sdch_dictionary.cc b/net/base/sdch_dictionary.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..875cce66b17fb7338852918cc05ffd5f273e5726
|
| --- /dev/null
|
| +++ b/net/base/sdch_dictionary.cc
|
| @@ -0,0 +1,170 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "net/base/sdch_dictionary.h"
|
| +
|
| +#include "base/time/clock.h"
|
| +#include "base/time/default_clock.h"
|
| +#include "base/values.h"
|
| +#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
|
| +
|
| +namespace {
|
| +
|
| +bool DomainMatch(const GURL& gurl, const std::string& restriction) {
|
| + // TODO(jar): This is not precisely a domain match definition.
|
| + return gurl.DomainIs(restriction.data(), restriction.size());
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +namespace net {
|
| +
|
| +SdchDictionary::SdchDictionary(const std::string& dictionary_text,
|
| + size_t offset,
|
| + const std::string& client_hash,
|
| + const std::string& server_hash,
|
| + const GURL& gurl,
|
| + const std::string& domain,
|
| + const std::string& path,
|
| + const base::Time& expiration,
|
| + const std::set<int>& ports)
|
| + : text_(dictionary_text, offset),
|
| + client_hash_(client_hash),
|
| + server_hash_(server_hash),
|
| + url_(gurl),
|
| + domain_(domain),
|
| + path_(path),
|
| + expiration_(expiration),
|
| + ports_(ports),
|
| + clock_(new base::DefaultClock) {
|
| +}
|
| +
|
| +SdchDictionary::SdchDictionary(const SdchDictionary& rhs)
|
| + : text_(rhs.text_),
|
| + client_hash_(rhs.client_hash_),
|
| + server_hash_(rhs.server_hash_),
|
| + url_(rhs.url_),
|
| + domain_(rhs.domain_),
|
| + path_(rhs.path_),
|
| + expiration_(rhs.expiration_),
|
| + ports_(rhs.ports_),
|
| + clock_(new base::DefaultClock) {
|
| +}
|
| +
|
| +SdchDictionary::~SdchDictionary() {
|
| +}
|
| +
|
| +// Security functions restricting loads and use of dictionaries.
|
| +
|
| +// static
|
| +SdchProblemCode SdchDictionary::CanSet(const std::string& domain,
|
| + const std::string& path,
|
| + const std::set<int>& ports,
|
| + const GURL& dictionary_url) {
|
| + /*
|
| + * A dictionary is invalid and must not be stored if any of the following are
|
| + * true:
|
| + * 1. The dictionary has no Domain attribute.
|
| + * 2. The effective host name that derives from the referer URL host name does
|
| + * not domain-match the Domain attribute.
|
| + * 3. The Domain attribute is a top level domain.
|
| + * 4. The referer URL host is a host domain name (not IP address) and has the
|
| + * form HD, where D is the value of the Domain attribute, and H is a string
|
| + * that contains one or more dots.
|
| + * 5. If the dictionary has a Port attribute and the referer URL's port
|
| + * was not in the list.
|
| + */
|
| +
|
| + // TODO(jar): Redirects in dictionary fetches might plausibly be problematic,
|
| + // and hence the conservative approach is to not allow any redirects (if there
|
| + // were any... then don't allow the dictionary to be set).
|
| +
|
| + if (domain.empty())
|
| + return SDCH_DICTIONARY_MISSING_DOMAIN_SPECIFIER; // Domain is required.
|
| +
|
| + if (registry_controlled_domains::GetDomainAndRegistry(
|
| + domain, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)
|
| + .empty()) {
|
| + return SDCH_DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN; // domain was a TLD.
|
| + }
|
| +
|
| + if (!DomainMatch(dictionary_url, domain))
|
| + return SDCH_DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL;
|
| +
|
| + std::string referrer_url_host = dictionary_url.host();
|
| + size_t postfix_domain_index = referrer_url_host.rfind(domain);
|
| + // See if it is indeed a postfix, or just an internal string.
|
| + if (referrer_url_host.size() == postfix_domain_index + domain.size()) {
|
| + // It is a postfix... so check to see if there's a dot in the prefix.
|
| + size_t end_of_host_index = referrer_url_host.find_first_of('.');
|
| + if (referrer_url_host.npos != end_of_host_index &&
|
| + end_of_host_index < postfix_domain_index) {
|
| + return SDCH_DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX;
|
| + }
|
| + }
|
| +
|
| + if (!ports.empty() && 0 == ports.count(dictionary_url.EffectiveIntPort()))
|
| + return SDCH_DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL;
|
| +
|
| + return SDCH_OK;
|
| +}
|
| +
|
| +SdchProblemCode SdchDictionary::CanUse(const GURL& target_url) const {
|
| + /*
|
| + * 1. The request URL's host name domain-matches the Domain attribute of the
|
| + * dictionary.
|
| + * 2. If the dictionary has a Port attribute, the request port is one of the
|
| + * ports listed in the Port attribute.
|
| + * 3. The request URL path-matches the path attribute of the dictionary.
|
| + * We can override (ignore) item (4) only when we have explicitly enabled
|
| + * HTTPS support AND the dictionary acquisition scheme matches the target
|
| + * url scheme.
|
| + */
|
| + if (!DomainMatch(target_url, domain_))
|
| + return SDCH_DICTIONARY_FOUND_HAS_WRONG_DOMAIN;
|
| +
|
| + if (!ports_.empty() && 0 == ports_.count(target_url.EffectiveIntPort()))
|
| + return SDCH_DICTIONARY_FOUND_HAS_WRONG_PORT_LIST;
|
| +
|
| + if (path_.size() && !PathMatch(target_url.path(), path_))
|
| + return SDCH_DICTIONARY_FOUND_HAS_WRONG_PATH;
|
| +
|
| + if (target_url.SchemeIsSecure() != url_.SchemeIsSecure())
|
| + return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
|
| +
|
| + // TODO(jar): Remove overly restrictive failsafe test (added per security
|
| + // review) when we have a need to be more general.
|
| + if (!target_url.SchemeIsHTTPOrHTTPS())
|
| + return SDCH_ATTEMPT_TO_DECODE_NON_HTTP_DATA;
|
| +
|
| + return SDCH_OK;
|
| +}
|
| +
|
| +// static
|
| +bool SdchDictionary::PathMatch(const std::string& path,
|
| + const std::string& restriction) {
|
| + /* Must be either:
|
| + * 1. P2 is equal to P1
|
| + * 2. P2 is a prefix of P1 and either the final character in P2 is "/"
|
| + * or the character following P2 in P1 is "/".
|
| + */
|
| + if (path == restriction)
|
| + return true;
|
| + size_t prefix_length = restriction.size();
|
| + if (prefix_length > path.size())
|
| + return false; // Can't be a prefix.
|
| + if (0 != path.compare(0, prefix_length, restriction))
|
| + return false;
|
| + return restriction[prefix_length - 1] == '/' || path[prefix_length] == '/';
|
| +}
|
| +
|
| +bool SdchDictionary::Expired() const {
|
| + return clock_->Now() > expiration_;
|
| +}
|
| +
|
| +void SdchDictionary::SetClockForTesting(scoped_ptr<base::Clock> clock) {
|
| + clock_ = clock.Pass();
|
| +}
|
| +
|
| +} // namespace net
|
|
|