Commit 75b35192 authored by rdsmith's avatar rdsmith Committed by Commit bot

Split SdchManager::Dictionary out into separate class/file.

BUG=None
R=ellyjones@chromium.org

Review URL: https://codereview.chromium.org/1051933002

Cr-Commit-Position: refs/heads/master@{#324333}
parent 98306881
// 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
// 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.
#ifndef NET_BASE_SDCH_DICTIONARY_H_
#define NET_BASE_SDCH_DICTIONARY_H_
#include <set>
#include <string>
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
#include "net/base/net_export.h"
#include "net/base/sdch_problem_codes.h"
#include "url/gurl.h"
namespace base {
class Clock;
class Value;
}
namespace net {
// Contains all information for an SDCH dictionary. This class is intended
// to be used with a RefCountedData<> wrappers. These dictionaries
// are vended by SdchManager; see sdch_manager.h for details.
class NET_EXPORT_PRIVATE SdchDictionary {
public:
// Construct a vc-diff usable dictionary from the dictionary_text starting
// at the given offset. The supplied client_hash should be used to
// advertise the dictionary's availability relative to the suppplied URL.
SdchDictionary(const std::string& dictionary_text,
size_t offset,
const std::string& client_hash,
const std::string& server_hash,
const GURL& url,
const std::string& domain,
const std::string& path,
const base::Time& expiration,
const std::set<int>& ports);
~SdchDictionary();
// Sdch filters can get our text to use in decoding compressed data.
const std::string& text() const { return text_; }
const GURL& url() const { return url_; }
const std::string& client_hash() const { return client_hash_; }
const std::string& server_hash() const { return server_hash_; }
const std::string& domain() const { return domain_; }
const std::string& path() const { return path_; }
const base::Time& expiration() const { return expiration_; }
const std::set<int>& ports() const { return ports_; }
// Security methods to check if we can establish a new dictionary with the
// given data, that arrived in response to get of dictionary_url.
static SdchProblemCode CanSet(const std::string& domain,
const std::string& path,
const std::set<int>& ports,
const GURL& dictionary_url);
// Security method to check if we can use a dictionary to decompress a
// target that arrived with a reference to this dictionary.
SdchProblemCode CanUse(const GURL& referring_url) const;
// Compare paths to see if they "match" for dictionary use.
static bool PathMatch(const std::string& path,
const std::string& restriction);
// Is this dictionary expired?
bool Expired() const;
void SetClockForTesting(scoped_ptr<base::Clock> clock);
private:
friend class base::RefCountedData<SdchDictionary>;
// Private copy-constructor to support RefCountedData<>, which requires
// that an object stored in it be either DefaultConstructible or
// CopyConstructible
SdchDictionary(const SdchDictionary& rhs);
// The actual text of the dictionary.
std::string text_;
// Part of the hash of text_ that the client uses to advertise the fact that
// it has a specific dictionary pre-cached.
std::string client_hash_;
// Part of the hash of text_ that the server uses to identify the
// dictionary it wants used for decoding.
std::string server_hash_;
// The GURL that arrived with the text_ in a URL request to specify where
// this dictionary may be used.
const GURL url_;
// Metadate "headers" in before dictionary text contained the following:
// Each dictionary payload consists of several headers, followed by the text
// of the dictionary. The following are the known headers.
const std::string domain_;
const std::string path_;
const base::Time expiration_; // Implied by max-age.
const std::set<int> ports_;
scoped_ptr<base::Clock> clock_;
void operator=(const SdchDictionary&) = delete;
};
} // namespace net
#endif // NET_BASE_SDCH_DICTIONARY_H_
// 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 <set>
#include <string>
#include "net/base/sdch_problem_codes.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
TEST(SdchDictionaryTest, CanSet) {
SdchProblemCode (*CanSet)(const std::string& domain, const std::string& path,
const std::set<int>& ports,
const GURL& dictionary_url) =
SdchDictionary::CanSet;
std::set<int> single_port;
single_port.insert(1);
std::set<int> dual_port;
dual_port.insert(2);
dual_port.insert(3);
// Not testing specific error codes; that's implementation, not behavior.
EXPECT_EQ(SDCH_OK, CanSet("www.google.com", "", std::set<int>(),
GURL("http://www.google.com/dictionary")));
EXPECT_NE(SDCH_OK, CanSet("", "", std::set<int>(),
GURL("http://www.google.com/dictionary")));
EXPECT_NE(SDCH_OK,
CanSet("com", "", std::set<int>(), GURL("http://com/dictionary")));
EXPECT_NE(SDCH_OK, CanSet("www.google.com", "", std::set<int>(),
GURL("http://www.simple.com/dictionary")));
EXPECT_EQ(SDCH_OK, CanSet(".google.com", "", std::set<int>(),
GURL("http://www.google.com/dictionary")));
EXPECT_NE(SDCH_OK, CanSet("google.com", "", std::set<int>(),
GURL("http://www.google.com/dictionary")));
EXPECT_EQ(SDCH_OK, CanSet("www.google.com", "", single_port,
GURL("http://www.google.com:1/dictionary")));
EXPECT_EQ(SDCH_OK, CanSet("www.google.com", "", dual_port,
GURL("http://www.google.com:2/dictionary")));
EXPECT_NE(SDCH_OK, CanSet("www.google.com", "", single_port,
GURL("http://www.google.com:10/dictionary")));
EXPECT_NE(SDCH_OK, CanSet("www.google.com", "", dual_port,
GURL("http://www.google.com:10/dictionary")));
}
TEST(SdchDictionaryTest, CanUse) {
std::set<int> dual_port;
dual_port.insert(2);
dual_port.insert(3);
SdchDictionary test_dictionary_1(
"xyzzy", 0u, // text, offset
"ch", "sh", // client hash, server hash
GURL("http://www.example.com"), "www.example.com",
"/url", // domain, path
base::Time::Now() + base::TimeDelta::FromSeconds(1), // expiration
dual_port); // ports
// Not testing specific error codes; that's implementation, not behavior.
EXPECT_EQ(SDCH_OK,
test_dictionary_1.CanUse(GURL("http://www.example.com:2/url")));
EXPECT_NE(SDCH_OK,
test_dictionary_1.CanUse(GURL("http://www.google.com:2/url")));
EXPECT_NE(SDCH_OK,
test_dictionary_1.CanUse(GURL("http://www.example.com:4/url")));
EXPECT_NE(SDCH_OK,
test_dictionary_1.CanUse(GURL("http://www.example.com:2/wurl")));
EXPECT_NE(SDCH_OK,
test_dictionary_1.CanUse(GURL("https://www.example.com:2/url")));
EXPECT_NE(SDCH_OK,
test_dictionary_1.CanUse(GURL("ws://www.example.com:2/url")));
}
TEST(SdchDictionaryTest, PathMatch) {
bool (*PathMatch)(const std::string& path, const std::string& restriction) =
SdchDictionary::PathMatch;
// Perfect match is supported.
EXPECT_TRUE(PathMatch("/search", "/search"));
EXPECT_TRUE(PathMatch("/search/", "/search/"));
// Prefix only works if last character of restriction is a slash, or first
// character in path after a match is a slash. Validate each case separately.
// Rely on the slash in the path (not at the end of the restriction).
EXPECT_TRUE(PathMatch("/search/something", "/search"));
EXPECT_TRUE(PathMatch("/search/s", "/search"));
EXPECT_TRUE(PathMatch("/search/other", "/search"));
EXPECT_TRUE(PathMatch("/search/something", "/search"));
// Rely on the slash at the end of the restriction.
EXPECT_TRUE(PathMatch("/search/something", "/search/"));
EXPECT_TRUE(PathMatch("/search/s", "/search/"));
EXPECT_TRUE(PathMatch("/search/other", "/search/"));
EXPECT_TRUE(PathMatch("/search/something", "/search/"));
// Make sure less that sufficient prefix match is false.
EXPECT_FALSE(PathMatch("/sear", "/search"));
EXPECT_FALSE(PathMatch("/", "/search"));
EXPECT_FALSE(PathMatch(std::string(), "/search"));
// Add examples with several levels of direcories in the restriction.
EXPECT_FALSE(PathMatch("/search/something", "search/s"));
EXPECT_FALSE(PathMatch("/search/", "/search/s"));
// Make sure adding characters to path will also fail.
EXPECT_FALSE(PathMatch("/searching", "/search/"));
EXPECT_FALSE(PathMatch("/searching", "/search"));
// Make sure we're case sensitive.
EXPECT_FALSE(PathMatch("/ABC", "/abc"));
EXPECT_FALSE(PathMatch("/abc", "/ABC"));
}
TEST(SdchDictionaryTest, Expired) {
EXPECT_TRUE(
SdchDictionary("xyzzy", 0u, "ch", "sh", GURL("http://www.example.com"),
"www.example.com", "/url",
base::Time::Now() - base::TimeDelta::FromSeconds(1),
std::set<int>()).Expired());
EXPECT_FALSE(
SdchDictionary("xyzzy", 0u, "ch", "sh", GURL("http://www.example.com"),
"www.example.com", "/url",
base::Time::Now() + base::TimeDelta::FromSeconds(1),
std::set<int>()).Expired());
}
} // namespace net
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
#include "base/time/default_clock.h" #include "base/time/default_clock.h"
#include "base/values.h" #include "base/values.h"
#include "crypto/sha2.h" #include "crypto/sha2.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/base/sdch_observer.h" #include "net/base/sdch_observer.h"
#include "net/url_request/url_request_http_job.h" #include "net/url_request/url_request_http_job.h"
...@@ -45,165 +44,6 @@ bool SdchManager::g_sdch_enabled_ = true; ...@@ -45,165 +44,6 @@ bool SdchManager::g_sdch_enabled_ = true;
// static // static
bool SdchManager::g_secure_scheme_supported_ = true; bool SdchManager::g_secure_scheme_supported_ = true;
SdchManager::Dictionary::Dictionary(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) {
}
SdchManager::Dictionary::Dictionary(const SdchManager::Dictionary& 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) {
}
SdchManager::Dictionary::~Dictionary() {}
// Security functions restricting loads and use of dictionaries.
// static
SdchProblemCode SdchManager::Dictionary::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 (!Dictionary::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 SdchManager::Dictionary::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.
4. The request is not an HTTPS request.
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 (!SdchManager::secure_scheme_supported() && target_url.SchemeIsSecure())
return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
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 SdchManager::Dictionary::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] == '/';
}
// static
bool SdchManager::Dictionary::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());
}
bool SdchManager::Dictionary::Expired() const {
return clock_->Now() > expiration_;
}
void SdchManager::Dictionary::SetClockForTesting(
scoped_ptr<base::Clock> clock) {
clock_ = clock.Pass();
}
SdchManager::DictionarySet::DictionarySet() {} SdchManager::DictionarySet::DictionarySet() {}
SdchManager::DictionarySet::~DictionarySet() {} SdchManager::DictionarySet::~DictionarySet() {}
...@@ -221,7 +61,7 @@ std::string SdchManager::DictionarySet::GetDictionaryClientHashList() const { ...@@ -221,7 +61,7 @@ std::string SdchManager::DictionarySet::GetDictionaryClientHashList() const {
return result; return result;
} }
const SdchManager::Dictionary* SdchManager::DictionarySet::GetDictionary( const SdchDictionary* SdchManager::DictionarySet::GetDictionary(
const std::string& hash) const { const std::string& hash) const {
auto it = dictionaries_.find(hash); auto it = dictionaries_.find(hash);
if (it == dictionaries_.end()) if (it == dictionaries_.end())
...@@ -236,8 +76,7 @@ bool SdchManager::DictionarySet::Empty() const { ...@@ -236,8 +76,7 @@ bool SdchManager::DictionarySet::Empty() const {
void SdchManager::DictionarySet::AddDictionary( void SdchManager::DictionarySet::AddDictionary(
const std::string& server_hash, const std::string& server_hash,
const scoped_refptr<base::RefCountedData<SdchManager::Dictionary>>& const scoped_refptr<base::RefCountedData<SdchDictionary>>& dictionary) {
dictionary) {
DCHECK(dictionaries_.end() == dictionaries_.find(server_hash)); DCHECK(dictionaries_.end() == dictionaries_.find(server_hash));
dictionaries_[server_hash] = dictionary; dictionaries_[server_hash] = dictionary;
...@@ -430,6 +269,8 @@ SdchManager::GetDictionarySet(const GURL& target_url) { ...@@ -430,6 +269,8 @@ SdchManager::GetDictionarySet(const GURL& target_url) {
int count = 0; int count = 0;
scoped_ptr<SdchManager::DictionarySet> result(new DictionarySet); scoped_ptr<SdchManager::DictionarySet> result(new DictionarySet);
for (const auto& entry: dictionaries_) { for (const auto& entry: dictionaries_) {
if (!secure_scheme_supported() && target_url.SchemeIsSecure())
continue;
if (entry.second->data.CanUse(target_url) != SDCH_OK) if (entry.second->data.CanUse(target_url) != SDCH_OK)
continue; continue;
if (entry.second->data.Expired()) if (entry.second->data.Expired())
...@@ -458,6 +299,11 @@ SdchManager::GetDictionarySetByHash( ...@@ -458,6 +299,11 @@ SdchManager::GetDictionarySetByHash(
if (it == dictionaries_.end()) if (it == dictionaries_.end())
return result.Pass(); return result.Pass();
if (!SdchManager::secure_scheme_supported() && target_url.SchemeIsSecure()) {
*problem_code = SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
return result.Pass();
}
*problem_code = it->second->data.CanUse(target_url); *problem_code = it->second->data.CanUse(target_url);
if (*problem_code != SDCH_OK) if (*problem_code != SDCH_OK)
return result.Pass(); return result.Pass();
...@@ -587,18 +433,18 @@ SdchProblemCode SdchManager::AddSdchDictionary( ...@@ -587,18 +433,18 @@ SdchProblemCode SdchManager::AddSdchDictionary(
if (rv != SDCH_OK) if (rv != SDCH_OK)
return rv; return rv;
rv = Dictionary::CanSet(domain, path, ports, dictionary_url_normalized); rv = SdchDictionary::CanSet(domain, path, ports, dictionary_url_normalized);
if (rv != SDCH_OK) if (rv != SDCH_OK)
return rv; return rv;
UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size()); UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size());
DVLOG(1) << "Loaded dictionary with client hash " << client_hash DVLOG(1) << "Loaded dictionary with client hash " << client_hash
<< " and server hash " << server_hash; << " and server hash " << server_hash;
Dictionary dictionary(dictionary_text, header_end + 2, client_hash, SdchDictionary dictionary(dictionary_text, header_end + 2, client_hash,
server_hash, dictionary_url_normalized, domain, path, server_hash, dictionary_url_normalized, domain,
expiration, ports); path, expiration, ports);
dictionaries_[server_hash] = dictionaries_[server_hash] =
new base::RefCountedData<Dictionary>(dictionary); new base::RefCountedData<SdchDictionary>(dictionary);
if (server_hash_p) if (server_hash_p)
*server_hash_p = server_hash; *server_hash_p = server_hash;
......
...@@ -2,15 +2,13 @@ ...@@ -2,15 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// This file contains the SdchManager class and two nested classes // This file contains the SdchManager class and the DictionarySet
// (Dictionary, DictionarySet). SdchManager::Dictionary contains all // nested class. The manager is responsible for storing all
// of the information about an SDCH dictionary. The manager is // SdchDictionarys, and provides access to them through DictionarySet
// responsible for storing those dictionaries, and provides access to // objects. A DictionarySet is an object whose lifetime is under the
// them through DictionarySet objects. A DictionarySet is an object // control of the consumer. It is a reference to a set of
// whose lifetime is under the control of the consumer. It is a // dictionaries, and guarantees that none of those dictionaries will
// reference to a set of dictionaries, and guarantees that none of // be destroyed while the DictionarySet reference is alive.
// those dictionaries will be destroyed while the DictionarySet
// reference is alive.
#ifndef NET_BASE_SDCH_MANAGER_H_ #ifndef NET_BASE_SDCH_MANAGER_H_
#define NET_BASE_SDCH_MANAGER_H_ #define NET_BASE_SDCH_MANAGER_H_
...@@ -26,13 +24,13 @@ ...@@ -26,13 +24,13 @@
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/observer_list.h" #include "base/observer_list.h"
#include "base/threading/thread_checker.h" #include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "net/base/net_export.h" #include "net/base/net_export.h"
#include "net/base/sdch_dictionary.h"
#include "net/base/sdch_problem_codes.h" #include "net/base/sdch_problem_codes.h"
#include "url/gurl.h"
class GURL;
namespace base { namespace base {
class Clock;
class Value; class Value;
} }
...@@ -56,97 +54,10 @@ class SdchObserver; ...@@ -56,97 +54,10 @@ class SdchObserver;
// a DictionarySet object refers to it; see below. // a DictionarySet object refers to it; see below.
class NET_EXPORT SdchManager { class NET_EXPORT SdchManager {
public: public:
class Dictionary; typedef std::map<std::string,
typedef std::map<std::string, scoped_refptr<base::RefCountedData<Dictionary>>> scoped_refptr<base::RefCountedData<SdchDictionary>>>
DictionaryMap; DictionaryMap;
class NET_EXPORT_PRIVATE Dictionary {
public:
// Construct a vc-diff usable dictionary from the dictionary_text starting
// at the given offset. The supplied client_hash should be used to
// advertise the dictionary's availability relative to the suppplied URL.
Dictionary(const std::string& dictionary_text,
size_t offset,
const std::string& client_hash,
const std::string& server_hash,
const GURL& url,
const std::string& domain,
const std::string& path,
const base::Time& expiration,
const std::set<int>& ports);
~Dictionary();
// Sdch filters can get our text to use in decoding compressed data.
const std::string& text() const { return text_; }
const GURL& url() const { return url_; }
const std::string& client_hash() const { return client_hash_; }
const std::string& server_hash() const { return server_hash_; }
const std::string& domain() const { return domain_; }
const std::string& path() const { return path_; }
const base::Time& expiration() const { return expiration_; }
const std::set<int>& ports() const { return ports_; }
// Security methods to check if we can establish a new dictionary with the
// given data, that arrived in response to get of dictionary_url.
static SdchProblemCode CanSet(const std::string& domain,
const std::string& path,
const std::set<int>& ports,
const GURL& dictionary_url);
// Security method to check if we can use a dictionary to decompress a
// target that arrived with a reference to this dictionary.
SdchProblemCode CanUse(const GURL& referring_url) const;
// Compare paths to see if they "match" for dictionary use.
static bool PathMatch(const std::string& path,
const std::string& restriction);
// Compare domains to see if the "match" for dictionary use.
static bool DomainMatch(const GURL& url, const std::string& restriction);
// Is this dictionary expired?
bool Expired() const;
void SetClockForTesting(scoped_ptr<base::Clock> clock);
private:
friend class base::RefCountedData<Dictionary>;
// Private copy-constructor to support RefCountedData<>, which requires
// that an object stored in it be either DefaultConstructible or
// CopyConstructible
Dictionary(const Dictionary& rhs);
// The actual text of the dictionary.
std::string text_;
// Part of the hash of text_ that the client uses to advertise the fact that
// it has a specific dictionary pre-cached.
std::string client_hash_;
// Part of the hash of text_ that the server uses to identify the
// dictionary it wants used for decoding.
std::string server_hash_;
// The GURL that arrived with the text_ in a URL request to specify where
// this dictionary may be used.
const GURL url_;
// Metadate "headers" in before dictionary text contained the following:
// Each dictionary payload consists of several headers, followed by the text
// of the dictionary. The following are the known headers.
const std::string domain_;
const std::string path_;
const base::Time expiration_; // Implied by max-age.
const std::set<int> ports_;
scoped_ptr<base::Clock> clock_;
void operator=(const Dictionary&) = delete;
};
// A handle for one or more dictionaries which will keep the dictionaries // A handle for one or more dictionaries which will keep the dictionaries
// alive and accessible for the handle's lifetime. // alive and accessible for the handle's lifetime.
class NET_EXPORT_PRIVATE DictionarySet { class NET_EXPORT_PRIVATE DictionarySet {
...@@ -160,7 +71,7 @@ class NET_EXPORT SdchManager { ...@@ -160,7 +71,7 @@ class NET_EXPORT SdchManager {
// is guaranteed to be valid for the lifetime of the DictionarySet. // is guaranteed to be valid for the lifetime of the DictionarySet.
// Returns NULL if hash is not a valid server hash for a dictionary // Returns NULL if hash is not a valid server hash for a dictionary
// named by DictionarySet. // named by DictionarySet.
const SdchManager::Dictionary* GetDictionary(const std::string& hash) const; const SdchDictionary* GetDictionary(const std::string& hash) const;
bool Empty() const; bool Empty() const;
...@@ -169,9 +80,9 @@ class NET_EXPORT SdchManager { ...@@ -169,9 +80,9 @@ class NET_EXPORT SdchManager {
friend class SdchManager; friend class SdchManager;
DictionarySet(); DictionarySet();
void AddDictionary(const std::string& server_hash, void AddDictionary(
const scoped_refptr<base::RefCountedData< const std::string& server_hash,
SdchManager::Dictionary>>& dictionary); const scoped_refptr<base::RefCountedData<SdchDictionary>>& dictionary);
DictionaryMap dictionaries_; DictionaryMap dictionaries_;
......
...@@ -419,46 +419,6 @@ TEST_F(SdchManagerTest, CanStillSetExactMatchDictionary) { ...@@ -419,46 +419,6 @@ TEST_F(SdchManagerTest, CanStillSetExactMatchDictionary) {
GURL("http://" + dictionary_domain))); GURL("http://" + dictionary_domain)));
} }
TEST_F(SdchManagerTest, PathMatch) {
bool (*PathMatch)(const std::string& path, const std::string& restriction) =
SdchManager::Dictionary::PathMatch;
// Perfect match is supported.
EXPECT_TRUE(PathMatch("/search", "/search"));
EXPECT_TRUE(PathMatch("/search/", "/search/"));
// Prefix only works if last character of restriction is a slash, or first
// character in path after a match is a slash. Validate each case separately.
// Rely on the slash in the path (not at the end of the restriction).
EXPECT_TRUE(PathMatch("/search/something", "/search"));
EXPECT_TRUE(PathMatch("/search/s", "/search"));
EXPECT_TRUE(PathMatch("/search/other", "/search"));
EXPECT_TRUE(PathMatch("/search/something", "/search"));
// Rely on the slash at the end of the restriction.
EXPECT_TRUE(PathMatch("/search/something", "/search/"));
EXPECT_TRUE(PathMatch("/search/s", "/search/"));
EXPECT_TRUE(PathMatch("/search/other", "/search/"));
EXPECT_TRUE(PathMatch("/search/something", "/search/"));
// Make sure less that sufficient prefix match is false.
EXPECT_FALSE(PathMatch("/sear", "/search"));
EXPECT_FALSE(PathMatch("/", "/search"));
EXPECT_FALSE(PathMatch(std::string(), "/search"));
// Add examples with several levels of direcories in the restriction.
EXPECT_FALSE(PathMatch("/search/something", "search/s"));
EXPECT_FALSE(PathMatch("/search/", "/search/s"));
// Make sure adding characters to path will also fail.
EXPECT_FALSE(PathMatch("/searching", "/search/"));
EXPECT_FALSE(PathMatch("/searching", "/search"));
// Make sure we're case sensitive.
EXPECT_FALSE(PathMatch("/ABC", "/abc"));
EXPECT_FALSE(PathMatch("/abc", "/ABC"));
}
// The following are only applicable while we have a latency test in the code, // The following are only applicable while we have a latency test in the code,
// and can be removed when that functionality is stripped. // and can be removed when that functionality is stripped.
TEST_F(SdchManagerTest, LatencyTestControls) { TEST_F(SdchManagerTest, LatencyTestControls) {
...@@ -636,9 +596,8 @@ TEST_F(SdchManagerTest, ExpirationCheckedProperly) { ...@@ -636,9 +596,8 @@ TEST_F(SdchManagerTest, ExpirationCheckedProperly) {
target_gurl, server_hash, &problem_code).Pass()); target_gurl, server_hash, &problem_code).Pass());
ASSERT_TRUE(hash_set); ASSERT_TRUE(hash_set);
ASSERT_EQ(SDCH_OK, problem_code); ASSERT_EQ(SDCH_OK, problem_code);
const_cast<SdchManager::Dictionary*>( const_cast<SdchDictionary*>(hash_set->GetDictionary(server_hash))
hash_set->GetDictionary(server_hash))->SetClockForTesting( ->SetClockForTesting(clock.Pass());
clock.Pass());
// Make sure it's not visible for advertisement, but is visible // Make sure it's not visible for advertisement, but is visible
// if looked up by hash. // if looked up by hash.
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "net/base/net_export.h" #include "net/base/net_export.h"
#include "net/base/sdch_dictionary.h"
#include "net/base/sdch_manager.h" #include "net/base/sdch_manager.h"
#include "net/filter/filter.h" #include "net/filter/filter.h"
...@@ -95,7 +96,7 @@ class NET_EXPORT_PRIVATE SdchFilter : public Filter { ...@@ -95,7 +96,7 @@ class NET_EXPORT_PRIVATE SdchFilter : public Filter {
// Validity of this pointer is guaranteed by either the FilterContext holding // Validity of this pointer is guaranteed by either the FilterContext holding
// a containing SdchManager::DictionarySet, or this object holding a // a containing SdchManager::DictionarySet, or this object holding a
// container in |unexpected_dictionary_handle_| below. // container in |unexpected_dictionary_handle_| below.
const SdchManager::Dictionary *dictionary_; const SdchDictionary* dictionary_;
// We keep a copy of the URLRequestContext for use in the destructor, (at // We keep a copy of the URLRequestContext for use in the destructor, (at
// which point GetURLRequestContext() will likely return null because of // which point GetURLRequestContext() will likely return null because of
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#include "base/test/histogram_tester.h" #include "base/test/histogram_tester.h"
#include "base/test/simple_test_clock.h" #include "base/test/simple_test_clock.h"
#include "net/base/io_buffer.h" #include "net/base/io_buffer.h"
#include "net/base/sdch_dictionary.h"
#include "net/base/sdch_manager.h"
#include "net/base/sdch_observer.h" #include "net/base/sdch_observer.h"
#include "net/filter/mock_filter_context.h" #include "net/filter/mock_filter_context.h"
#include "net/filter/sdch_filter.h" #include "net/filter/sdch_filter.h"
...@@ -1220,9 +1222,8 @@ TEST_F(SdchFilterTest, UnexpectedDictionary) { ...@@ -1220,9 +1222,8 @@ TEST_F(SdchFilterTest, UnexpectedDictionary) {
ASSERT_TRUE(hash_set); ASSERT_TRUE(hash_set);
ASSERT_EQ(SDCH_OK, problem_code); ASSERT_EQ(SDCH_OK, problem_code);
const_cast<SdchManager::Dictionary*>( const_cast<SdchDictionary*>(hash_set->GetDictionary(server_hash))
hash_set->GetDictionary(server_hash))->SetClockForTesting( ->SetClockForTesting(clock.Pass());
clock.Pass());
// Encode output with the second dictionary. // Encode output with the second dictionary.
std::string sdch_compressed(NewSdchCompressedData(expired_dictionary)); std::string sdch_compressed(NewSdchCompressedData(expired_dictionary));
......
...@@ -271,6 +271,8 @@ ...@@ -271,6 +271,8 @@
'base/proxy_delegate.h', 'base/proxy_delegate.h',
'base/request_priority.cc', 'base/request_priority.cc',
'base/request_priority.h', 'base/request_priority.h',
'base/sdch_dictionary.cc',
'base/sdch_dictionary.h',
'base/sdch_manager.cc', 'base/sdch_manager.cc',
'base/sdch_manager.h', 'base/sdch_manager.h',
'base/sdch_net_log_params.cc', 'base/sdch_net_log_params.cc',
...@@ -1287,6 +1289,7 @@ ...@@ -1287,6 +1289,7 @@
'base/prioritized_dispatcher_unittest.cc', 'base/prioritized_dispatcher_unittest.cc',
'base/priority_queue_unittest.cc', 'base/priority_queue_unittest.cc',
'base/registry_controlled_domains/registry_controlled_domain_unittest.cc', 'base/registry_controlled_domains/registry_controlled_domain_unittest.cc',
'base/sdch_dictionary_unittest.cc',
'base/sdch_manager_unittest.cc', 'base/sdch_manager_unittest.cc',
'base/static_cookie_policy_unittest.cc', 'base/static_cookie_policy_unittest.cc',
'base/test_completion_callback_unittest.cc', 'base/test_completion_callback_unittest.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment