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