Home | History | Annotate | Download | only in base
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <limits.h>
      6 
      7 #include <string>
      8 
      9 #include "base/logging.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "net/base/sdch_manager.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 
     14 namespace net {
     15 
     16 //------------------------------------------------------------------------------
     17 // Provide sample data and compression results with a sample VCDIFF dictionary.
     18 // Note an SDCH dictionary has extra meta-data before the VCDIFF dictionary.
     19 static const char kTestVcdiffDictionary[] = "DictionaryFor"
     20     "SdchCompression1SdchCompression2SdchCompression3SdchCompression\n";
     21 
     22 //------------------------------------------------------------------------------
     23 
     24 class SdchManagerTest : public testing::Test {
     25  protected:
     26   SdchManagerTest()
     27     : sdch_manager_(new SdchManager) {
     28   }
     29 
     30   SdchManager* sdch_manager() { return sdch_manager_.get(); }
     31 
     32   // Reset globals back to default state.
     33   virtual void TearDown() {
     34     SdchManager::EnableSdchSupport(true);
     35     SdchManager::EnableSecureSchemeSupport(false);
     36   }
     37 
     38  private:
     39   scoped_ptr<SdchManager> sdch_manager_;
     40 };
     41 
     42 //------------------------------------------------------------------------------
     43 static std::string NewSdchDictionary(const std::string& domain) {
     44   std::string dictionary;
     45   if (!domain.empty()) {
     46     dictionary.append("Domain: ");
     47     dictionary.append(domain);
     48     dictionary.append("\n");
     49   }
     50   dictionary.append("\n");
     51   dictionary.append(kTestVcdiffDictionary, sizeof(kTestVcdiffDictionary) - 1);
     52   return dictionary;
     53 }
     54 
     55 TEST_F(SdchManagerTest, DomainSupported) {
     56   GURL google_url("http://www.google.com");
     57 
     58   SdchManager::EnableSdchSupport(false);
     59   EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(google_url));
     60   SdchManager::EnableSdchSupport(true);
     61   EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(google_url));
     62 }
     63 
     64 TEST_F(SdchManagerTest, DomainBlacklisting) {
     65   GURL test_url("http://www.test.com");
     66   GURL google_url("http://www.google.com");
     67 
     68   sdch_manager()->BlacklistDomain(test_url);
     69   EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(test_url));
     70   EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(google_url));
     71 
     72   sdch_manager()->BlacklistDomain(google_url);
     73   EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(google_url));
     74 }
     75 
     76 TEST_F(SdchManagerTest, DomainBlacklistingCaseSensitivity) {
     77   GURL test_url("http://www.TesT.com");
     78   GURL test2_url("http://www.tEst.com");
     79 
     80   EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(test_url));
     81   EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(test2_url));
     82   sdch_manager()->BlacklistDomain(test_url);
     83   EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(test2_url));
     84 }
     85 
     86 TEST_F(SdchManagerTest, BlacklistingReset) {
     87   GURL gurl("http://mytest.DoMain.com");
     88   std::string domain(gurl.host());
     89 
     90   sdch_manager()->ClearBlacklistings();
     91   EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 0);
     92   EXPECT_EQ(sdch_manager()->BlacklistDomainExponential(domain), 0);
     93   EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(gurl));
     94 }
     95 
     96 TEST_F(SdchManagerTest, BlacklistingSingleBlacklist) {
     97   GURL gurl("http://mytest.DoMain.com");
     98   std::string domain(gurl.host());
     99   sdch_manager()->ClearBlacklistings();
    100 
    101   sdch_manager()->BlacklistDomain(gurl);
    102   EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 1);
    103   EXPECT_EQ(sdch_manager()->BlacklistDomainExponential(domain), 1);
    104 
    105   // Check that any domain lookup reduces the blacklist counter.
    106   EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(gurl));
    107   EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 0);
    108   EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(gurl));
    109 }
    110 
    111 TEST_F(SdchManagerTest, BlacklistingExponential) {
    112   GURL gurl("http://mytest.DoMain.com");
    113   std::string domain(gurl.host());
    114   sdch_manager()->ClearBlacklistings();
    115 
    116   int exponential = 1;
    117   for (int i = 1; i < 100; ++i) {
    118     sdch_manager()->BlacklistDomain(gurl);
    119     EXPECT_EQ(sdch_manager()->BlacklistDomainExponential(domain), exponential);
    120 
    121     EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), exponential);
    122     EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(gurl));
    123     EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), exponential - 1);
    124 
    125     // Simulate a large number of domain checks (which eventually remove the
    126     // blacklisting).
    127     sdch_manager()->ClearDomainBlacklisting(domain);
    128     EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 0);
    129     EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(gurl));
    130 
    131     // Predict what exponential backoff will be.
    132     exponential = 1 + 2 * exponential;
    133     if (exponential < 0)
    134       exponential = INT_MAX;  // We don't wrap.
    135   }
    136 }
    137 
    138 TEST_F(SdchManagerTest, CanSetExactMatchDictionary) {
    139   std::string dictionary_domain("x.y.z.google.com");
    140   std::string dictionary_text(NewSdchDictionary(dictionary_domain));
    141 
    142   // Perfect match should work.
    143   EXPECT_TRUE(sdch_manager()->AddSdchDictionary(dictionary_text,
    144               GURL("http://" + dictionary_domain)));
    145 }
    146 
    147 TEST_F(SdchManagerTest, CanAdvertiseDictionaryOverHTTP) {
    148   std::string dictionary_domain("x.y.z.google.com");
    149   std::string dictionary_text(NewSdchDictionary(dictionary_domain));
    150 
    151   EXPECT_TRUE(sdch_manager()->AddSdchDictionary(dictionary_text,
    152               GURL("http://" + dictionary_domain)));
    153 
    154   std::string dictionary_list;
    155   // HTTP target URL can advertise dictionary.
    156   sdch_manager()->GetAvailDictionaryList(
    157       GURL("http://" + dictionary_domain + "/test"),
    158       &dictionary_list);
    159   EXPECT_FALSE(dictionary_list.empty());
    160 }
    161 
    162 TEST_F(SdchManagerTest, CanNotAdvertiseDictionaryOverHTTPS) {
    163   std::string dictionary_domain("x.y.z.google.com");
    164   std::string dictionary_text(NewSdchDictionary(dictionary_domain));
    165 
    166   EXPECT_TRUE(sdch_manager()->AddSdchDictionary(dictionary_text,
    167               GURL("http://" + dictionary_domain)));
    168 
    169   std::string dictionary_list;
    170   // HTTPS target URL should NOT advertise dictionary.
    171   sdch_manager()->GetAvailDictionaryList(
    172       GURL("https://" + dictionary_domain + "/test"),
    173       &dictionary_list);
    174   EXPECT_TRUE(dictionary_list.empty());
    175 }
    176 
    177 TEST_F(SdchManagerTest, CanUseHTTPSDictionaryOverHTTPSIfEnabled) {
    178   std::string dictionary_domain("x.y.z.google.com");
    179   std::string dictionary_text(NewSdchDictionary(dictionary_domain));
    180 
    181   EXPECT_FALSE(sdch_manager()->AddSdchDictionary(
    182       dictionary_text, GURL("https://" + dictionary_domain)));
    183   SdchManager::EnableSecureSchemeSupport(true);
    184   EXPECT_TRUE(sdch_manager()->AddSdchDictionary(
    185       dictionary_text, GURL("https://" + dictionary_domain)));
    186 
    187   GURL target_url("https://" + dictionary_domain + "/test");
    188   std::string dictionary_list;
    189   // HTTPS target URL should advertise dictionary if secure scheme support is
    190   // enabled.
    191   sdch_manager()->GetAvailDictionaryList(target_url, &dictionary_list);
    192   EXPECT_FALSE(dictionary_list.empty());
    193 
    194   // Dictionary should be available.
    195   scoped_refptr<SdchManager::Dictionary> dictionary;
    196   std::string client_hash;
    197   std::string server_hash;
    198   sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash);
    199   sdch_manager()->GetVcdiffDictionary(server_hash, target_url, &dictionary);
    200   EXPECT_TRUE(dictionary != NULL);
    201 }
    202 
    203 TEST_F(SdchManagerTest, CanNotUseHTTPDictionaryOverHTTPS) {
    204   std::string dictionary_domain("x.y.z.google.com");
    205   std::string dictionary_text(NewSdchDictionary(dictionary_domain));
    206 
    207   EXPECT_TRUE(sdch_manager()->AddSdchDictionary(dictionary_text,
    208               GURL("http://" + dictionary_domain)));
    209 
    210   GURL target_url("https://" + dictionary_domain + "/test");
    211   std::string dictionary_list;
    212   // HTTPS target URL should not advertise dictionary acquired over HTTP even if
    213   // secure scheme support is enabled.
    214   SdchManager::EnableSecureSchemeSupport(true);
    215   sdch_manager()->GetAvailDictionaryList(target_url, &dictionary_list);
    216   EXPECT_TRUE(dictionary_list.empty());
    217 
    218   scoped_refptr<SdchManager::Dictionary> dictionary;
    219   std::string client_hash;
    220   std::string server_hash;
    221   sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash);
    222   sdch_manager()->GetVcdiffDictionary(server_hash, target_url, &dictionary);
    223   EXPECT_TRUE(dictionary == NULL);
    224 }
    225 
    226 TEST_F(SdchManagerTest, FailToSetDomainMismatchDictionary) {
    227   std::string dictionary_domain("x.y.z.google.com");
    228   std::string dictionary_text(NewSdchDictionary(dictionary_domain));
    229 
    230   // Fail the "domain match" requirement.
    231   EXPECT_FALSE(sdch_manager()->AddSdchDictionary(dictionary_text,
    232                GURL("http://y.z.google.com")));
    233 }
    234 
    235 TEST_F(SdchManagerTest, FailToSetDotHostPrefixDomainDictionary) {
    236   std::string dictionary_domain("x.y.z.google.com");
    237   std::string dictionary_text(NewSdchDictionary(dictionary_domain));
    238 
    239   // Fail the HD with D being the domain and H having a dot requirement.
    240   EXPECT_FALSE(sdch_manager()->AddSdchDictionary(dictionary_text,
    241                GURL("http://w.x.y.z.google.com")));
    242 }
    243 
    244 TEST_F(SdchManagerTest, FailToSetRepeatPrefixWithDotDictionary) {
    245   // Make sure that a prefix that matches the domain postfix won't confuse
    246   // the validation checks.
    247   std::string dictionary_domain("www.google.com");
    248   std::string dictionary_text(NewSdchDictionary(dictionary_domain));
    249 
    250   // Fail the HD with D being the domain and H having a dot requirement.
    251   EXPECT_FALSE(sdch_manager()->AddSdchDictionary(dictionary_text,
    252                GURL("http://www.google.com.www.google.com")));
    253 }
    254 
    255 TEST_F(SdchManagerTest, CanSetLeadingDotDomainDictionary) {
    256   // Make sure that a prefix that matches the domain postfix won't confuse
    257   // the validation checks.
    258   std::string dictionary_domain(".google.com");
    259   std::string dictionary_text(NewSdchDictionary(dictionary_domain));
    260 
    261   // Verify that a leading dot in the domain is acceptable, as long as the host
    262   // name does not contain any dots preceding the matched domain name.
    263   EXPECT_TRUE(sdch_manager()->AddSdchDictionary(dictionary_text,
    264                GURL("http://www.google.com")));
    265 }
    266 
    267 // Make sure the order of the tests is not helping us or confusing things.
    268 // See test CanSetExactMatchDictionary above for first try.
    269 TEST_F(SdchManagerTest, CanStillSetExactMatchDictionary) {
    270   std::string dictionary_domain("x.y.z.google.com");
    271   std::string dictionary_text(NewSdchDictionary(dictionary_domain));
    272 
    273   // Perfect match should *STILL* work.
    274   EXPECT_TRUE(sdch_manager()->AddSdchDictionary(dictionary_text,
    275               GURL("http://" + dictionary_domain)));
    276 }
    277 
    278 // Make sure the DOS protection precludes the addition of too many dictionaries.
    279 TEST_F(SdchManagerTest, TooManyDictionaries) {
    280   std::string dictionary_domain(".google.com");
    281   std::string dictionary_text(NewSdchDictionary(dictionary_domain));
    282 
    283   size_t count = 0;
    284   while (count <= SdchManager::kMaxDictionaryCount + 1) {
    285     if (!sdch_manager()->AddSdchDictionary(dictionary_text,
    286                                           GURL("http://www.google.com")))
    287       break;
    288 
    289     dictionary_text += " ";  // Create dictionary with different SHA signature.
    290     ++count;
    291   }
    292   EXPECT_EQ(SdchManager::kMaxDictionaryCount, count);
    293 }
    294 
    295 TEST_F(SdchManagerTest, DictionaryNotTooLarge) {
    296   std::string dictionary_domain(".google.com");
    297   std::string dictionary_text(NewSdchDictionary(dictionary_domain));
    298 
    299   dictionary_text.append(
    300       SdchManager::kMaxDictionarySize  - dictionary_text.size(), ' ');
    301   EXPECT_TRUE(sdch_manager()->AddSdchDictionary(dictionary_text,
    302               GURL("http://" + dictionary_domain)));
    303 }
    304 
    305 TEST_F(SdchManagerTest, DictionaryTooLarge) {
    306   std::string dictionary_domain(".google.com");
    307   std::string dictionary_text(NewSdchDictionary(dictionary_domain));
    308 
    309   dictionary_text.append(
    310       SdchManager::kMaxDictionarySize + 1 - dictionary_text.size(), ' ');
    311   EXPECT_FALSE(sdch_manager()->AddSdchDictionary(dictionary_text,
    312               GURL("http://" + dictionary_domain)));
    313 }
    314 
    315 TEST_F(SdchManagerTest, PathMatch) {
    316   bool (*PathMatch)(const std::string& path, const std::string& restriction) =
    317       SdchManager::Dictionary::PathMatch;
    318   // Perfect match is supported.
    319   EXPECT_TRUE(PathMatch("/search", "/search"));
    320   EXPECT_TRUE(PathMatch("/search/", "/search/"));
    321 
    322   // Prefix only works if last character of restriction is a slash, or first
    323   // character in path after a match is a slash.  Validate each case separately.
    324 
    325   // Rely on the slash in the path (not at the end of the restriction).
    326   EXPECT_TRUE(PathMatch("/search/something", "/search"));
    327   EXPECT_TRUE(PathMatch("/search/s", "/search"));
    328   EXPECT_TRUE(PathMatch("/search/other", "/search"));
    329   EXPECT_TRUE(PathMatch("/search/something", "/search"));
    330 
    331   // Rely on the slash at the end of the restriction.
    332   EXPECT_TRUE(PathMatch("/search/something", "/search/"));
    333   EXPECT_TRUE(PathMatch("/search/s", "/search/"));
    334   EXPECT_TRUE(PathMatch("/search/other", "/search/"));
    335   EXPECT_TRUE(PathMatch("/search/something", "/search/"));
    336 
    337   // Make sure less that sufficient prefix match is false.
    338   EXPECT_FALSE(PathMatch("/sear", "/search"));
    339   EXPECT_FALSE(PathMatch("/", "/search"));
    340   EXPECT_FALSE(PathMatch(std::string(), "/search"));
    341 
    342   // Add examples with several levels of direcories in the restriction.
    343   EXPECT_FALSE(PathMatch("/search/something", "search/s"));
    344   EXPECT_FALSE(PathMatch("/search/", "/search/s"));
    345 
    346   // Make sure adding characters to path will also fail.
    347   EXPECT_FALSE(PathMatch("/searching", "/search/"));
    348   EXPECT_FALSE(PathMatch("/searching", "/search"));
    349 
    350   // Make sure we're case sensitive.
    351   EXPECT_FALSE(PathMatch("/ABC", "/abc"));
    352   EXPECT_FALSE(PathMatch("/abc", "/ABC"));
    353 }
    354 
    355 // The following are only applicable while we have a latency test in the code,
    356 // and can be removed when that functionality is stripped.
    357 TEST_F(SdchManagerTest, LatencyTestControls) {
    358   GURL url("http://www.google.com");
    359   GURL url2("http://www.google2.com");
    360 
    361   // First make sure we default to false.
    362   EXPECT_FALSE(sdch_manager()->AllowLatencyExperiment(url));
    363   EXPECT_FALSE(sdch_manager()->AllowLatencyExperiment(url2));
    364 
    365   // That we can set each to true.
    366   sdch_manager()->SetAllowLatencyExperiment(url, true);
    367   EXPECT_TRUE(sdch_manager()->AllowLatencyExperiment(url));
    368   EXPECT_FALSE(sdch_manager()->AllowLatencyExperiment(url2));
    369 
    370   sdch_manager()->SetAllowLatencyExperiment(url2, true);
    371   EXPECT_TRUE(sdch_manager()->AllowLatencyExperiment(url));
    372   EXPECT_TRUE(sdch_manager()->AllowLatencyExperiment(url2));
    373 
    374   // And can reset them to false.
    375   sdch_manager()->SetAllowLatencyExperiment(url, false);
    376   EXPECT_FALSE(sdch_manager()->AllowLatencyExperiment(url));
    377   EXPECT_TRUE(sdch_manager()->AllowLatencyExperiment(url2));
    378 
    379   sdch_manager()->SetAllowLatencyExperiment(url2, false);
    380   EXPECT_FALSE(sdch_manager()->AllowLatencyExperiment(url));
    381   EXPECT_FALSE(sdch_manager()->AllowLatencyExperiment(url2));
    382 }
    383 
    384 TEST_F(SdchManagerTest, CanUseMultipleManagers) {
    385   SdchManager second_manager;
    386 
    387   std::string dictionary_domain_1("x.y.z.google.com");
    388   std::string dictionary_domain_2("x.y.z.chromium.org");
    389 
    390   std::string dictionary_text_1(NewSdchDictionary(dictionary_domain_1));
    391   std::string dictionary_text_2(NewSdchDictionary(dictionary_domain_2));
    392 
    393   std::string tmp_hash;
    394   std::string server_hash_1;
    395   std::string server_hash_2;
    396 
    397   SdchManager::GenerateHash(dictionary_text_1, &tmp_hash, &server_hash_1);
    398   SdchManager::GenerateHash(dictionary_text_2, &tmp_hash, &server_hash_2);
    399 
    400   // Confirm that if you add directories to one manager, you
    401   // can't get them from the other.
    402   EXPECT_TRUE(sdch_manager()->AddSdchDictionary(
    403       dictionary_text_1, GURL("http://" + dictionary_domain_1)));
    404   scoped_refptr<SdchManager::Dictionary> dictionary;
    405   sdch_manager()->GetVcdiffDictionary(
    406       server_hash_1,
    407       GURL("http://" + dictionary_domain_1 + "/random_url"),
    408       &dictionary);
    409   EXPECT_TRUE(dictionary);
    410 
    411   EXPECT_TRUE(second_manager.AddSdchDictionary(
    412       dictionary_text_2, GURL("http://" + dictionary_domain_2)));
    413   second_manager.GetVcdiffDictionary(
    414       server_hash_2,
    415       GURL("http://" + dictionary_domain_2 + "/random_url"),
    416       &dictionary);
    417   EXPECT_TRUE(dictionary);
    418 
    419   sdch_manager()->GetVcdiffDictionary(
    420       server_hash_2,
    421       GURL("http://" + dictionary_domain_2 + "/random_url"),
    422       &dictionary);
    423   EXPECT_FALSE(dictionary);
    424 
    425   second_manager.GetVcdiffDictionary(
    426       server_hash_1,
    427       GURL("http://" + dictionary_domain_1 + "/random_url"),
    428       &dictionary);
    429   EXPECT_FALSE(dictionary);
    430 }
    431 
    432 TEST_F(SdchManagerTest, HttpsCorrectlySupported) {
    433   GURL url("http://www.google.com");
    434   GURL secure_url("https://www.google.com");
    435 
    436   EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(url));
    437   EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(secure_url));
    438 
    439   SdchManager::EnableSecureSchemeSupport(true);
    440   EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(url));
    441   EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(secure_url));
    442 }
    443 
    444 TEST_F(SdchManagerTest, ClearDictionaryData) {
    445   std::string dictionary_domain("x.y.z.google.com");
    446   GURL blacklist_url("http://bad.chromium.org");
    447 
    448   std::string dictionary_text(NewSdchDictionary(dictionary_domain));
    449   std::string tmp_hash;
    450   std::string server_hash;
    451 
    452   SdchManager::GenerateHash(dictionary_text, &tmp_hash, &server_hash);
    453 
    454   EXPECT_TRUE(sdch_manager()->AddSdchDictionary(
    455       dictionary_text, GURL("http://" + dictionary_domain)));
    456   scoped_refptr<SdchManager::Dictionary> dictionary;
    457   sdch_manager()->GetVcdiffDictionary(
    458       server_hash,
    459       GURL("http://" + dictionary_domain + "/random_url"),
    460       &dictionary);
    461   EXPECT_TRUE(dictionary);
    462 
    463   sdch_manager()->BlacklistDomain(GURL(blacklist_url));
    464   EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(blacklist_url));
    465 
    466   sdch_manager()->ClearData();
    467 
    468   dictionary = NULL;
    469   sdch_manager()->GetVcdiffDictionary(
    470       server_hash,
    471       GURL("http://" + dictionary_domain + "/random_url"),
    472       &dictionary);
    473   EXPECT_FALSE(dictionary);
    474   EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(blacklist_url));
    475 }
    476 
    477 }  // namespace net
    478 
    479