blob: abf47fd4da2dc7cdebee44909113b42fbe776f48 [file] [log] [blame]
// Copyright 2014 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 <limits.h>
#include <string>
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "net/base/sdch_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
//------------------------------------------------------------------------------
// Workaround for http://crbug.com/418975; remove when fixed.
#if !defined(OS_IOS)
//------------------------------------------------------------------------------
// Provide sample data and compression results with a sample VCDIFF dictionary.
// Note an SDCH dictionary has extra meta-data before the VCDIFF dictionary.
static const char kTestVcdiffDictionary[] = "DictionaryFor"
"SdchCompression1SdchCompression2SdchCompression3SdchCompression\n";
//------------------------------------------------------------------------------
class SdchManagerTest : public testing::Test {
protected:
SdchManagerTest()
: sdch_manager_(new SdchManager),
default_support_(false),
default_https_support_(false) {
default_support_ = sdch_manager_->sdch_enabled();
default_https_support_ = sdch_manager_->secure_scheme_supported();
}
SdchManager* sdch_manager() { return sdch_manager_.get(); }
// Reset globals back to default state.
virtual void TearDown() {
SdchManager::EnableSdchSupport(default_support_);
SdchManager::EnableSecureSchemeSupport(default_https_support_);
}
// Attempt to add a dictionary to the manager and probe for success or
// failure.
bool AddSdchDictionary(const std::string& dictionary_text,
const GURL& gurl) {
std::string list;
sdch_manager_->GetAvailDictionaryList(gurl, &list);
sdch_manager_->AddSdchDictionary(dictionary_text, gurl);
std::string list2;
sdch_manager_->GetAvailDictionaryList(gurl, &list2);
// The list of hashes should change iff the addition succeeds.
return (list != list2);
}
private:
scoped_ptr<SdchManager> sdch_manager_;
bool default_support_;
bool default_https_support_;
};
static std::string NewSdchDictionary(const std::string& domain) {
std::string dictionary;
if (!domain.empty()) {
dictionary.append("Domain: ");
dictionary.append(domain);
dictionary.append("\n");
}
dictionary.append("\n");
dictionary.append(kTestVcdiffDictionary, sizeof(kTestVcdiffDictionary) - 1);
return dictionary;
}
TEST_F(SdchManagerTest, DomainSupported) {
GURL google_url("http://www.google.com");
SdchManager::EnableSdchSupport(false);
EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(google_url));
SdchManager::EnableSdchSupport(true);
EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(google_url));
}
TEST_F(SdchManagerTest, DomainBlacklisting) {
GURL test_url("http://www.test.com");
GURL google_url("http://www.google.com");
sdch_manager()->BlacklistDomain(test_url, SdchManager::MIN_PROBLEM_CODE);
EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(test_url));
EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(google_url));
sdch_manager()->BlacklistDomain(google_url, SdchManager::MIN_PROBLEM_CODE);
EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(google_url));
}
TEST_F(SdchManagerTest, DomainBlacklistingCaseSensitivity) {
GURL test_url("http://www.TesT.com");
GURL test2_url("http://www.tEst.com");
EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(test_url));
EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(test2_url));
sdch_manager()->BlacklistDomain(test_url, SdchManager::MIN_PROBLEM_CODE);
EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(test2_url));
}
TEST_F(SdchManagerTest, BlacklistingReset) {
GURL gurl("http://mytest.DoMain.com");
std::string domain(gurl.host());
sdch_manager()->ClearBlacklistings();
EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 0);
EXPECT_EQ(sdch_manager()->BlacklistDomainExponential(domain), 0);
EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(gurl));
}
TEST_F(SdchManagerTest, BlacklistingSingleBlacklist) {
GURL gurl("http://mytest.DoMain.com");
std::string domain(gurl.host());
sdch_manager()->ClearBlacklistings();
sdch_manager()->BlacklistDomain(gurl, SdchManager::MIN_PROBLEM_CODE);
EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 1);
EXPECT_EQ(sdch_manager()->BlacklistDomainExponential(domain), 1);
// Check that any domain lookup reduces the blacklist counter.
EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(gurl));
EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 0);
EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(gurl));
}
TEST_F(SdchManagerTest, BlacklistingExponential) {
GURL gurl("http://mytest.DoMain.com");
std::string domain(gurl.host());
sdch_manager()->ClearBlacklistings();
int exponential = 1;
for (int i = 1; i < 100; ++i) {
sdch_manager()->BlacklistDomain(gurl, SdchManager::MIN_PROBLEM_CODE);
EXPECT_EQ(sdch_manager()->BlacklistDomainExponential(domain), exponential);
EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), exponential);
EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(gurl));
EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), exponential - 1);
// Simulate a large number of domain checks (which eventually remove the
// blacklisting).
sdch_manager()->ClearDomainBlacklisting(domain);
EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 0);
EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(gurl));
// Predict what exponential backoff will be.
exponential = 1 + 2 * exponential;
if (exponential < 0)
exponential = INT_MAX; // We don't wrap.
}
}
TEST_F(SdchManagerTest, CanSetExactMatchDictionary) {
std::string dictionary_domain("x.y.z.google.com");
std::string dictionary_text(NewSdchDictionary(dictionary_domain));
// Perfect match should work.
EXPECT_TRUE(AddSdchDictionary(dictionary_text,
GURL("http://" + dictionary_domain)));
}
TEST_F(SdchManagerTest, CanAdvertiseDictionaryOverHTTP) {
std::string dictionary_domain("x.y.z.google.com");
std::string dictionary_text(NewSdchDictionary(dictionary_domain));
EXPECT_TRUE(AddSdchDictionary(dictionary_text,
GURL("http://" + dictionary_domain)));
std::string dictionary_list;
// HTTP target URL can advertise dictionary.
sdch_manager()->GetAvailDictionaryList(
GURL("http://" + dictionary_domain + "/test"),
&dictionary_list);
EXPECT_FALSE(dictionary_list.empty());
}
TEST_F(SdchManagerTest, CanNotAdvertiseDictionaryOverHTTPS) {
std::string dictionary_domain("x.y.z.google.com");
std::string dictionary_text(NewSdchDictionary(dictionary_domain));
EXPECT_TRUE(AddSdchDictionary(dictionary_text,
GURL("http://" + dictionary_domain)));
std::string dictionary_list;
// HTTPS target URL should NOT advertise dictionary.
sdch_manager()->GetAvailDictionaryList(
GURL("https://" + dictionary_domain + "/test"),
&dictionary_list);
EXPECT_TRUE(dictionary_list.empty());
}
TEST_F(SdchManagerTest, CanUseHTTPSDictionaryOverHTTPSIfEnabled) {
std::string dictionary_domain("x.y.z.google.com");
std::string dictionary_text(NewSdchDictionary(dictionary_domain));
SdchManager::EnableSecureSchemeSupport(false);
EXPECT_FALSE(AddSdchDictionary(dictionary_text,
GURL("https://" + dictionary_domain)));
SdchManager::EnableSecureSchemeSupport(true);
EXPECT_TRUE(AddSdchDictionary(dictionary_text,
GURL("https://" + dictionary_domain)));
GURL target_url("https://" + dictionary_domain + "/test");
std::string dictionary_list;
// HTTPS target URL should advertise dictionary if secure scheme support is
// enabled.
sdch_manager()->GetAvailDictionaryList(target_url, &dictionary_list);
EXPECT_FALSE(dictionary_list.empty());
// Dictionary should be available.
scoped_refptr<SdchManager::Dictionary> dictionary;
std::string client_hash;
std::string server_hash;
sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash);
sdch_manager()->GetVcdiffDictionary(server_hash, target_url, &dictionary);
EXPECT_TRUE(dictionary.get() != NULL);
}
TEST_F(SdchManagerTest, CanNotUseHTTPDictionaryOverHTTPS) {
std::string dictionary_domain("x.y.z.google.com");
std::string dictionary_text(NewSdchDictionary(dictionary_domain));
EXPECT_TRUE(AddSdchDictionary(dictionary_text,
GURL("http://" + dictionary_domain)));
GURL target_url("https://" + dictionary_domain + "/test");
std::string dictionary_list;
// HTTPS target URL should not advertise dictionary acquired over HTTP even if
// secure scheme support is enabled.
SdchManager::EnableSecureSchemeSupport(true);
sdch_manager()->GetAvailDictionaryList(target_url, &dictionary_list);
EXPECT_TRUE(dictionary_list.empty());
scoped_refptr<SdchManager::Dictionary> dictionary;
std::string client_hash;
std::string server_hash;
sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash);
sdch_manager()->GetVcdiffDictionary(server_hash, target_url, &dictionary);
EXPECT_TRUE(dictionary.get() == NULL);
}
TEST_F(SdchManagerTest, CanNotUseHTTPSDictionaryOverHTTP) {
std::string dictionary_domain("x.y.z.google.com");
std::string dictionary_text(NewSdchDictionary(dictionary_domain));
SdchManager::EnableSecureSchemeSupport(true);
EXPECT_TRUE(AddSdchDictionary(dictionary_text,
GURL("https://" + dictionary_domain)));
GURL target_url("http://" + dictionary_domain + "/test");
std::string dictionary_list;
// HTTP target URL should not advertise dictionary acquired over HTTPS even if
// secure scheme support is enabled.
sdch_manager()->GetAvailDictionaryList(target_url, &dictionary_list);
EXPECT_TRUE(dictionary_list.empty());
scoped_refptr<SdchManager::Dictionary> dictionary;
std::string client_hash;
std::string server_hash;
sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash);
sdch_manager()->GetVcdiffDictionary(server_hash, target_url, &dictionary);
EXPECT_TRUE(dictionary.get() == NULL);
}
TEST_F(SdchManagerTest, FailToSetDomainMismatchDictionary) {
std::string dictionary_domain("x.y.z.google.com");
std::string dictionary_text(NewSdchDictionary(dictionary_domain));
// Fail the "domain match" requirement.
EXPECT_FALSE(AddSdchDictionary(dictionary_text,
GURL("http://y.z.google.com")));
}
TEST_F(SdchManagerTest, FailToSetDotHostPrefixDomainDictionary) {
std::string dictionary_domain("x.y.z.google.com");
std::string dictionary_text(NewSdchDictionary(dictionary_domain));
// Fail the HD with D being the domain and H having a dot requirement.
EXPECT_FALSE(AddSdchDictionary(dictionary_text,
GURL("http://w.x.y.z.google.com")));
}
TEST_F(SdchManagerTest, FailToSetDotHostPrefixDomainDictionaryTrailingDot) {
std::string dictionary_domain("x.y.z.google.com");
std::string dictionary_text(NewSdchDictionary(dictionary_domain));
// Fail the HD with D being the domain and H having a dot requirement.
EXPECT_FALSE(AddSdchDictionary(dictionary_text,
GURL("http://w.x.y.z.google.com.")));
}
TEST_F(SdchManagerTest, FailToSetRepeatPrefixWithDotDictionary) {
// Make sure that a prefix that matches the domain postfix won't confuse
// the validation checks.
std::string dictionary_domain("www.google.com");
std::string dictionary_text(NewSdchDictionary(dictionary_domain));
// Fail the HD with D being the domain and H having a dot requirement.
EXPECT_FALSE(AddSdchDictionary(dictionary_text,
GURL("http://www.google.com.www.google.com")));
}
TEST_F(SdchManagerTest, CanSetLeadingDotDomainDictionary) {
// Make sure that a prefix that matches the domain postfix won't confuse
// the validation checks.
std::string dictionary_domain(".google.com");
std::string dictionary_text(NewSdchDictionary(dictionary_domain));
// Verify that a leading dot in the domain is acceptable, as long as the host
// name does not contain any dots preceding the matched domain name.
EXPECT_TRUE(AddSdchDictionary(dictionary_text, GURL("http://www.google.com")));
}
TEST_F(SdchManagerTest,
CanSetLeadingDotDomainDictionaryFromURLWithTrailingDot) {
// Make sure that a prefix that matches the domain postfix won't confuse
// the validation checks.
std::string dictionary_domain(".google.com");
std::string dictionary_text(NewSdchDictionary(dictionary_domain));
// Verify that a leading dot in the domain is acceptable, as long as the host
// name does not contain any dots preceding the matched domain name.
EXPECT_TRUE(AddSdchDictionary(dictionary_text,
GURL("http://www.google.com.")));
}
TEST_F(SdchManagerTest, CannotSetLeadingDotDomainDictionary) {
// Make sure that a prefix that matches the domain postfix won't confuse
// the validation checks.
std::string dictionary_domain(".google.com");
std::string dictionary_text(NewSdchDictionary(dictionary_domain));
// Verify that a leading dot in the domain does not affect the name containing
// dots failure.
EXPECT_FALSE(AddSdchDictionary(dictionary_text,
GURL("http://www.subdomain.google.com")));
}
TEST_F(SdchManagerTest, CannotSetLeadingDotDomainDictionaryTrailingDot) {
// Make sure that a prefix that matches the domain postfix won't confuse
// the validation checks.
std::string dictionary_domain(".google.com");
std::string dictionary_text(NewSdchDictionary(dictionary_domain));
// Verify that a trailing period in the URL doesn't affect the check.
EXPECT_FALSE(AddSdchDictionary(dictionary_text,
GURL("http://www.subdomain.google.com.")));
}
// Make sure the order of the tests is not helping us or confusing things.
// See test CanSetExactMatchDictionary above for first try.
TEST_F(SdchManagerTest, CanStillSetExactMatchDictionary) {
std::string dictionary_domain("x.y.z.google.com");
std::string dictionary_text(NewSdchDictionary(dictionary_domain));
// Perfect match should *STILL* work.
EXPECT_TRUE(AddSdchDictionary(dictionary_text,
GURL("http://" + dictionary_domain)));
}
// Make sure the DOS protection precludes the addition of too many dictionaries.
TEST_F(SdchManagerTest, TooManyDictionaries) {
std::string dictionary_domain(".google.com");
std::string dictionary_text(NewSdchDictionary(dictionary_domain));
for (size_t count = 0; count < SdchManager::kMaxDictionaryCount; ++count) {
EXPECT_TRUE(AddSdchDictionary(dictionary_text,
GURL("http://www.google.com")));
dictionary_text += " "; // Create dictionary with different SHA signature.
}
EXPECT_FALSE(
AddSdchDictionary(dictionary_text, GURL("http://www.google.com")));
}
TEST_F(SdchManagerTest, DictionaryNotTooLarge) {
std::string dictionary_domain(".google.com");
std::string dictionary_text(NewSdchDictionary(dictionary_domain));
dictionary_text.append(
SdchManager::kMaxDictionarySize - dictionary_text.size(), ' ');
EXPECT_TRUE(AddSdchDictionary(dictionary_text,
GURL("http://" + dictionary_domain)));
}
TEST_F(SdchManagerTest, DictionaryTooLarge) {
std::string dictionary_domain(".google.com");
std::string dictionary_text(NewSdchDictionary(dictionary_domain));
dictionary_text.append(
SdchManager::kMaxDictionarySize + 1 - dictionary_text.size(), ' ');
EXPECT_FALSE(AddSdchDictionary(dictionary_text,
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,
// and can be removed when that functionality is stripped.
TEST_F(SdchManagerTest, LatencyTestControls) {
GURL url("http://www.google.com");
GURL url2("http://www.google2.com");
// First make sure we default to false.
EXPECT_FALSE(sdch_manager()->AllowLatencyExperiment(url));
EXPECT_FALSE(sdch_manager()->AllowLatencyExperiment(url2));
// That we can set each to true.
sdch_manager()->SetAllowLatencyExperiment(url, true);
EXPECT_TRUE(sdch_manager()->AllowLatencyExperiment(url));
EXPECT_FALSE(sdch_manager()->AllowLatencyExperiment(url2));
sdch_manager()->SetAllowLatencyExperiment(url2, true);
EXPECT_TRUE(sdch_manager()->AllowLatencyExperiment(url));
EXPECT_TRUE(sdch_manager()->AllowLatencyExperiment(url2));
// And can reset them to false.
sdch_manager()->SetAllowLatencyExperiment(url, false);
EXPECT_FALSE(sdch_manager()->AllowLatencyExperiment(url));
EXPECT_TRUE(sdch_manager()->AllowLatencyExperiment(url2));
sdch_manager()->SetAllowLatencyExperiment(url2, false);
EXPECT_FALSE(sdch_manager()->AllowLatencyExperiment(url));
EXPECT_FALSE(sdch_manager()->AllowLatencyExperiment(url2));
}
TEST_F(SdchManagerTest, CanUseMultipleManagers) {
SdchManager second_manager;
std::string dictionary_domain_1("x.y.z.google.com");
std::string dictionary_domain_2("x.y.z.chromium.org");
std::string dictionary_text_1(NewSdchDictionary(dictionary_domain_1));
std::string dictionary_text_2(NewSdchDictionary(dictionary_domain_2));
std::string tmp_hash;
std::string server_hash_1;
std::string server_hash_2;
SdchManager::GenerateHash(dictionary_text_1, &tmp_hash, &server_hash_1);
SdchManager::GenerateHash(dictionary_text_2, &tmp_hash, &server_hash_2);
// Confirm that if you add directories to one manager, you
// can't get them from the other.
EXPECT_TRUE(AddSdchDictionary(dictionary_text_1,
GURL("http://" + dictionary_domain_1)));
scoped_refptr<SdchManager::Dictionary> dictionary;
sdch_manager()->GetVcdiffDictionary(
server_hash_1,
GURL("http://" + dictionary_domain_1 + "/random_url"),
&dictionary);
EXPECT_TRUE(dictionary.get());
second_manager.AddSdchDictionary(
dictionary_text_2, GURL("http://" + dictionary_domain_2));
second_manager.GetVcdiffDictionary(
server_hash_2,
GURL("http://" + dictionary_domain_2 + "/random_url"),
&dictionary);
EXPECT_TRUE(dictionary.get());
sdch_manager()->GetVcdiffDictionary(
server_hash_2,
GURL("http://" + dictionary_domain_2 + "/random_url"),
&dictionary);
EXPECT_FALSE(dictionary.get());
second_manager.GetVcdiffDictionary(
server_hash_1,
GURL("http://" + dictionary_domain_1 + "/random_url"),
&dictionary);
EXPECT_FALSE(dictionary.get());
}
TEST_F(SdchManagerTest, HttpsCorrectlySupported) {
GURL url("http://www.google.com");
GURL secure_url("https://www.google.com");
#if !defined(OS_IOS)
// Workaround for http://crbug.com/418975; remove when fixed.
bool expect_https_support = true;
#else
bool expect_https_support = false;
#endif
EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(url));
EXPECT_EQ(expect_https_support,
sdch_manager()->IsInSupportedDomain(secure_url));
SdchManager::EnableSecureSchemeSupport(!expect_https_support);
EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(url));
EXPECT_NE(expect_https_support,
sdch_manager()->IsInSupportedDomain(secure_url));
}
TEST_F(SdchManagerTest, ClearDictionaryData) {
std::string dictionary_domain("x.y.z.google.com");
GURL blacklist_url("http://bad.chromium.org");
std::string dictionary_text(NewSdchDictionary(dictionary_domain));
std::string tmp_hash;
std::string server_hash;
SdchManager::GenerateHash(dictionary_text, &tmp_hash, &server_hash);
EXPECT_TRUE(AddSdchDictionary(dictionary_text,
GURL("http://" + dictionary_domain)));
scoped_refptr<SdchManager::Dictionary> dictionary;
sdch_manager()->GetVcdiffDictionary(
server_hash,
GURL("http://" + dictionary_domain + "/random_url"),
&dictionary);
EXPECT_TRUE(dictionary.get());
sdch_manager()->BlacklistDomain(GURL(blacklist_url),
SdchManager::MIN_PROBLEM_CODE);
EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(blacklist_url));
sdch_manager()->ClearData();
dictionary = NULL;
sdch_manager()->GetVcdiffDictionary(
server_hash,
GURL("http://" + dictionary_domain + "/random_url"),
&dictionary);
EXPECT_FALSE(dictionary.get());
EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(blacklist_url));
}
#else
TEST(SdchManagerTest, SdchOffByDefault) {
GURL google_url("http://www.google.com");
SdchManager* sdch_manager(new SdchManager);
EXPECT_FALSE(sdch_manager->IsInSupportedDomain(google_url));
SdchManager::EnableSdchSupport(true);
EXPECT_TRUE(sdch_manager->IsInSupportedDomain(google_url));
}
#endif // !defined(OS_IOS)
} // namespace net