| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 "net/cookies/cookie_store_unittest.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <string> | |
| 9 #include <vector> | |
| 10 | |
| 11 #include "base/basictypes.h" | |
| 12 #include "base/bind.h" | |
| 13 #include "base/memory/ref_counted.h" | |
| 14 #include "base/memory/scoped_ptr.h" | |
| 15 #include "base/memory/scoped_vector.h" | |
| 16 #include "base/message_loop/message_loop.h" | |
| 17 #include "base/metrics/histogram.h" | |
| 18 #include "base/metrics/histogram_samples.h" | |
| 19 #include "base/strings/string_number_conversions.h" | |
| 20 #include "base/strings/string_piece.h" | |
| 21 #include "base/strings/string_split.h" | |
| 22 #include "base/strings/string_tokenizer.h" | |
| 23 #include "base/strings/stringprintf.h" | |
| 24 #include "base/threading/thread.h" | |
| 25 #include "base/time/time.h" | |
| 26 #include "net/cookies/canonical_cookie.h" | |
| 27 #include "net/cookies/cookie_constants.h" | |
| 28 #include "net/cookies/cookie_monster.h" | |
| 29 #include "net/cookies/cookie_monster_store_test.h" // For CookieStore mock | |
| 30 #include "net/cookies/cookie_util.h" | |
| 31 #include "net/cookies/parsed_cookie.h" | |
| 32 #include "testing/gmock/include/gmock/gmock.h" | |
| 33 #include "testing/gtest/include/gtest/gtest.h" | |
| 34 #include "url/gurl.h" | |
| 35 | |
| 36 namespace net { | |
| 37 | |
| 38 using base::Time; | |
| 39 using base::TimeDelta; | |
| 40 | |
| 41 namespace { | |
| 42 | |
| 43 // TODO(erikwright): Replace the pre-existing MockPersistentCookieStore (and | |
| 44 // brethren) with this one, and remove the 'New' prefix. | |
| 45 class NewMockPersistentCookieStore | |
| 46 : public CookieMonster::PersistentCookieStore { | |
| 47 public: | |
| 48 MOCK_METHOD1(Load, void(const LoadedCallback& loaded_callback)); | |
| 49 MOCK_METHOD2(LoadCookiesForKey, void(const std::string& key, | |
| 50 const LoadedCallback& loaded_callback)); | |
| 51 MOCK_METHOD1(AddCookie, void(const CanonicalCookie& cc)); | |
| 52 MOCK_METHOD1(UpdateCookieAccessTime, void(const CanonicalCookie& cc)); | |
| 53 MOCK_METHOD1(DeleteCookie, void(const CanonicalCookie& cc)); | |
| 54 virtual void Flush(const base::Closure& callback) { | |
| 55 if (!callback.is_null()) | |
| 56 base::MessageLoop::current()->PostTask(FROM_HERE, callback); | |
| 57 } | |
| 58 MOCK_METHOD0(SetForceKeepSessionState, void()); | |
| 59 | |
| 60 private: | |
| 61 virtual ~NewMockPersistentCookieStore() {} | |
| 62 }; | |
| 63 | |
| 64 const char kTopLevelDomainPlus1[] = "http://www.harvard.edu"; | |
| 65 const char kTopLevelDomainPlus2[] = "http://www.math.harvard.edu"; | |
| 66 const char kTopLevelDomainPlus2Secure[] = "https://www.math.harvard.edu"; | |
| 67 const char kTopLevelDomainPlus3[] = | |
| 68 "http://www.bourbaki.math.harvard.edu"; | |
| 69 const char kOtherDomain[] = "http://www.mit.edu"; | |
| 70 const char kUrlGoogleSpecific[] = "http://www.gmail.google.izzle"; | |
| 71 | |
| 72 class GetCookieListCallback : public CookieCallback { | |
| 73 public: | |
| 74 GetCookieListCallback() {} | |
| 75 explicit GetCookieListCallback(Thread* run_in_thread) | |
| 76 : CookieCallback(run_in_thread) {} | |
| 77 | |
| 78 void Run(const CookieList& cookies) { | |
| 79 cookies_ = cookies; | |
| 80 CallbackEpilogue(); | |
| 81 } | |
| 82 | |
| 83 const CookieList& cookies() { return cookies_; } | |
| 84 | |
| 85 private: | |
| 86 CookieList cookies_; | |
| 87 }; | |
| 88 | |
| 89 struct CookieMonsterTestTraits { | |
| 90 static scoped_refptr<CookieStore> Create() { | |
| 91 return new CookieMonster(NULL, NULL); | |
| 92 } | |
| 93 | |
| 94 static const bool is_cookie_monster = true; | |
| 95 static const bool supports_http_only = true; | |
| 96 static const bool supports_non_dotted_domains = true; | |
| 97 static const bool supports_trailing_dots = true; | |
| 98 static const bool filters_schemes = true; | |
| 99 static const bool has_path_prefix_bug = false; | |
| 100 static const int creation_time_granularity_in_ms = 0; | |
| 101 }; | |
| 102 | |
| 103 INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster, | |
| 104 CookieStoreTest, | |
| 105 CookieMonsterTestTraits); | |
| 106 | |
| 107 INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster, | |
| 108 MultiThreadedCookieStoreTest, | |
| 109 CookieMonsterTestTraits); | |
| 110 | |
| 111 class CookieMonsterTest : public CookieStoreTest<CookieMonsterTestTraits> { | |
| 112 protected: | |
| 113 | |
| 114 CookieList GetAllCookies(CookieMonster* cm) { | |
| 115 DCHECK(cm); | |
| 116 GetCookieListCallback callback; | |
| 117 cm->GetAllCookiesAsync( | |
| 118 base::Bind(&GetCookieListCallback::Run, | |
| 119 base::Unretained(&callback))); | |
| 120 RunFor(kTimeout); | |
| 121 EXPECT_TRUE(callback.did_run()); | |
| 122 return callback.cookies(); | |
| 123 } | |
| 124 | |
| 125 CookieList GetAllCookiesForURL(CookieMonster* cm, | |
| 126 const GURL& url) { | |
| 127 DCHECK(cm); | |
| 128 GetCookieListCallback callback; | |
| 129 cm->GetAllCookiesForURLAsync( | |
| 130 url, base::Bind(&GetCookieListCallback::Run, | |
| 131 base::Unretained(&callback))); | |
| 132 RunFor(kTimeout); | |
| 133 EXPECT_TRUE(callback.did_run()); | |
| 134 return callback.cookies(); | |
| 135 } | |
| 136 | |
| 137 CookieList GetAllCookiesForURLWithOptions(CookieMonster* cm, | |
| 138 const GURL& url, | |
| 139 const CookieOptions& options) { | |
| 140 DCHECK(cm); | |
| 141 GetCookieListCallback callback; | |
| 142 cm->GetAllCookiesForURLWithOptionsAsync( | |
| 143 url, options, base::Bind(&GetCookieListCallback::Run, | |
| 144 base::Unretained(&callback))); | |
| 145 RunFor(kTimeout); | |
| 146 EXPECT_TRUE(callback.did_run()); | |
| 147 return callback.cookies(); | |
| 148 } | |
| 149 | |
| 150 bool SetCookieWithDetails(CookieMonster* cm, | |
| 151 const GURL& url, | |
| 152 const std::string& name, | |
| 153 const std::string& value, | |
| 154 const std::string& domain, | |
| 155 const std::string& path, | |
| 156 const base::Time& expiration_time, | |
| 157 bool secure, | |
| 158 bool http_only, | |
| 159 CookiePriority priority) { | |
| 160 DCHECK(cm); | |
| 161 ResultSavingCookieCallback<bool> callback; | |
| 162 cm->SetCookieWithDetailsAsync( | |
| 163 url, name, value, domain, path, expiration_time, secure, http_only, | |
| 164 priority, | |
| 165 base::Bind( | |
| 166 &ResultSavingCookieCallback<bool>::Run, | |
| 167 base::Unretained(&callback))); | |
| 168 RunFor(kTimeout); | |
| 169 EXPECT_TRUE(callback.did_run()); | |
| 170 return callback.result(); | |
| 171 } | |
| 172 | |
| 173 int DeleteAll(CookieMonster*cm) { | |
| 174 DCHECK(cm); | |
| 175 ResultSavingCookieCallback<int> callback; | |
| 176 cm->DeleteAllAsync( | |
| 177 base::Bind( | |
| 178 &ResultSavingCookieCallback<int>::Run, | |
| 179 base::Unretained(&callback))); | |
| 180 RunFor(kTimeout); | |
| 181 EXPECT_TRUE(callback.did_run()); | |
| 182 return callback.result(); | |
| 183 } | |
| 184 | |
| 185 int DeleteAllCreatedBetween(CookieMonster*cm, | |
| 186 const base::Time& delete_begin, | |
| 187 const base::Time& delete_end) { | |
| 188 DCHECK(cm); | |
| 189 ResultSavingCookieCallback<int> callback; | |
| 190 cm->DeleteAllCreatedBetweenAsync( | |
| 191 delete_begin, delete_end, | |
| 192 base::Bind( | |
| 193 &ResultSavingCookieCallback<int>::Run, | |
| 194 base::Unretained(&callback))); | |
| 195 RunFor(kTimeout); | |
| 196 EXPECT_TRUE(callback.did_run()); | |
| 197 return callback.result(); | |
| 198 } | |
| 199 | |
| 200 int DeleteAllCreatedBetweenForHost(CookieMonster* cm, | |
| 201 const base::Time delete_begin, | |
| 202 const base::Time delete_end, | |
| 203 const GURL& url) { | |
| 204 DCHECK(cm); | |
| 205 ResultSavingCookieCallback<int> callback; | |
| 206 cm->DeleteAllCreatedBetweenForHostAsync( | |
| 207 delete_begin, delete_end, url, | |
| 208 base::Bind( | |
| 209 &ResultSavingCookieCallback<int>::Run, | |
| 210 base::Unretained(&callback))); | |
| 211 RunFor(kTimeout); | |
| 212 EXPECT_TRUE(callback.did_run()); | |
| 213 return callback.result(); | |
| 214 } | |
| 215 | |
| 216 int DeleteAllForHost(CookieMonster* cm, | |
| 217 const GURL& url) { | |
| 218 DCHECK(cm); | |
| 219 ResultSavingCookieCallback<int> callback; | |
| 220 cm->DeleteAllForHostAsync( | |
| 221 url, base::Bind(&ResultSavingCookieCallback<int>::Run, | |
| 222 base::Unretained(&callback))); | |
| 223 RunFor(kTimeout); | |
| 224 EXPECT_TRUE(callback.did_run()); | |
| 225 return callback.result(); | |
| 226 } | |
| 227 | |
| 228 bool DeleteCanonicalCookie(CookieMonster* cm, const CanonicalCookie& cookie) { | |
| 229 DCHECK(cm); | |
| 230 ResultSavingCookieCallback<bool> callback; | |
| 231 cm->DeleteCanonicalCookieAsync( | |
| 232 cookie, | |
| 233 base::Bind(&ResultSavingCookieCallback<bool>::Run, | |
| 234 base::Unretained(&callback))); | |
| 235 RunFor(kTimeout); | |
| 236 EXPECT_TRUE(callback.did_run()); | |
| 237 return callback.result(); | |
| 238 } | |
| 239 | |
| 240 // Helper for DeleteAllForHost test; repopulates CM with same layout | |
| 241 // each time. | |
| 242 void PopulateCmForDeleteAllForHost(scoped_refptr<CookieMonster> cm) { | |
| 243 GURL url_top_level_domain_plus_1(kTopLevelDomainPlus1); | |
| 244 GURL url_top_level_domain_plus_2(kTopLevelDomainPlus2); | |
| 245 GURL url_top_level_domain_plus_2_secure(kTopLevelDomainPlus2Secure); | |
| 246 GURL url_top_level_domain_plus_3(kTopLevelDomainPlus3); | |
| 247 GURL url_other(kOtherDomain); | |
| 248 | |
| 249 DeleteAll(cm.get()); | |
| 250 | |
| 251 // Static population for probe: | |
| 252 // * Three levels of domain cookie (.b.a, .c.b.a, .d.c.b.a) | |
| 253 // * Three levels of host cookie (w.b.a, w.c.b.a, w.d.c.b.a) | |
| 254 // * http_only cookie (w.c.b.a) | |
| 255 // * Two secure cookies (.c.b.a, w.c.b.a) | |
| 256 // * Two domain path cookies (.c.b.a/dir1, .c.b.a/dir1/dir2) | |
| 257 // * Two host path cookies (w.c.b.a/dir1, w.c.b.a/dir1/dir2) | |
| 258 | |
| 259 // Domain cookies | |
| 260 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(), | |
| 261 url_top_level_domain_plus_1, | |
| 262 "dom_1", | |
| 263 "X", | |
| 264 ".harvard.edu", | |
| 265 "/", | |
| 266 base::Time(), | |
| 267 false, | |
| 268 false, | |
| 269 COOKIE_PRIORITY_DEFAULT)); | |
| 270 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(), | |
| 271 url_top_level_domain_plus_2, | |
| 272 "dom_2", | |
| 273 "X", | |
| 274 ".math.harvard.edu", | |
| 275 "/", | |
| 276 base::Time(), | |
| 277 false, | |
| 278 false, | |
| 279 COOKIE_PRIORITY_DEFAULT)); | |
| 280 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(), | |
| 281 url_top_level_domain_plus_3, | |
| 282 "dom_3", | |
| 283 "X", | |
| 284 ".bourbaki.math.harvard.edu", | |
| 285 "/", | |
| 286 base::Time(), | |
| 287 false, | |
| 288 false, | |
| 289 COOKIE_PRIORITY_DEFAULT)); | |
| 290 | |
| 291 // Host cookies | |
| 292 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(), | |
| 293 url_top_level_domain_plus_1, | |
| 294 "host_1", | |
| 295 "X", | |
| 296 std::string(), | |
| 297 "/", | |
| 298 base::Time(), | |
| 299 false, | |
| 300 false, | |
| 301 COOKIE_PRIORITY_DEFAULT)); | |
| 302 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(), | |
| 303 url_top_level_domain_plus_2, | |
| 304 "host_2", | |
| 305 "X", | |
| 306 std::string(), | |
| 307 "/", | |
| 308 base::Time(), | |
| 309 false, | |
| 310 false, | |
| 311 COOKIE_PRIORITY_DEFAULT)); | |
| 312 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(), | |
| 313 url_top_level_domain_plus_3, | |
| 314 "host_3", | |
| 315 "X", | |
| 316 std::string(), | |
| 317 "/", | |
| 318 base::Time(), | |
| 319 false, | |
| 320 false, | |
| 321 COOKIE_PRIORITY_DEFAULT)); | |
| 322 | |
| 323 // Http_only cookie | |
| 324 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(), | |
| 325 url_top_level_domain_plus_2, | |
| 326 "httpo_check", | |
| 327 "X", | |
| 328 std::string(), | |
| 329 "/", | |
| 330 base::Time(), | |
| 331 false, | |
| 332 true, | |
| 333 COOKIE_PRIORITY_DEFAULT)); | |
| 334 | |
| 335 // Secure cookies | |
| 336 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(), | |
| 337 url_top_level_domain_plus_2_secure, | |
| 338 "sec_dom", | |
| 339 "X", | |
| 340 ".math.harvard.edu", | |
| 341 "/", | |
| 342 base::Time(), | |
| 343 true, | |
| 344 false, | |
| 345 COOKIE_PRIORITY_DEFAULT)); | |
| 346 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(), | |
| 347 url_top_level_domain_plus_2_secure, | |
| 348 "sec_host", | |
| 349 "X", | |
| 350 std::string(), | |
| 351 "/", | |
| 352 base::Time(), | |
| 353 true, | |
| 354 false, | |
| 355 COOKIE_PRIORITY_DEFAULT)); | |
| 356 | |
| 357 // Domain path cookies | |
| 358 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(), | |
| 359 url_top_level_domain_plus_2, | |
| 360 "dom_path_1", | |
| 361 "X", | |
| 362 ".math.harvard.edu", | |
| 363 "/dir1", | |
| 364 base::Time(), | |
| 365 false, | |
| 366 false, | |
| 367 COOKIE_PRIORITY_DEFAULT)); | |
| 368 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(), | |
| 369 url_top_level_domain_plus_2, | |
| 370 "dom_path_2", | |
| 371 "X", | |
| 372 ".math.harvard.edu", | |
| 373 "/dir1/dir2", | |
| 374 base::Time(), | |
| 375 false, | |
| 376 false, | |
| 377 COOKIE_PRIORITY_DEFAULT)); | |
| 378 | |
| 379 // Host path cookies | |
| 380 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(), | |
| 381 url_top_level_domain_plus_2, | |
| 382 "host_path_1", | |
| 383 "X", | |
| 384 std::string(), | |
| 385 "/dir1", | |
| 386 base::Time(), | |
| 387 false, | |
| 388 false, | |
| 389 COOKIE_PRIORITY_DEFAULT)); | |
| 390 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(), | |
| 391 url_top_level_domain_plus_2, | |
| 392 "host_path_2", | |
| 393 "X", | |
| 394 std::string(), | |
| 395 "/dir1/dir2", | |
| 396 base::Time(), | |
| 397 false, | |
| 398 false, | |
| 399 COOKIE_PRIORITY_DEFAULT)); | |
| 400 | |
| 401 EXPECT_EQ(13U, this->GetAllCookies(cm.get()).size()); | |
| 402 } | |
| 403 | |
| 404 Time GetFirstCookieAccessDate(CookieMonster* cm) { | |
| 405 const CookieList all_cookies(this->GetAllCookies(cm)); | |
| 406 return all_cookies.front().LastAccessDate(); | |
| 407 } | |
| 408 | |
| 409 bool FindAndDeleteCookie(CookieMonster* cm, | |
| 410 const std::string& domain, | |
| 411 const std::string& name) { | |
| 412 CookieList cookies = this->GetAllCookies(cm); | |
| 413 for (CookieList::iterator it = cookies.begin(); | |
| 414 it != cookies.end(); ++it) | |
| 415 if (it->Domain() == domain && it->Name() == name) | |
| 416 return this->DeleteCanonicalCookie(cm, *it); | |
| 417 return false; | |
| 418 } | |
| 419 | |
| 420 int CountInString(const std::string& str, char c) { | |
| 421 return std::count(str.begin(), str.end(), c); | |
| 422 } | |
| 423 | |
| 424 void TestHostGarbageCollectHelper() { | |
| 425 int domain_max_cookies = CookieMonster::kDomainMaxCookies; | |
| 426 int domain_purge_cookies = CookieMonster::kDomainPurgeCookies; | |
| 427 const int more_than_enough_cookies = | |
| 428 (domain_max_cookies + domain_purge_cookies) * 2; | |
| 429 // Add a bunch of cookies on a single host, should purge them. | |
| 430 { | |
| 431 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 432 for (int i = 0; i < more_than_enough_cookies; ++i) { | |
| 433 std::string cookie = base::StringPrintf("a%03d=b", i); | |
| 434 EXPECT_TRUE(SetCookie(cm.get(), url_google_, cookie)); | |
| 435 std::string cookies = this->GetCookies(cm.get(), url_google_); | |
| 436 // Make sure we find it in the cookies. | |
| 437 EXPECT_NE(cookies.find(cookie), std::string::npos); | |
| 438 // Count the number of cookies. | |
| 439 EXPECT_LE(CountInString(cookies, '='), domain_max_cookies); | |
| 440 } | |
| 441 } | |
| 442 | |
| 443 // Add a bunch of cookies on multiple hosts within a single eTLD. | |
| 444 // Should keep at least kDomainMaxCookies - kDomainPurgeCookies | |
| 445 // between them. We shouldn't go above kDomainMaxCookies for both together. | |
| 446 GURL url_google_specific(kUrlGoogleSpecific); | |
| 447 { | |
| 448 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 449 for (int i = 0; i < more_than_enough_cookies; ++i) { | |
| 450 std::string cookie_general = base::StringPrintf("a%03d=b", i); | |
| 451 EXPECT_TRUE(SetCookie(cm.get(), url_google_, cookie_general)); | |
| 452 std::string cookie_specific = base::StringPrintf("c%03d=b", i); | |
| 453 EXPECT_TRUE(SetCookie(cm.get(), url_google_specific, cookie_specific)); | |
| 454 std::string cookies_general = this->GetCookies(cm.get(), url_google_); | |
| 455 EXPECT_NE(cookies_general.find(cookie_general), std::string::npos); | |
| 456 std::string cookies_specific = | |
| 457 this->GetCookies(cm.get(), url_google_specific); | |
| 458 EXPECT_NE(cookies_specific.find(cookie_specific), std::string::npos); | |
| 459 EXPECT_LE((CountInString(cookies_general, '=') + | |
| 460 CountInString(cookies_specific, '=')), | |
| 461 domain_max_cookies); | |
| 462 } | |
| 463 // After all this, there should be at least | |
| 464 // kDomainMaxCookies - kDomainPurgeCookies for both URLs. | |
| 465 std::string cookies_general = this->GetCookies(cm.get(), url_google_); | |
| 466 std::string cookies_specific = | |
| 467 this->GetCookies(cm.get(), url_google_specific); | |
| 468 int total_cookies = (CountInString(cookies_general, '=') + | |
| 469 CountInString(cookies_specific, '=')); | |
| 470 EXPECT_GE(total_cookies, domain_max_cookies - domain_purge_cookies); | |
| 471 EXPECT_LE(total_cookies, domain_max_cookies); | |
| 472 } | |
| 473 } | |
| 474 | |
| 475 CookiePriority CharToPriority(char ch) { | |
| 476 switch (ch) { | |
| 477 case 'L': | |
| 478 return COOKIE_PRIORITY_LOW; | |
| 479 case 'M': | |
| 480 return COOKIE_PRIORITY_MEDIUM; | |
| 481 case 'H': | |
| 482 return COOKIE_PRIORITY_HIGH; | |
| 483 } | |
| 484 NOTREACHED(); | |
| 485 return COOKIE_PRIORITY_DEFAULT; | |
| 486 } | |
| 487 | |
| 488 // Instantiates a CookieMonster, adds multiple cookies (to url_google_) with | |
| 489 // priorities specified by |coded_priority_str|, and tests priority-aware | |
| 490 // domain cookie eviction. | |
| 491 // |coded_priority_str| specifies a run-length-encoded string of priorities. | |
| 492 // Example: "2M 3L M 4H" means "MMLLLMHHHH", and speicifies sequential (i.e., | |
| 493 // from least- to most-recently accessed) insertion of 2 medium-priority | |
| 494 // cookies, 3 low-priority cookies, 1 medium-priority cookie, and 4 | |
| 495 // high-priority cookies. | |
| 496 // Within each priority, only the least-accessed cookies should be evicted. | |
| 497 // Thus, to describe expected suriving cookies, it suffices to specify the | |
| 498 // expected population of surviving cookies per priority, i.e., | |
| 499 // |expected_low_count|, |expected_medium_count|, and |expected_high_count|. | |
| 500 void TestPriorityCookieCase(CookieMonster* cm, | |
| 501 const std::string& coded_priority_str, | |
| 502 size_t expected_low_count, | |
| 503 size_t expected_medium_count, | |
| 504 size_t expected_high_count) { | |
| 505 DeleteAll(cm); | |
| 506 int next_cookie_id = 0; | |
| 507 std::vector<CookiePriority> priority_list; | |
| 508 std::vector<int> id_list[3]; // Indexed by CookiePriority. | |
| 509 | |
| 510 // Parse |coded_priority_str| and add cookies. | |
| 511 std::vector<std::string> priority_tok_list; | |
| 512 base::SplitString(coded_priority_str, ' ', &priority_tok_list); | |
| 513 for (std::vector<std::string>::iterator it = priority_tok_list.begin(); | |
| 514 it != priority_tok_list.end(); ++it) { | |
| 515 size_t len = it->length(); | |
| 516 DCHECK_NE(len, 0U); | |
| 517 // Take last character as priority. | |
| 518 CookiePriority priority = CharToPriority((*it)[len - 1]); | |
| 519 std::string priority_str = CookiePriorityToString(priority); | |
| 520 // The rest of the string (possibly empty) specifies repetition. | |
| 521 int rep = 1; | |
| 522 if (!it->empty()) { | |
| 523 bool result = base::StringToInt( | |
| 524 base::StringPiece(it->begin(), it->end() - 1), &rep); | |
| 525 DCHECK(result); | |
| 526 } | |
| 527 for (; rep > 0; --rep, ++next_cookie_id) { | |
| 528 std::string cookie = base::StringPrintf( | |
| 529 "a%d=b;priority=%s", next_cookie_id, priority_str.c_str()); | |
| 530 EXPECT_TRUE(SetCookie(cm, url_google_, cookie)); | |
| 531 priority_list.push_back(priority); | |
| 532 id_list[priority].push_back(next_cookie_id); | |
| 533 } | |
| 534 } | |
| 535 | |
| 536 int num_cookies = static_cast<int>(priority_list.size()); | |
| 537 std::vector<int> surviving_id_list[3]; // Indexed by CookiePriority. | |
| 538 | |
| 539 // Parse the list of cookies | |
| 540 std::string cookie_str = this->GetCookies(cm, url_google_); | |
| 541 std::vector<std::string> cookie_tok_list; | |
| 542 base::SplitString(cookie_str, ';', &cookie_tok_list); | |
| 543 for (std::vector<std::string>::iterator it = cookie_tok_list.begin(); | |
| 544 it != cookie_tok_list.end(); ++it) { | |
| 545 // Assuming *it is "a#=b", so extract and parse "#" portion. | |
| 546 int id = -1; | |
| 547 bool result = base::StringToInt( | |
| 548 base::StringPiece(it->begin() + 1, it->end() - 2), &id); | |
| 549 DCHECK(result); | |
| 550 DCHECK_GE(id, 0); | |
| 551 DCHECK_LT(id, num_cookies); | |
| 552 surviving_id_list[priority_list[id]].push_back(id); | |
| 553 } | |
| 554 | |
| 555 // Validate each priority. | |
| 556 size_t expected_count[3] = { | |
| 557 expected_low_count, expected_medium_count, expected_high_count | |
| 558 }; | |
| 559 for (int i = 0; i < 3; ++i) { | |
| 560 DCHECK_LE(surviving_id_list[i].size(), id_list[i].size()); | |
| 561 EXPECT_EQ(expected_count[i], surviving_id_list[i].size()); | |
| 562 // Verify that the remaining cookies are the most recent among those | |
| 563 // with the same priorities. | |
| 564 if (expected_count[i] == surviving_id_list[i].size()) { | |
| 565 std::sort(surviving_id_list[i].begin(), surviving_id_list[i].end()); | |
| 566 EXPECT_TRUE(std::equal(surviving_id_list[i].begin(), | |
| 567 surviving_id_list[i].end(), | |
| 568 id_list[i].end() - expected_count[i])); | |
| 569 } | |
| 570 } | |
| 571 } | |
| 572 | |
| 573 void TestPriorityAwareGarbageCollectHelper() { | |
| 574 // Hard-coding limits in the test, but use DCHECK_EQ to enforce constraint. | |
| 575 DCHECK_EQ(180U, CookieMonster::kDomainMaxCookies); | |
| 576 DCHECK_EQ(150U, CookieMonster::kDomainMaxCookies - | |
| 577 CookieMonster::kDomainPurgeCookies); | |
| 578 DCHECK_EQ(30U, CookieMonster::kDomainCookiesQuotaLow); | |
| 579 DCHECK_EQ(50U, CookieMonster::kDomainCookiesQuotaMedium); | |
| 580 DCHECK_EQ(70U, CookieMonster::kDomainCookiesQuotaHigh); | |
| 581 | |
| 582 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 583 | |
| 584 // Each test case adds 181 cookies, so 31 cookies are evicted. | |
| 585 // Cookie same priority, repeated for each priority. | |
| 586 TestPriorityCookieCase(cm.get(), "181L", 150U, 0U, 0U); | |
| 587 TestPriorityCookieCase(cm.get(), "181M", 0U, 150U, 0U); | |
| 588 TestPriorityCookieCase(cm.get(), "181H", 0U, 0U, 150U); | |
| 589 | |
| 590 // Pairwise scenarios. | |
| 591 // Round 1 => none; round2 => 31M; round 3 => none. | |
| 592 TestPriorityCookieCase(cm.get(), "10H 171M", 0U, 140U, 10U); | |
| 593 // Round 1 => 10L; round2 => 21M; round 3 => none. | |
| 594 TestPriorityCookieCase(cm.get(), "141M 40L", 30U, 120U, 0U); | |
| 595 // Round 1 => none; round2 => none; round 3 => 31H. | |
| 596 TestPriorityCookieCase(cm.get(), "101H 80M", 0U, 80U, 70U); | |
| 597 | |
| 598 // For {low, medium} priorities right on quota, different orders. | |
| 599 // Round 1 => 1L; round 2 => none, round3 => 30L. | |
| 600 TestPriorityCookieCase(cm.get(), "31L 50M 100H", 0U, 50U, 100U); | |
| 601 // Round 1 => none; round 2 => 1M, round3 => 30M. | |
| 602 TestPriorityCookieCase(cm.get(), "51M 100H 30L", 30U, 20U, 100U); | |
| 603 // Round 1 => none; round 2 => none; round3 => 31H. | |
| 604 TestPriorityCookieCase(cm.get(), "101H 50M 30L", 30U, 50U, 70U); | |
| 605 | |
| 606 // Round 1 => 10L; round 2 => 10M; round3 => 11H. | |
| 607 TestPriorityCookieCase(cm.get(), "81H 60M 40L", 30U, 50U, 70U); | |
| 608 | |
| 609 // More complex scenarios. | |
| 610 // Round 1 => 10L; round 2 => 10M; round 3 => 11H. | |
| 611 TestPriorityCookieCase(cm.get(), "21H 60M 40L 60H", 30U, 50U, 70U); | |
| 612 // Round 1 => 10L; round 2 => 11M, 10L; round 3 => none. | |
| 613 TestPriorityCookieCase( | |
| 614 cm.get(), "11H 10M 20L 110M 20L 10H", 20U, 109U, 21U); | |
| 615 // Round 1 => none; round 2 => none; round 3 => 11L, 10M, 10H. | |
| 616 TestPriorityCookieCase(cm.get(), "11L 10M 140H 10M 10L", 10U, 10U, 130U); | |
| 617 // Round 1 => none; round 2 => 1M; round 3 => 10L, 10M, 10H. | |
| 618 TestPriorityCookieCase(cm.get(), "11M 10H 10L 60M 90H", 0U, 60U, 90U); | |
| 619 // Round 1 => none; round 2 => 10L, 21M; round 3 => none. | |
| 620 TestPriorityCookieCase(cm.get(), "11M 10H 10L 90M 60H", 0U, 80U, 70U); | |
| 621 } | |
| 622 | |
| 623 // Function for creating a CM with a number of cookies in it, | |
| 624 // no store (and hence no ability to affect access time). | |
| 625 CookieMonster* CreateMonsterForGC(int num_cookies) { | |
| 626 CookieMonster* cm(new CookieMonster(NULL, NULL)); | |
| 627 for (int i = 0; i < num_cookies; i++) { | |
| 628 SetCookie(cm, GURL(base::StringPrintf("http://h%05d.izzle", i)), "a=1"); | |
| 629 } | |
| 630 return cm; | |
| 631 } | |
| 632 }; | |
| 633 | |
| 634 // TODO(erikwright): Replace the other callbacks and synchronous helper methods | |
| 635 // in this test suite with these Mocks. | |
| 636 template<typename T, typename C> class MockCookieCallback { | |
| 637 public: | |
| 638 C AsCallback() { | |
| 639 return base::Bind(&T::Invoke, base::Unretained(static_cast<T*>(this))); | |
| 640 } | |
| 641 }; | |
| 642 | |
| 643 class MockGetCookiesCallback | |
| 644 : public MockCookieCallback<MockGetCookiesCallback, | |
| 645 CookieStore::GetCookiesCallback> { | |
| 646 public: | |
| 647 MOCK_METHOD1(Invoke, void(const std::string& cookies)); | |
| 648 }; | |
| 649 | |
| 650 class MockSetCookiesCallback | |
| 651 : public MockCookieCallback<MockSetCookiesCallback, | |
| 652 CookieStore::SetCookiesCallback> { | |
| 653 public: | |
| 654 MOCK_METHOD1(Invoke, void(bool success)); | |
| 655 }; | |
| 656 | |
| 657 class MockClosure | |
| 658 : public MockCookieCallback<MockClosure, base::Closure> { | |
| 659 public: | |
| 660 MOCK_METHOD0(Invoke, void(void)); | |
| 661 }; | |
| 662 | |
| 663 class MockGetCookieListCallback | |
| 664 : public MockCookieCallback<MockGetCookieListCallback, | |
| 665 CookieMonster::GetCookieListCallback> { | |
| 666 public: | |
| 667 MOCK_METHOD1(Invoke, void(const CookieList& cookies)); | |
| 668 }; | |
| 669 | |
| 670 class MockDeleteCallback | |
| 671 : public MockCookieCallback<MockDeleteCallback, | |
| 672 CookieMonster::DeleteCallback> { | |
| 673 public: | |
| 674 MOCK_METHOD1(Invoke, void(int num_deleted)); | |
| 675 }; | |
| 676 | |
| 677 class MockDeleteCookieCallback | |
| 678 : public MockCookieCallback<MockDeleteCookieCallback, | |
| 679 CookieMonster::DeleteCookieCallback> { | |
| 680 public: | |
| 681 MOCK_METHOD1(Invoke, void(bool success)); | |
| 682 }; | |
| 683 | |
| 684 struct CookiesInputInfo { | |
| 685 const GURL url; | |
| 686 const std::string name; | |
| 687 const std::string value; | |
| 688 const std::string domain; | |
| 689 const std::string path; | |
| 690 const base::Time expiration_time; | |
| 691 bool secure; | |
| 692 bool http_only; | |
| 693 CookiePriority priority; | |
| 694 }; | |
| 695 | |
| 696 ACTION(QuitCurrentMessageLoop) { | |
| 697 base::MessageLoop::current()->PostTask(FROM_HERE, | |
| 698 base::MessageLoop::QuitClosure()); | |
| 699 } | |
| 700 | |
| 701 // TODO(erikwright): When the synchronous helpers 'GetCookies' etc. are removed, | |
| 702 // rename these, removing the 'Action' suffix. | |
| 703 ACTION_P4(DeleteCookieAction, cookie_monster, url, name, callback) { | |
| 704 cookie_monster->DeleteCookieAsync(url, name, callback->AsCallback()); | |
| 705 } | |
| 706 ACTION_P3(GetCookiesAction, cookie_monster, url, callback) { | |
| 707 cookie_monster->GetCookiesWithOptionsAsync( | |
| 708 url, CookieOptions(), callback->AsCallback()); | |
| 709 } | |
| 710 ACTION_P4(SetCookieAction, cookie_monster, url, cookie_line, callback) { | |
| 711 cookie_monster->SetCookieWithOptionsAsync( | |
| 712 url, cookie_line, CookieOptions(), callback->AsCallback()); | |
| 713 } | |
| 714 ACTION_P4(DeleteAllCreatedBetweenAction, | |
| 715 cookie_monster, delete_begin, delete_end, callback) { | |
| 716 cookie_monster->DeleteAllCreatedBetweenAsync( | |
| 717 delete_begin, delete_end, callback->AsCallback()); | |
| 718 } | |
| 719 ACTION_P3(SetCookieWithDetailsAction, cookie_monster, cc, callback) { | |
| 720 cookie_monster->SetCookieWithDetailsAsync( | |
| 721 cc.url, cc.name, cc.value, cc.domain, cc.path, cc.expiration_time, | |
| 722 cc.secure, cc.http_only, cc.priority, | |
| 723 callback->AsCallback()); | |
| 724 } | |
| 725 | |
| 726 ACTION_P2(GetAllCookiesAction, cookie_monster, callback) { | |
| 727 cookie_monster->GetAllCookiesAsync(callback->AsCallback()); | |
| 728 } | |
| 729 | |
| 730 ACTION_P3(DeleteAllForHostAction, cookie_monster, url, callback) { | |
| 731 cookie_monster->DeleteAllForHostAsync(url, callback->AsCallback()); | |
| 732 } | |
| 733 | |
| 734 ACTION_P3(DeleteCanonicalCookieAction, cookie_monster, cookie, callback) { | |
| 735 cookie_monster->DeleteCanonicalCookieAsync(cookie, callback->AsCallback()); | |
| 736 } | |
| 737 | |
| 738 ACTION_P2(DeleteAllAction, cookie_monster, callback) { | |
| 739 cookie_monster->DeleteAllAsync(callback->AsCallback()); | |
| 740 } | |
| 741 | |
| 742 ACTION_P3(GetAllCookiesForUrlWithOptionsAction, cookie_monster, url, callback) { | |
| 743 cookie_monster->GetAllCookiesForURLWithOptionsAsync( | |
| 744 url, CookieOptions(), callback->AsCallback()); | |
| 745 } | |
| 746 | |
| 747 ACTION_P3(GetAllCookiesForUrlAction, cookie_monster, url, callback) { | |
| 748 cookie_monster->GetAllCookiesForURLAsync(url, callback->AsCallback()); | |
| 749 } | |
| 750 | |
| 751 ACTION_P(PushCallbackAction, callback_vector) { | |
| 752 callback_vector->push(arg1); | |
| 753 } | |
| 754 | |
| 755 ACTION_P2(DeleteSessionCookiesAction, cookie_monster, callback) { | |
| 756 cookie_monster->DeleteSessionCookiesAsync(callback->AsCallback()); | |
| 757 } | |
| 758 | |
| 759 } // namespace | |
| 760 | |
| 761 // This test suite verifies the task deferral behaviour of the CookieMonster. | |
| 762 // Specifically, for each asynchronous method, verify that: | |
| 763 // 1. invoking it on an uninitialized cookie store causes the store to begin | |
| 764 // chain-loading its backing data or loading data for a specific domain key | |
| 765 // (eTLD+1). | |
| 766 // 2. The initial invocation does not complete until the loading completes. | |
| 767 // 3. Invocations after the loading has completed complete immediately. | |
| 768 class DeferredCookieTaskTest : public CookieMonsterTest { | |
| 769 protected: | |
| 770 DeferredCookieTaskTest() { | |
| 771 persistent_store_ = new NewMockPersistentCookieStore(); | |
| 772 cookie_monster_ = new CookieMonster(persistent_store_.get(), NULL); | |
| 773 } | |
| 774 | |
| 775 // Defines a cookie to be returned from PersistentCookieStore::Load | |
| 776 void DeclareLoadedCookie(const std::string& key, | |
| 777 const std::string& cookie_line, | |
| 778 const base::Time& creation_time) { | |
| 779 AddCookieToList(key, cookie_line, creation_time, &loaded_cookies_); | |
| 780 } | |
| 781 | |
| 782 // Runs the message loop, waiting until PersistentCookieStore::Load is called. | |
| 783 // Call CompleteLoadingAndWait to cause the load to complete. | |
| 784 void WaitForLoadCall() { | |
| 785 RunFor(kTimeout); | |
| 786 | |
| 787 // Verify that PeristentStore::Load was called. | |
| 788 testing::Mock::VerifyAndClear(persistent_store_.get()); | |
| 789 } | |
| 790 | |
| 791 // Invokes the PersistentCookieStore::LoadCookiesForKey completion callbacks | |
| 792 // and PersistentCookieStore::Load completion callback and waits | |
| 793 // until the message loop is quit. | |
| 794 void CompleteLoadingAndWait() { | |
| 795 while (!loaded_for_key_callbacks_.empty()) { | |
| 796 loaded_for_key_callbacks_.front().Run(loaded_cookies_); | |
| 797 loaded_cookies_.clear(); | |
| 798 loaded_for_key_callbacks_.pop(); | |
| 799 } | |
| 800 | |
| 801 loaded_callback_.Run(loaded_cookies_); | |
| 802 RunFor(kTimeout); | |
| 803 } | |
| 804 | |
| 805 // Performs the provided action, expecting it to cause a call to | |
| 806 // PersistentCookieStore::Load. Call WaitForLoadCall to verify the load call | |
| 807 // is received. | |
| 808 void BeginWith(testing::Action<void(void)> action) { | |
| 809 EXPECT_CALL(*this, Begin()).WillOnce(action); | |
| 810 ExpectLoadCall(); | |
| 811 Begin(); | |
| 812 } | |
| 813 | |
| 814 void BeginWithForDomainKey(std::string key, | |
| 815 testing::Action<void(void)> action) { | |
| 816 EXPECT_CALL(*this, Begin()).WillOnce(action); | |
| 817 ExpectLoadCall(); | |
| 818 ExpectLoadForKeyCall(key, false); | |
| 819 Begin(); | |
| 820 } | |
| 821 | |
| 822 // Declares an expectation that PersistentCookieStore::Load will be called, | |
| 823 // saving the provided callback and sending a quit to the message loop. | |
| 824 void ExpectLoadCall() { | |
| 825 EXPECT_CALL(*persistent_store_.get(), Load(testing::_)) | |
| 826 .WillOnce(testing::DoAll(testing::SaveArg<0>(&loaded_callback_), | |
| 827 QuitCurrentMessageLoop())); | |
| 828 } | |
| 829 | |
| 830 // Declares an expectation that PersistentCookieStore::LoadCookiesForKey | |
| 831 // will be called, saving the provided callback and sending a quit to the | |
| 832 // message loop. | |
| 833 void ExpectLoadForKeyCall(std::string key, bool quit_queue) { | |
| 834 if (quit_queue) | |
| 835 EXPECT_CALL(*persistent_store_.get(), LoadCookiesForKey(key, testing::_)) | |
| 836 .WillOnce( | |
| 837 testing::DoAll(PushCallbackAction(&loaded_for_key_callbacks_), | |
| 838 QuitCurrentMessageLoop())); | |
| 839 else | |
| 840 EXPECT_CALL(*persistent_store_.get(), LoadCookiesForKey(key, testing::_)) | |
| 841 .WillOnce(PushCallbackAction(&loaded_for_key_callbacks_)); | |
| 842 } | |
| 843 | |
| 844 // Invokes the initial action. | |
| 845 MOCK_METHOD0(Begin, void(void)); | |
| 846 | |
| 847 // Returns the CookieMonster instance under test. | |
| 848 CookieMonster& cookie_monster() { return *cookie_monster_.get(); } | |
| 849 | |
| 850 private: | |
| 851 // Declares that mock expectations in this test suite are strictly ordered. | |
| 852 testing::InSequence in_sequence_; | |
| 853 // Holds cookies to be returned from PersistentCookieStore::Load or | |
| 854 // PersistentCookieStore::LoadCookiesForKey. | |
| 855 std::vector<CanonicalCookie*> loaded_cookies_; | |
| 856 // Stores the callback passed from the CookieMonster to the | |
| 857 // PersistentCookieStore::Load | |
| 858 CookieMonster::PersistentCookieStore::LoadedCallback loaded_callback_; | |
| 859 // Stores the callback passed from the CookieMonster to the | |
| 860 // PersistentCookieStore::LoadCookiesForKey | |
| 861 std::queue<CookieMonster::PersistentCookieStore::LoadedCallback> | |
| 862 loaded_for_key_callbacks_; | |
| 863 | |
| 864 // Stores the CookieMonster under test. | |
| 865 scoped_refptr<CookieMonster> cookie_monster_; | |
| 866 // Stores the mock PersistentCookieStore. | |
| 867 scoped_refptr<NewMockPersistentCookieStore> persistent_store_; | |
| 868 }; | |
| 869 | |
| 870 TEST_F(DeferredCookieTaskTest, DeferredGetCookies) { | |
| 871 DeclareLoadedCookie("www.google.izzle", | |
| 872 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
| 873 Time::Now() + TimeDelta::FromDays(3)); | |
| 874 | |
| 875 MockGetCookiesCallback get_cookies_callback; | |
| 876 | |
| 877 BeginWithForDomainKey("google.izzle", GetCookiesAction( | |
| 878 &cookie_monster(), url_google_, &get_cookies_callback)); | |
| 879 | |
| 880 WaitForLoadCall(); | |
| 881 | |
| 882 EXPECT_CALL(get_cookies_callback, Invoke("X=1")).WillOnce( | |
| 883 GetCookiesAction(&cookie_monster(), url_google_, &get_cookies_callback)); | |
| 884 EXPECT_CALL(get_cookies_callback, Invoke("X=1")).WillOnce( | |
| 885 QuitCurrentMessageLoop()); | |
| 886 | |
| 887 CompleteLoadingAndWait(); | |
| 888 } | |
| 889 | |
| 890 TEST_F(DeferredCookieTaskTest, DeferredSetCookie) { | |
| 891 MockSetCookiesCallback set_cookies_callback; | |
| 892 | |
| 893 BeginWithForDomainKey("google.izzle", SetCookieAction( | |
| 894 &cookie_monster(), url_google_, "A=B", &set_cookies_callback)); | |
| 895 | |
| 896 WaitForLoadCall(); | |
| 897 | |
| 898 EXPECT_CALL(set_cookies_callback, Invoke(true)).WillOnce( | |
| 899 SetCookieAction( | |
| 900 &cookie_monster(), url_google_, "X=Y", &set_cookies_callback)); | |
| 901 EXPECT_CALL(set_cookies_callback, Invoke(true)).WillOnce( | |
| 902 QuitCurrentMessageLoop()); | |
| 903 | |
| 904 CompleteLoadingAndWait(); | |
| 905 } | |
| 906 | |
| 907 TEST_F(DeferredCookieTaskTest, DeferredDeleteCookie) { | |
| 908 MockClosure delete_cookie_callback; | |
| 909 | |
| 910 BeginWithForDomainKey("google.izzle", DeleteCookieAction( | |
| 911 &cookie_monster(), url_google_, "A", &delete_cookie_callback)); | |
| 912 | |
| 913 WaitForLoadCall(); | |
| 914 | |
| 915 EXPECT_CALL(delete_cookie_callback, Invoke()).WillOnce( | |
| 916 DeleteCookieAction( | |
| 917 &cookie_monster(), url_google_, "X", &delete_cookie_callback)); | |
| 918 EXPECT_CALL(delete_cookie_callback, Invoke()).WillOnce( | |
| 919 QuitCurrentMessageLoop()); | |
| 920 | |
| 921 CompleteLoadingAndWait(); | |
| 922 } | |
| 923 | |
| 924 TEST_F(DeferredCookieTaskTest, DeferredSetCookieWithDetails) { | |
| 925 MockSetCookiesCallback set_cookies_callback; | |
| 926 | |
| 927 CookiesInputInfo cookie_info = { | |
| 928 url_google_foo_, "A", "B", std::string(), "/foo", | |
| 929 base::Time(), false, false, COOKIE_PRIORITY_DEFAULT | |
| 930 }; | |
| 931 BeginWithForDomainKey("google.izzle", SetCookieWithDetailsAction( | |
| 932 &cookie_monster(), cookie_info, &set_cookies_callback)); | |
| 933 | |
| 934 WaitForLoadCall(); | |
| 935 | |
| 936 CookiesInputInfo cookie_info_exp = { | |
| 937 url_google_foo_, "A", "B", std::string(), "/foo", | |
| 938 base::Time(), false, false, COOKIE_PRIORITY_DEFAULT | |
| 939 }; | |
| 940 EXPECT_CALL(set_cookies_callback, Invoke(true)).WillOnce( | |
| 941 SetCookieWithDetailsAction( | |
| 942 &cookie_monster(), cookie_info_exp, &set_cookies_callback)); | |
| 943 EXPECT_CALL(set_cookies_callback, Invoke(true)).WillOnce( | |
| 944 QuitCurrentMessageLoop()); | |
| 945 | |
| 946 CompleteLoadingAndWait(); | |
| 947 } | |
| 948 | |
| 949 TEST_F(DeferredCookieTaskTest, DeferredGetAllCookies) { | |
| 950 DeclareLoadedCookie("www.google.izzle", | |
| 951 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
| 952 Time::Now() + TimeDelta::FromDays(3)); | |
| 953 | |
| 954 MockGetCookieListCallback get_cookie_list_callback; | |
| 955 | |
| 956 BeginWith(GetAllCookiesAction( | |
| 957 &cookie_monster(), &get_cookie_list_callback)); | |
| 958 | |
| 959 WaitForLoadCall(); | |
| 960 | |
| 961 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce( | |
| 962 GetAllCookiesAction(&cookie_monster(), &get_cookie_list_callback)); | |
| 963 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce( | |
| 964 QuitCurrentMessageLoop()); | |
| 965 | |
| 966 CompleteLoadingAndWait(); | |
| 967 } | |
| 968 | |
| 969 TEST_F(DeferredCookieTaskTest, DeferredGetAllForUrlCookies) { | |
| 970 DeclareLoadedCookie("www.google.izzle", | |
| 971 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
| 972 Time::Now() + TimeDelta::FromDays(3)); | |
| 973 | |
| 974 MockGetCookieListCallback get_cookie_list_callback; | |
| 975 | |
| 976 BeginWithForDomainKey("google.izzle", GetAllCookiesForUrlAction( | |
| 977 &cookie_monster(), url_google_, &get_cookie_list_callback)); | |
| 978 | |
| 979 WaitForLoadCall(); | |
| 980 | |
| 981 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce( | |
| 982 GetAllCookiesForUrlAction( | |
| 983 &cookie_monster(), url_google_, &get_cookie_list_callback)); | |
| 984 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce( | |
| 985 QuitCurrentMessageLoop()); | |
| 986 | |
| 987 CompleteLoadingAndWait(); | |
| 988 } | |
| 989 | |
| 990 TEST_F(DeferredCookieTaskTest, DeferredGetAllForUrlWithOptionsCookies) { | |
| 991 DeclareLoadedCookie("www.google.izzle", | |
| 992 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
| 993 Time::Now() + TimeDelta::FromDays(3)); | |
| 994 | |
| 995 MockGetCookieListCallback get_cookie_list_callback; | |
| 996 | |
| 997 BeginWithForDomainKey("google.izzle", GetAllCookiesForUrlWithOptionsAction( | |
| 998 &cookie_monster(), url_google_, &get_cookie_list_callback)); | |
| 999 | |
| 1000 WaitForLoadCall(); | |
| 1001 | |
| 1002 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce( | |
| 1003 GetAllCookiesForUrlWithOptionsAction( | |
| 1004 &cookie_monster(), url_google_, &get_cookie_list_callback)); | |
| 1005 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce( | |
| 1006 QuitCurrentMessageLoop()); | |
| 1007 | |
| 1008 CompleteLoadingAndWait(); | |
| 1009 } | |
| 1010 | |
| 1011 TEST_F(DeferredCookieTaskTest, DeferredDeleteAllCookies) { | |
| 1012 MockDeleteCallback delete_callback; | |
| 1013 | |
| 1014 BeginWith(DeleteAllAction( | |
| 1015 &cookie_monster(), &delete_callback)); | |
| 1016 | |
| 1017 WaitForLoadCall(); | |
| 1018 | |
| 1019 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce( | |
| 1020 DeleteAllAction(&cookie_monster(), &delete_callback)); | |
| 1021 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce( | |
| 1022 QuitCurrentMessageLoop()); | |
| 1023 | |
| 1024 CompleteLoadingAndWait(); | |
| 1025 } | |
| 1026 | |
| 1027 TEST_F(DeferredCookieTaskTest, DeferredDeleteAllCreatedBetweenCookies) { | |
| 1028 MockDeleteCallback delete_callback; | |
| 1029 | |
| 1030 BeginWith(DeleteAllCreatedBetweenAction( | |
| 1031 &cookie_monster(), base::Time(), base::Time::Now(), &delete_callback)); | |
| 1032 | |
| 1033 WaitForLoadCall(); | |
| 1034 | |
| 1035 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce( | |
| 1036 DeleteAllCreatedBetweenAction( | |
| 1037 &cookie_monster(), base::Time(), base::Time::Now(), | |
| 1038 &delete_callback)); | |
| 1039 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce( | |
| 1040 QuitCurrentMessageLoop()); | |
| 1041 | |
| 1042 CompleteLoadingAndWait(); | |
| 1043 } | |
| 1044 | |
| 1045 TEST_F(DeferredCookieTaskTest, DeferredDeleteAllForHostCookies) { | |
| 1046 MockDeleteCallback delete_callback; | |
| 1047 | |
| 1048 BeginWithForDomainKey("google.izzle", DeleteAllForHostAction( | |
| 1049 &cookie_monster(), url_google_, &delete_callback)); | |
| 1050 | |
| 1051 WaitForLoadCall(); | |
| 1052 | |
| 1053 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce( | |
| 1054 DeleteAllForHostAction( | |
| 1055 &cookie_monster(), url_google_, &delete_callback)); | |
| 1056 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce( | |
| 1057 QuitCurrentMessageLoop()); | |
| 1058 | |
| 1059 CompleteLoadingAndWait(); | |
| 1060 } | |
| 1061 | |
| 1062 TEST_F(DeferredCookieTaskTest, DeferredDeleteCanonicalCookie) { | |
| 1063 std::vector<CanonicalCookie*> cookies; | |
| 1064 CanonicalCookie cookie = BuildCanonicalCookie( | |
| 1065 "www.google.com", "X=1; path=/", base::Time::Now()); | |
| 1066 | |
| 1067 MockDeleteCookieCallback delete_cookie_callback; | |
| 1068 | |
| 1069 BeginWith(DeleteCanonicalCookieAction( | |
| 1070 &cookie_monster(), cookie, &delete_cookie_callback)); | |
| 1071 | |
| 1072 WaitForLoadCall(); | |
| 1073 | |
| 1074 EXPECT_CALL(delete_cookie_callback, Invoke(false)).WillOnce( | |
| 1075 DeleteCanonicalCookieAction( | |
| 1076 &cookie_monster(), cookie, &delete_cookie_callback)); | |
| 1077 EXPECT_CALL(delete_cookie_callback, Invoke(false)).WillOnce( | |
| 1078 QuitCurrentMessageLoop()); | |
| 1079 | |
| 1080 CompleteLoadingAndWait(); | |
| 1081 } | |
| 1082 | |
| 1083 TEST_F(DeferredCookieTaskTest, DeferredDeleteSessionCookies) { | |
| 1084 MockDeleteCallback delete_callback; | |
| 1085 | |
| 1086 BeginWith(DeleteSessionCookiesAction( | |
| 1087 &cookie_monster(), &delete_callback)); | |
| 1088 | |
| 1089 WaitForLoadCall(); | |
| 1090 | |
| 1091 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce( | |
| 1092 DeleteSessionCookiesAction(&cookie_monster(), &delete_callback)); | |
| 1093 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce( | |
| 1094 QuitCurrentMessageLoop()); | |
| 1095 | |
| 1096 CompleteLoadingAndWait(); | |
| 1097 } | |
| 1098 | |
| 1099 // Verify that a series of queued tasks are executed in order upon loading of | |
| 1100 // the backing store and that new tasks received while the queued tasks are | |
| 1101 // being dispatched go to the end of the queue. | |
| 1102 TEST_F(DeferredCookieTaskTest, DeferredTaskOrder) { | |
| 1103 DeclareLoadedCookie("www.google.izzle", | |
| 1104 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
| 1105 Time::Now() + TimeDelta::FromDays(3)); | |
| 1106 | |
| 1107 MockGetCookiesCallback get_cookies_callback; | |
| 1108 MockSetCookiesCallback set_cookies_callback; | |
| 1109 MockGetCookiesCallback get_cookies_callback_deferred; | |
| 1110 | |
| 1111 EXPECT_CALL(*this, Begin()).WillOnce(testing::DoAll( | |
| 1112 GetCookiesAction( | |
| 1113 &cookie_monster(), url_google_, &get_cookies_callback), | |
| 1114 SetCookieAction( | |
| 1115 &cookie_monster(), url_google_, "A=B", &set_cookies_callback))); | |
| 1116 ExpectLoadCall(); | |
| 1117 ExpectLoadForKeyCall("google.izzle", false); | |
| 1118 Begin(); | |
| 1119 | |
| 1120 WaitForLoadCall(); | |
| 1121 EXPECT_CALL(get_cookies_callback, Invoke("X=1")).WillOnce( | |
| 1122 GetCookiesAction( | |
| 1123 &cookie_monster(), url_google_, &get_cookies_callback_deferred)); | |
| 1124 EXPECT_CALL(set_cookies_callback, Invoke(true)); | |
| 1125 EXPECT_CALL(get_cookies_callback_deferred, Invoke("A=B; X=1")).WillOnce( | |
| 1126 QuitCurrentMessageLoop()); | |
| 1127 | |
| 1128 CompleteLoadingAndWait(); | |
| 1129 } | |
| 1130 | |
| 1131 TEST_F(CookieMonsterTest, TestCookieDeleteAll) { | |
| 1132 scoped_refptr<MockPersistentCookieStore> store( | |
| 1133 new MockPersistentCookieStore); | |
| 1134 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL)); | |
| 1135 CookieOptions options; | |
| 1136 options.set_include_httponly(); | |
| 1137 | |
| 1138 EXPECT_TRUE(SetCookie(cm.get(), url_google_, kValidCookieLine)); | |
| 1139 EXPECT_EQ("A=B", GetCookies(cm.get(), url_google_)); | |
| 1140 | |
| 1141 EXPECT_TRUE( | |
| 1142 SetCookieWithOptions(cm.get(), url_google_, "C=D; httponly", options)); | |
| 1143 EXPECT_EQ("A=B; C=D", GetCookiesWithOptions(cm.get(), url_google_, options)); | |
| 1144 | |
| 1145 EXPECT_EQ(2, DeleteAll(cm.get())); | |
| 1146 EXPECT_EQ("", GetCookiesWithOptions(cm.get(), url_google_, options)); | |
| 1147 EXPECT_EQ(0u, store->commands().size()); | |
| 1148 | |
| 1149 // Create a persistent cookie. | |
| 1150 EXPECT_TRUE(SetCookie( | |
| 1151 cm.get(), | |
| 1152 url_google_, | |
| 1153 std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT")); | |
| 1154 ASSERT_EQ(1u, store->commands().size()); | |
| 1155 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type); | |
| 1156 | |
| 1157 EXPECT_EQ(1, DeleteAll(cm.get())); // sync_to_store = true. | |
| 1158 ASSERT_EQ(2u, store->commands().size()); | |
| 1159 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type); | |
| 1160 | |
| 1161 EXPECT_EQ("", GetCookiesWithOptions(cm.get(), url_google_, options)); | |
| 1162 } | |
| 1163 | |
| 1164 TEST_F(CookieMonsterTest, TestCookieDeleteAllCreatedBetweenTimestamps) { | |
| 1165 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 1166 Time now = Time::Now(); | |
| 1167 | |
| 1168 // Nothing has been added so nothing should be deleted. | |
| 1169 EXPECT_EQ( | |
| 1170 0, | |
| 1171 DeleteAllCreatedBetween(cm.get(), now - TimeDelta::FromDays(99), Time())); | |
| 1172 | |
| 1173 // Create 3 cookies with creation date of today, yesterday and the day before. | |
| 1174 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-0=Now", now)); | |
| 1175 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-1=Yesterday", | |
| 1176 now - TimeDelta::FromDays(1))); | |
| 1177 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-2=DayBefore", | |
| 1178 now - TimeDelta::FromDays(2))); | |
| 1179 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-3=ThreeDays", | |
| 1180 now - TimeDelta::FromDays(3))); | |
| 1181 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-7=LastWeek", | |
| 1182 now - TimeDelta::FromDays(7))); | |
| 1183 | |
| 1184 // Try to delete threedays and the daybefore. | |
| 1185 EXPECT_EQ(2, | |
| 1186 DeleteAllCreatedBetween(cm.get(), | |
| 1187 now - TimeDelta::FromDays(3), | |
| 1188 now - TimeDelta::FromDays(1))); | |
| 1189 | |
| 1190 // Try to delete yesterday, also make sure that delete_end is not | |
| 1191 // inclusive. | |
| 1192 EXPECT_EQ( | |
| 1193 1, DeleteAllCreatedBetween(cm.get(), now - TimeDelta::FromDays(2), now)); | |
| 1194 | |
| 1195 // Make sure the delete_begin is inclusive. | |
| 1196 EXPECT_EQ( | |
| 1197 1, DeleteAllCreatedBetween(cm.get(), now - TimeDelta::FromDays(7), now)); | |
| 1198 | |
| 1199 // Delete the last (now) item. | |
| 1200 EXPECT_EQ(1, DeleteAllCreatedBetween(cm.get(), Time(), Time())); | |
| 1201 | |
| 1202 // Really make sure everything is gone. | |
| 1203 EXPECT_EQ(0, DeleteAll(cm.get())); | |
| 1204 } | |
| 1205 | |
| 1206 static const int kAccessDelayMs = kLastAccessThresholdMilliseconds + 20; | |
| 1207 | |
| 1208 TEST_F(CookieMonsterTest, TestLastAccess) { | |
| 1209 scoped_refptr<CookieMonster> cm( | |
| 1210 new CookieMonster(NULL, NULL, kLastAccessThresholdMilliseconds)); | |
| 1211 | |
| 1212 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B")); | |
| 1213 const Time last_access_date(GetFirstCookieAccessDate(cm.get())); | |
| 1214 | |
| 1215 // Reading the cookie again immediately shouldn't update the access date, | |
| 1216 // since we're inside the threshold. | |
| 1217 EXPECT_EQ("A=B", GetCookies(cm.get(), url_google_)); | |
| 1218 EXPECT_TRUE(last_access_date == GetFirstCookieAccessDate(cm.get())); | |
| 1219 | |
| 1220 // Reading after a short wait should update the access date. | |
| 1221 base::PlatformThread::Sleep( | |
| 1222 base::TimeDelta::FromMilliseconds(kAccessDelayMs)); | |
| 1223 EXPECT_EQ("A=B", GetCookies(cm.get(), url_google_)); | |
| 1224 EXPECT_FALSE(last_access_date == GetFirstCookieAccessDate(cm.get())); | |
| 1225 } | |
| 1226 | |
| 1227 TEST_F(CookieMonsterTest, TestHostGarbageCollection) { | |
| 1228 TestHostGarbageCollectHelper(); | |
| 1229 } | |
| 1230 | |
| 1231 TEST_F(CookieMonsterTest, TestPriorityAwareGarbageCollection) { | |
| 1232 TestPriorityAwareGarbageCollectHelper(); | |
| 1233 } | |
| 1234 | |
| 1235 TEST_F(CookieMonsterTest, TestDeleteSingleCookie) { | |
| 1236 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 1237 | |
| 1238 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B")); | |
| 1239 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "C=D")); | |
| 1240 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "E=F")); | |
| 1241 EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm.get(), url_google_)); | |
| 1242 | |
| 1243 EXPECT_TRUE(FindAndDeleteCookie(cm.get(), url_google_.host(), "C")); | |
| 1244 EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), url_google_)); | |
| 1245 | |
| 1246 EXPECT_FALSE(FindAndDeleteCookie(cm.get(), "random.host", "E")); | |
| 1247 EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), url_google_)); | |
| 1248 } | |
| 1249 | |
| 1250 TEST_F(CookieMonsterTest, SetCookieableSchemes) { | |
| 1251 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 1252 scoped_refptr<CookieMonster> cm_foo(new CookieMonster(NULL, NULL)); | |
| 1253 | |
| 1254 // Only cm_foo should allow foo:// cookies. | |
| 1255 const char* const kSchemes[] = {"foo"}; | |
| 1256 cm_foo->SetCookieableSchemes(kSchemes, 1); | |
| 1257 | |
| 1258 GURL foo_url("foo://host/path"); | |
| 1259 GURL http_url("http://host/path"); | |
| 1260 | |
| 1261 EXPECT_TRUE(SetCookie(cm.get(), http_url, "x=1")); | |
| 1262 EXPECT_FALSE(SetCookie(cm.get(), foo_url, "x=1")); | |
| 1263 EXPECT_TRUE(SetCookie(cm_foo.get(), foo_url, "x=1")); | |
| 1264 EXPECT_FALSE(SetCookie(cm_foo.get(), http_url, "x=1")); | |
| 1265 } | |
| 1266 | |
| 1267 TEST_F(CookieMonsterTest, GetAllCookiesForURL) { | |
| 1268 scoped_refptr<CookieMonster> cm( | |
| 1269 new CookieMonster(NULL, NULL, kLastAccessThresholdMilliseconds)); | |
| 1270 | |
| 1271 // Create an httponly cookie. | |
| 1272 CookieOptions options; | |
| 1273 options.set_include_httponly(); | |
| 1274 | |
| 1275 EXPECT_TRUE( | |
| 1276 SetCookieWithOptions(cm.get(), url_google_, "A=B; httponly", options)); | |
| 1277 EXPECT_TRUE(SetCookieWithOptions( | |
| 1278 cm.get(), url_google_, "C=D; domain=.google.izzle", options)); | |
| 1279 EXPECT_TRUE(SetCookieWithOptions(cm.get(), | |
| 1280 url_google_secure_, | |
| 1281 "E=F; domain=.google.izzle; secure", | |
| 1282 options)); | |
| 1283 | |
| 1284 const Time last_access_date(GetFirstCookieAccessDate(cm.get())); | |
| 1285 | |
| 1286 base::PlatformThread::Sleep( | |
| 1287 base::TimeDelta::FromMilliseconds(kAccessDelayMs)); | |
| 1288 | |
| 1289 // Check cookies for url. | |
| 1290 CookieList cookies = GetAllCookiesForURL(cm.get(), url_google_); | |
| 1291 CookieList::iterator it = cookies.begin(); | |
| 1292 | |
| 1293 ASSERT_TRUE(it != cookies.end()); | |
| 1294 EXPECT_EQ("www.google.izzle", it->Domain()); | |
| 1295 EXPECT_EQ("A", it->Name()); | |
| 1296 | |
| 1297 ASSERT_TRUE(++it != cookies.end()); | |
| 1298 EXPECT_EQ(".google.izzle", it->Domain()); | |
| 1299 EXPECT_EQ("C", it->Name()); | |
| 1300 | |
| 1301 ASSERT_TRUE(++it == cookies.end()); | |
| 1302 | |
| 1303 // Check cookies for url excluding http-only cookies. | |
| 1304 cookies = | |
| 1305 GetAllCookiesForURLWithOptions(cm.get(), url_google_, CookieOptions()); | |
| 1306 it = cookies.begin(); | |
| 1307 | |
| 1308 ASSERT_TRUE(it != cookies.end()); | |
| 1309 EXPECT_EQ(".google.izzle", it->Domain()); | |
| 1310 EXPECT_EQ("C", it->Name()); | |
| 1311 | |
| 1312 ASSERT_TRUE(++it == cookies.end()); | |
| 1313 | |
| 1314 // Test secure cookies. | |
| 1315 cookies = GetAllCookiesForURL(cm.get(), url_google_secure_); | |
| 1316 it = cookies.begin(); | |
| 1317 | |
| 1318 ASSERT_TRUE(it != cookies.end()); | |
| 1319 EXPECT_EQ("www.google.izzle", it->Domain()); | |
| 1320 EXPECT_EQ("A", it->Name()); | |
| 1321 | |
| 1322 ASSERT_TRUE(++it != cookies.end()); | |
| 1323 EXPECT_EQ(".google.izzle", it->Domain()); | |
| 1324 EXPECT_EQ("C", it->Name()); | |
| 1325 | |
| 1326 ASSERT_TRUE(++it != cookies.end()); | |
| 1327 EXPECT_EQ(".google.izzle", it->Domain()); | |
| 1328 EXPECT_EQ("E", it->Name()); | |
| 1329 | |
| 1330 ASSERT_TRUE(++it == cookies.end()); | |
| 1331 | |
| 1332 // Reading after a short wait should not update the access date. | |
| 1333 EXPECT_TRUE(last_access_date == GetFirstCookieAccessDate(cm.get())); | |
| 1334 } | |
| 1335 | |
| 1336 TEST_F(CookieMonsterTest, GetAllCookiesForURLPathMatching) { | |
| 1337 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 1338 CookieOptions options; | |
| 1339 | |
| 1340 EXPECT_TRUE(SetCookieWithOptions( | |
| 1341 cm.get(), url_google_foo_, "A=B; path=/foo;", options)); | |
| 1342 EXPECT_TRUE(SetCookieWithOptions( | |
| 1343 cm.get(), url_google_bar_, "C=D; path=/bar;", options)); | |
| 1344 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "E=F;", options)); | |
| 1345 | |
| 1346 CookieList cookies = GetAllCookiesForURL(cm.get(), url_google_foo_); | |
| 1347 CookieList::iterator it = cookies.begin(); | |
| 1348 | |
| 1349 ASSERT_TRUE(it != cookies.end()); | |
| 1350 EXPECT_EQ("A", it->Name()); | |
| 1351 EXPECT_EQ("/foo", it->Path()); | |
| 1352 | |
| 1353 ASSERT_TRUE(++it != cookies.end()); | |
| 1354 EXPECT_EQ("E", it->Name()); | |
| 1355 EXPECT_EQ("/", it->Path()); | |
| 1356 | |
| 1357 ASSERT_TRUE(++it == cookies.end()); | |
| 1358 | |
| 1359 cookies = GetAllCookiesForURL(cm.get(), url_google_bar_); | |
| 1360 it = cookies.begin(); | |
| 1361 | |
| 1362 ASSERT_TRUE(it != cookies.end()); | |
| 1363 EXPECT_EQ("C", it->Name()); | |
| 1364 EXPECT_EQ("/bar", it->Path()); | |
| 1365 | |
| 1366 ASSERT_TRUE(++it != cookies.end()); | |
| 1367 EXPECT_EQ("E", it->Name()); | |
| 1368 EXPECT_EQ("/", it->Path()); | |
| 1369 | |
| 1370 ASSERT_TRUE(++it == cookies.end()); | |
| 1371 } | |
| 1372 | |
| 1373 TEST_F(CookieMonsterTest, DeleteCookieByName) { | |
| 1374 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 1375 | |
| 1376 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=A1; path=/")); | |
| 1377 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=A2; path=/foo")); | |
| 1378 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=A3; path=/bar")); | |
| 1379 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B1; path=/")); | |
| 1380 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B2; path=/foo")); | |
| 1381 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B3; path=/bar")); | |
| 1382 | |
| 1383 DeleteCookie(cm.get(), GURL(std::string(kUrlGoogle) + "/foo/bar"), "A"); | |
| 1384 | |
| 1385 CookieList cookies = GetAllCookies(cm.get()); | |
| 1386 size_t expected_size = 4; | |
| 1387 EXPECT_EQ(expected_size, cookies.size()); | |
| 1388 for (CookieList::iterator it = cookies.begin(); | |
| 1389 it != cookies.end(); ++it) { | |
| 1390 EXPECT_NE("A1", it->Value()); | |
| 1391 EXPECT_NE("A2", it->Value()); | |
| 1392 } | |
| 1393 } | |
| 1394 | |
| 1395 TEST_F(CookieMonsterTest, ImportCookiesFromCookieMonster) { | |
| 1396 scoped_refptr<CookieMonster> cm_1(new CookieMonster(NULL, NULL)); | |
| 1397 CookieOptions options; | |
| 1398 | |
| 1399 EXPECT_TRUE(SetCookieWithOptions(cm_1.get(), url_google_foo_, | |
| 1400 "A1=B; path=/foo;", | |
| 1401 options)); | |
| 1402 EXPECT_TRUE(SetCookieWithOptions(cm_1.get(), url_google_bar_, | |
| 1403 "A2=D; path=/bar;", | |
| 1404 options)); | |
| 1405 EXPECT_TRUE(SetCookieWithOptions(cm_1.get(), url_google_, | |
| 1406 "A3=F;", | |
| 1407 options)); | |
| 1408 | |
| 1409 CookieList cookies_1 = GetAllCookies(cm_1.get()); | |
| 1410 scoped_refptr<CookieMonster> cm_2(new CookieMonster(NULL, NULL)); | |
| 1411 ASSERT_TRUE(cm_2->ImportCookies(cookies_1)); | |
| 1412 CookieList cookies_2 = GetAllCookies(cm_2.get()); | |
| 1413 | |
| 1414 size_t expected_size = 3; | |
| 1415 EXPECT_EQ(expected_size, cookies_2.size()); | |
| 1416 | |
| 1417 CookieList::iterator it = cookies_2.begin(); | |
| 1418 | |
| 1419 ASSERT_TRUE(it != cookies_2.end()); | |
| 1420 EXPECT_EQ("A1", it->Name()); | |
| 1421 EXPECT_EQ("/foo", it->Path()); | |
| 1422 | |
| 1423 ASSERT_TRUE(++it != cookies_2.end()); | |
| 1424 EXPECT_EQ("A2", it->Name()); | |
| 1425 EXPECT_EQ("/bar", it->Path()); | |
| 1426 | |
| 1427 ASSERT_TRUE(++it != cookies_2.end()); | |
| 1428 EXPECT_EQ("A3", it->Name()); | |
| 1429 EXPECT_EQ("/", it->Path()); | |
| 1430 } | |
| 1431 | |
| 1432 // Tests importing from a persistent cookie store that contains duplicate | |
| 1433 // equivalent cookies. This situation should be handled by removing the | |
| 1434 // duplicate cookie (both from the in-memory cache, and from the backing store). | |
| 1435 // | |
| 1436 // This is a regression test for: http://crbug.com/17855. | |
| 1437 TEST_F(CookieMonsterTest, DontImportDuplicateCookies) { | |
| 1438 scoped_refptr<MockPersistentCookieStore> store( | |
| 1439 new MockPersistentCookieStore); | |
| 1440 | |
| 1441 // We will fill some initial cookies into the PersistentCookieStore, | |
| 1442 // to simulate a database with 4 duplicates. Note that we need to | |
| 1443 // be careful not to have any duplicate creation times at all (as it's a | |
| 1444 // violation of a CookieMonster invariant) even if Time::Now() doesn't | |
| 1445 // move between calls. | |
| 1446 std::vector<CanonicalCookie*> initial_cookies; | |
| 1447 | |
| 1448 // Insert 4 cookies with name "X" on path "/", with varying creation | |
| 1449 // dates. We expect only the most recent one to be preserved following | |
| 1450 // the import. | |
| 1451 | |
| 1452 AddCookieToList("www.google.com", | |
| 1453 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
| 1454 Time::Now() + TimeDelta::FromDays(3), | |
| 1455 &initial_cookies); | |
| 1456 | |
| 1457 AddCookieToList("www.google.com", | |
| 1458 "X=2; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
| 1459 Time::Now() + TimeDelta::FromDays(1), | |
| 1460 &initial_cookies); | |
| 1461 | |
| 1462 // ===> This one is the WINNER (biggest creation time). <==== | |
| 1463 AddCookieToList("www.google.com", | |
| 1464 "X=3; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
| 1465 Time::Now() + TimeDelta::FromDays(4), | |
| 1466 &initial_cookies); | |
| 1467 | |
| 1468 AddCookieToList("www.google.com", | |
| 1469 "X=4; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
| 1470 Time::Now(), | |
| 1471 &initial_cookies); | |
| 1472 | |
| 1473 // Insert 2 cookies with name "X" on path "/2", with varying creation | |
| 1474 // dates. We expect only the most recent one to be preserved the import. | |
| 1475 | |
| 1476 // ===> This one is the WINNER (biggest creation time). <==== | |
| 1477 AddCookieToList("www.google.com", | |
| 1478 "X=a1; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
| 1479 Time::Now() + TimeDelta::FromDays(9), | |
| 1480 &initial_cookies); | |
| 1481 | |
| 1482 AddCookieToList("www.google.com", | |
| 1483 "X=a2; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
| 1484 Time::Now() + TimeDelta::FromDays(2), | |
| 1485 &initial_cookies); | |
| 1486 | |
| 1487 // Insert 1 cookie with name "Y" on path "/". | |
| 1488 AddCookieToList("www.google.com", | |
| 1489 "Y=a; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
| 1490 Time::Now() + TimeDelta::FromDays(10), | |
| 1491 &initial_cookies); | |
| 1492 | |
| 1493 // Inject our initial cookies into the mock PersistentCookieStore. | |
| 1494 store->SetLoadExpectation(true, initial_cookies); | |
| 1495 | |
| 1496 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL)); | |
| 1497 | |
| 1498 // Verify that duplicates were not imported for path "/". | |
| 1499 // (If this had failed, GetCookies() would have also returned X=1, X=2, X=4). | |
| 1500 EXPECT_EQ("X=3; Y=a", GetCookies(cm.get(), GURL("http://www.google.com/"))); | |
| 1501 | |
| 1502 // Verify that same-named cookie on a different path ("/x2") didn't get | |
| 1503 // messed up. | |
| 1504 EXPECT_EQ("X=a1; X=3; Y=a", | |
| 1505 GetCookies(cm.get(), GURL("http://www.google.com/2/x"))); | |
| 1506 | |
| 1507 // Verify that the PersistentCookieStore was told to kill its 4 duplicates. | |
| 1508 ASSERT_EQ(4u, store->commands().size()); | |
| 1509 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[0].type); | |
| 1510 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type); | |
| 1511 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[2].type); | |
| 1512 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type); | |
| 1513 } | |
| 1514 | |
| 1515 // Tests importing from a persistent cookie store that contains cookies | |
| 1516 // with duplicate creation times. This situation should be handled by | |
| 1517 // dropping the cookies before insertion/visibility to user. | |
| 1518 // | |
| 1519 // This is a regression test for: http://crbug.com/43188. | |
| 1520 TEST_F(CookieMonsterTest, DontImportDuplicateCreationTimes) { | |
| 1521 scoped_refptr<MockPersistentCookieStore> store( | |
| 1522 new MockPersistentCookieStore); | |
| 1523 | |
| 1524 Time now(Time::Now()); | |
| 1525 Time earlier(now - TimeDelta::FromDays(1)); | |
| 1526 | |
| 1527 // Insert 8 cookies, four with the current time as creation times, and | |
| 1528 // four with the earlier time as creation times. We should only get | |
| 1529 // two cookies remaining, but which two (other than that there should | |
| 1530 // be one from each set) will be random. | |
| 1531 std::vector<CanonicalCookie*> initial_cookies; | |
| 1532 AddCookieToList("www.google.com", "X=1; path=/", now, &initial_cookies); | |
| 1533 AddCookieToList("www.google.com", "X=2; path=/", now, &initial_cookies); | |
| 1534 AddCookieToList("www.google.com", "X=3; path=/", now, &initial_cookies); | |
| 1535 AddCookieToList("www.google.com", "X=4; path=/", now, &initial_cookies); | |
| 1536 | |
| 1537 AddCookieToList("www.google.com", "Y=1; path=/", earlier, &initial_cookies); | |
| 1538 AddCookieToList("www.google.com", "Y=2; path=/", earlier, &initial_cookies); | |
| 1539 AddCookieToList("www.google.com", "Y=3; path=/", earlier, &initial_cookies); | |
| 1540 AddCookieToList("www.google.com", "Y=4; path=/", earlier, &initial_cookies); | |
| 1541 | |
| 1542 // Inject our initial cookies into the mock PersistentCookieStore. | |
| 1543 store->SetLoadExpectation(true, initial_cookies); | |
| 1544 | |
| 1545 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL)); | |
| 1546 | |
| 1547 CookieList list(GetAllCookies(cm.get())); | |
| 1548 EXPECT_EQ(2U, list.size()); | |
| 1549 // Confirm that we have one of each. | |
| 1550 std::string name1(list[0].Name()); | |
| 1551 std::string name2(list[1].Name()); | |
| 1552 EXPECT_TRUE(name1 == "X" || name2 == "X"); | |
| 1553 EXPECT_TRUE(name1 == "Y" || name2 == "Y"); | |
| 1554 EXPECT_NE(name1, name2); | |
| 1555 } | |
| 1556 | |
| 1557 TEST_F(CookieMonsterTest, CookieMonsterDelegate) { | |
| 1558 scoped_refptr<MockPersistentCookieStore> store( | |
| 1559 new MockPersistentCookieStore); | |
| 1560 scoped_refptr<MockCookieMonsterDelegate> delegate( | |
| 1561 new MockCookieMonsterDelegate); | |
| 1562 scoped_refptr<CookieMonster> cm( | |
| 1563 new CookieMonster(store.get(), delegate.get())); | |
| 1564 | |
| 1565 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B")); | |
| 1566 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "C=D")); | |
| 1567 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "E=F")); | |
| 1568 EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm.get(), url_google_)); | |
| 1569 ASSERT_EQ(3u, delegate->changes().size()); | |
| 1570 EXPECT_FALSE(delegate->changes()[0].second); | |
| 1571 EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain()); | |
| 1572 EXPECT_EQ("A", delegate->changes()[0].first.Name()); | |
| 1573 EXPECT_EQ("B", delegate->changes()[0].first.Value()); | |
| 1574 EXPECT_EQ(url_google_.host(), delegate->changes()[1].first.Domain()); | |
| 1575 EXPECT_FALSE(delegate->changes()[1].second); | |
| 1576 EXPECT_EQ("C", delegate->changes()[1].first.Name()); | |
| 1577 EXPECT_EQ("D", delegate->changes()[1].first.Value()); | |
| 1578 EXPECT_EQ(url_google_.host(), delegate->changes()[2].first.Domain()); | |
| 1579 EXPECT_FALSE(delegate->changes()[2].second); | |
| 1580 EXPECT_EQ("E", delegate->changes()[2].first.Name()); | |
| 1581 EXPECT_EQ("F", delegate->changes()[2].first.Value()); | |
| 1582 delegate->reset(); | |
| 1583 | |
| 1584 EXPECT_TRUE(FindAndDeleteCookie(cm.get(), url_google_.host(), "C")); | |
| 1585 EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), url_google_)); | |
| 1586 ASSERT_EQ(1u, delegate->changes().size()); | |
| 1587 EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain()); | |
| 1588 EXPECT_TRUE(delegate->changes()[0].second); | |
| 1589 EXPECT_EQ("C", delegate->changes()[0].first.Name()); | |
| 1590 EXPECT_EQ("D", delegate->changes()[0].first.Value()); | |
| 1591 delegate->reset(); | |
| 1592 | |
| 1593 EXPECT_FALSE(FindAndDeleteCookie(cm.get(), "random.host", "E")); | |
| 1594 EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), url_google_)); | |
| 1595 EXPECT_EQ(0u, delegate->changes().size()); | |
| 1596 | |
| 1597 // Insert a cookie "a" for path "/path1" | |
| 1598 EXPECT_TRUE(SetCookie(cm.get(), | |
| 1599 url_google_, | |
| 1600 "a=val1; path=/path1; " | |
| 1601 "expires=Mon, 18-Apr-22 22:50:13 GMT")); | |
| 1602 ASSERT_EQ(1u, store->commands().size()); | |
| 1603 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type); | |
| 1604 ASSERT_EQ(1u, delegate->changes().size()); | |
| 1605 EXPECT_FALSE(delegate->changes()[0].second); | |
| 1606 EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain()); | |
| 1607 EXPECT_EQ("a", delegate->changes()[0].first.Name()); | |
| 1608 EXPECT_EQ("val1", delegate->changes()[0].first.Value()); | |
| 1609 delegate->reset(); | |
| 1610 | |
| 1611 // Insert a cookie "a" for path "/path1", that is httponly. This should | |
| 1612 // overwrite the non-http-only version. | |
| 1613 CookieOptions allow_httponly; | |
| 1614 allow_httponly.set_include_httponly(); | |
| 1615 EXPECT_TRUE(SetCookieWithOptions(cm.get(), | |
| 1616 url_google_, | |
| 1617 "a=val2; path=/path1; httponly; " | |
| 1618 "expires=Mon, 18-Apr-22 22:50:14 GMT", | |
| 1619 allow_httponly)); | |
| 1620 ASSERT_EQ(3u, store->commands().size()); | |
| 1621 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type); | |
| 1622 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type); | |
| 1623 ASSERT_EQ(2u, delegate->changes().size()); | |
| 1624 EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain()); | |
| 1625 EXPECT_TRUE(delegate->changes()[0].second); | |
| 1626 EXPECT_EQ("a", delegate->changes()[0].first.Name()); | |
| 1627 EXPECT_EQ("val1", delegate->changes()[0].first.Value()); | |
| 1628 EXPECT_EQ(url_google_.host(), delegate->changes()[1].first.Domain()); | |
| 1629 EXPECT_FALSE(delegate->changes()[1].second); | |
| 1630 EXPECT_EQ("a", delegate->changes()[1].first.Name()); | |
| 1631 EXPECT_EQ("val2", delegate->changes()[1].first.Value()); | |
| 1632 delegate->reset(); | |
| 1633 } | |
| 1634 | |
| 1635 TEST_F(CookieMonsterTest, SetCookieWithDetails) { | |
| 1636 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 1637 | |
| 1638 EXPECT_TRUE(SetCookieWithDetails(cm.get(), | |
| 1639 url_google_foo_, | |
| 1640 "A", | |
| 1641 "B", | |
| 1642 std::string(), | |
| 1643 "/foo", | |
| 1644 base::Time(), | |
| 1645 false, | |
| 1646 false, | |
| 1647 COOKIE_PRIORITY_DEFAULT)); | |
| 1648 EXPECT_TRUE(SetCookieWithDetails(cm.get(), | |
| 1649 url_google_bar_, | |
| 1650 "C", | |
| 1651 "D", | |
| 1652 "google.izzle", | |
| 1653 "/bar", | |
| 1654 base::Time(), | |
| 1655 false, | |
| 1656 true, | |
| 1657 COOKIE_PRIORITY_DEFAULT)); | |
| 1658 EXPECT_TRUE(SetCookieWithDetails(cm.get(), | |
| 1659 url_google_, | |
| 1660 "E", | |
| 1661 "F", | |
| 1662 std::string(), | |
| 1663 std::string(), | |
| 1664 base::Time(), | |
| 1665 true, | |
| 1666 false, | |
| 1667 COOKIE_PRIORITY_DEFAULT)); | |
| 1668 | |
| 1669 // Test that malformed attributes fail to set the cookie. | |
| 1670 EXPECT_FALSE(SetCookieWithDetails(cm.get(), | |
| 1671 url_google_foo_, | |
| 1672 " A", | |
| 1673 "B", | |
| 1674 std::string(), | |
| 1675 "/foo", | |
| 1676 base::Time(), | |
| 1677 false, | |
| 1678 false, | |
| 1679 COOKIE_PRIORITY_DEFAULT)); | |
| 1680 EXPECT_FALSE(SetCookieWithDetails(cm.get(), | |
| 1681 url_google_foo_, | |
| 1682 "A;", | |
| 1683 "B", | |
| 1684 std::string(), | |
| 1685 "/foo", | |
| 1686 base::Time(), | |
| 1687 false, | |
| 1688 false, | |
| 1689 COOKIE_PRIORITY_DEFAULT)); | |
| 1690 EXPECT_FALSE(SetCookieWithDetails(cm.get(), | |
| 1691 url_google_foo_, | |
| 1692 "A=", | |
| 1693 "B", | |
| 1694 std::string(), | |
| 1695 "/foo", | |
| 1696 base::Time(), | |
| 1697 false, | |
| 1698 false, | |
| 1699 COOKIE_PRIORITY_DEFAULT)); | |
| 1700 EXPECT_FALSE(SetCookieWithDetails(cm.get(), | |
| 1701 url_google_foo_, | |
| 1702 "A", | |
| 1703 "B", | |
| 1704 "google.ozzzzzzle", | |
| 1705 "foo", | |
| 1706 base::Time(), | |
| 1707 false, | |
| 1708 false, | |
| 1709 COOKIE_PRIORITY_DEFAULT)); | |
| 1710 EXPECT_FALSE(SetCookieWithDetails(cm.get(), | |
| 1711 url_google_foo_, | |
| 1712 "A=", | |
| 1713 "B", | |
| 1714 std::string(), | |
| 1715 "foo", | |
| 1716 base::Time(), | |
| 1717 false, | |
| 1718 false, | |
| 1719 COOKIE_PRIORITY_DEFAULT)); | |
| 1720 | |
| 1721 CookieList cookies = GetAllCookiesForURL(cm.get(), url_google_foo_); | |
| 1722 CookieList::iterator it = cookies.begin(); | |
| 1723 | |
| 1724 ASSERT_TRUE(it != cookies.end()); | |
| 1725 EXPECT_EQ("A", it->Name()); | |
| 1726 EXPECT_EQ("B", it->Value()); | |
| 1727 EXPECT_EQ("www.google.izzle", it->Domain()); | |
| 1728 EXPECT_EQ("/foo", it->Path()); | |
| 1729 EXPECT_FALSE(it->IsPersistent()); | |
| 1730 EXPECT_FALSE(it->IsSecure()); | |
| 1731 EXPECT_FALSE(it->IsHttpOnly()); | |
| 1732 | |
| 1733 ASSERT_TRUE(++it == cookies.end()); | |
| 1734 | |
| 1735 cookies = GetAllCookiesForURL(cm.get(), url_google_bar_); | |
| 1736 it = cookies.begin(); | |
| 1737 | |
| 1738 ASSERT_TRUE(it != cookies.end()); | |
| 1739 EXPECT_EQ("C", it->Name()); | |
| 1740 EXPECT_EQ("D", it->Value()); | |
| 1741 EXPECT_EQ(".google.izzle", it->Domain()); | |
| 1742 EXPECT_EQ("/bar", it->Path()); | |
| 1743 EXPECT_FALSE(it->IsSecure()); | |
| 1744 EXPECT_TRUE(it->IsHttpOnly()); | |
| 1745 | |
| 1746 ASSERT_TRUE(++it == cookies.end()); | |
| 1747 | |
| 1748 cookies = GetAllCookiesForURL(cm.get(), url_google_secure_); | |
| 1749 it = cookies.begin(); | |
| 1750 | |
| 1751 ASSERT_TRUE(it != cookies.end()); | |
| 1752 EXPECT_EQ("E", it->Name()); | |
| 1753 EXPECT_EQ("F", it->Value()); | |
| 1754 EXPECT_EQ("/", it->Path()); | |
| 1755 EXPECT_EQ("www.google.izzle", it->Domain()); | |
| 1756 EXPECT_TRUE(it->IsSecure()); | |
| 1757 EXPECT_FALSE(it->IsHttpOnly()); | |
| 1758 | |
| 1759 ASSERT_TRUE(++it == cookies.end()); | |
| 1760 } | |
| 1761 | |
| 1762 TEST_F(CookieMonsterTest, DeleteAllForHost) { | |
| 1763 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 1764 | |
| 1765 // Test probes: | |
| 1766 // * Non-secure URL, mid-level (http://w.c.b.a) | |
| 1767 // * Secure URL, mid-level (https://w.c.b.a) | |
| 1768 // * URL with path, mid-level (https:/w.c.b.a/dir1/xx) | |
| 1769 // All three tests should nuke only the midlevel host cookie, | |
| 1770 // the http_only cookie, the host secure cookie, and the two host | |
| 1771 // path cookies. http_only, secure, and paths are ignored by | |
| 1772 // this call, and domain cookies arent touched. | |
| 1773 PopulateCmForDeleteAllForHost(cm); | |
| 1774 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X", | |
| 1775 GetCookies(cm.get(), GURL(kTopLevelDomainPlus3))); | |
| 1776 EXPECT_EQ("dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X", | |
| 1777 GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure))); | |
| 1778 EXPECT_EQ("dom_1=X; host_1=X", | |
| 1779 GetCookies(cm.get(), GURL(kTopLevelDomainPlus1))); | |
| 1780 EXPECT_EQ("dom_path_2=X; host_path_2=X; dom_path_1=X; host_path_1=X; " | |
| 1781 "dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X", | |
| 1782 GetCookies(cm.get(), | |
| 1783 GURL(kTopLevelDomainPlus2Secure + | |
| 1784 std::string("/dir1/dir2/xxx")))); | |
| 1785 | |
| 1786 EXPECT_EQ(5, DeleteAllForHost(cm.get(), GURL(kTopLevelDomainPlus2))); | |
| 1787 EXPECT_EQ(8U, GetAllCookies(cm.get()).size()); | |
| 1788 | |
| 1789 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X", | |
| 1790 GetCookies(cm.get(), GURL(kTopLevelDomainPlus3))); | |
| 1791 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X", | |
| 1792 GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure))); | |
| 1793 EXPECT_EQ("dom_1=X; host_1=X", | |
| 1794 GetCookies(cm.get(), GURL(kTopLevelDomainPlus1))); | |
| 1795 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X", | |
| 1796 GetCookies(cm.get(), | |
| 1797 GURL(kTopLevelDomainPlus2Secure + | |
| 1798 std::string("/dir1/dir2/xxx")))); | |
| 1799 | |
| 1800 PopulateCmForDeleteAllForHost(cm); | |
| 1801 EXPECT_EQ(5, DeleteAllForHost(cm.get(), GURL(kTopLevelDomainPlus2Secure))); | |
| 1802 EXPECT_EQ(8U, GetAllCookies(cm.get()).size()); | |
| 1803 | |
| 1804 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X", | |
| 1805 GetCookies(cm.get(), GURL(kTopLevelDomainPlus3))); | |
| 1806 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X", | |
| 1807 GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure))); | |
| 1808 EXPECT_EQ("dom_1=X; host_1=X", | |
| 1809 GetCookies(cm.get(), GURL(kTopLevelDomainPlus1))); | |
| 1810 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X", | |
| 1811 GetCookies(cm.get(), | |
| 1812 GURL(kTopLevelDomainPlus2Secure + | |
| 1813 std::string("/dir1/dir2/xxx")))); | |
| 1814 | |
| 1815 PopulateCmForDeleteAllForHost(cm); | |
| 1816 EXPECT_EQ(5, | |
| 1817 DeleteAllForHost( | |
| 1818 cm.get(), | |
| 1819 GURL(kTopLevelDomainPlus2Secure + std::string("/dir1/xxx")))); | |
| 1820 EXPECT_EQ(8U, GetAllCookies(cm.get()).size()); | |
| 1821 | |
| 1822 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X", | |
| 1823 GetCookies(cm.get(), GURL(kTopLevelDomainPlus3))); | |
| 1824 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X", | |
| 1825 GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure))); | |
| 1826 EXPECT_EQ("dom_1=X; host_1=X", | |
| 1827 GetCookies(cm.get(), GURL(kTopLevelDomainPlus1))); | |
| 1828 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X", | |
| 1829 GetCookies(cm.get(), | |
| 1830 GURL(kTopLevelDomainPlus2Secure + | |
| 1831 std::string("/dir1/dir2/xxx")))); | |
| 1832 } | |
| 1833 | |
| 1834 TEST_F(CookieMonsterTest, UniqueCreationTime) { | |
| 1835 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 1836 CookieOptions options; | |
| 1837 | |
| 1838 // Add in three cookies through every public interface to the | |
| 1839 // CookieMonster and confirm that none of them have duplicate | |
| 1840 // creation times. | |
| 1841 | |
| 1842 // SetCookieWithCreationTime and SetCookieWithCreationTimeAndOptions | |
| 1843 // are not included as they aren't going to be public for very much | |
| 1844 // longer. | |
| 1845 | |
| 1846 // SetCookie, SetCookieWithOptions, SetCookieWithDetails | |
| 1847 | |
| 1848 SetCookie(cm.get(), url_google_, "SetCookie1=A"); | |
| 1849 SetCookie(cm.get(), url_google_, "SetCookie2=A"); | |
| 1850 SetCookie(cm.get(), url_google_, "SetCookie3=A"); | |
| 1851 | |
| 1852 SetCookieWithOptions( | |
| 1853 cm.get(), url_google_, "setCookieWithOptions1=A", options); | |
| 1854 SetCookieWithOptions( | |
| 1855 cm.get(), url_google_, "setCookieWithOptions2=A", options); | |
| 1856 SetCookieWithOptions( | |
| 1857 cm.get(), url_google_, "setCookieWithOptions3=A", options); | |
| 1858 | |
| 1859 SetCookieWithDetails(cm.get(), | |
| 1860 url_google_, | |
| 1861 "setCookieWithDetails1", | |
| 1862 "A", | |
| 1863 ".google.com", | |
| 1864 "/", | |
| 1865 Time(), | |
| 1866 false, | |
| 1867 false, | |
| 1868 COOKIE_PRIORITY_DEFAULT); | |
| 1869 SetCookieWithDetails(cm.get(), | |
| 1870 url_google_, | |
| 1871 "setCookieWithDetails2", | |
| 1872 "A", | |
| 1873 ".google.com", | |
| 1874 "/", | |
| 1875 Time(), | |
| 1876 false, | |
| 1877 false, | |
| 1878 COOKIE_PRIORITY_DEFAULT); | |
| 1879 SetCookieWithDetails(cm.get(), | |
| 1880 url_google_, | |
| 1881 "setCookieWithDetails3", | |
| 1882 "A", | |
| 1883 ".google.com", | |
| 1884 "/", | |
| 1885 Time(), | |
| 1886 false, | |
| 1887 false, | |
| 1888 COOKIE_PRIORITY_DEFAULT); | |
| 1889 | |
| 1890 // Now we check | |
| 1891 CookieList cookie_list(GetAllCookies(cm.get())); | |
| 1892 typedef std::map<int64, CanonicalCookie> TimeCookieMap; | |
| 1893 TimeCookieMap check_map; | |
| 1894 for (CookieList::const_iterator it = cookie_list.begin(); | |
| 1895 it != cookie_list.end(); it++) { | |
| 1896 const int64 creation_date = it->CreationDate().ToInternalValue(); | |
| 1897 TimeCookieMap::const_iterator | |
| 1898 existing_cookie_it(check_map.find(creation_date)); | |
| 1899 EXPECT_TRUE(existing_cookie_it == check_map.end()) | |
| 1900 << "Cookie " << it->Name() << " has same creation date (" | |
| 1901 << it->CreationDate().ToInternalValue() | |
| 1902 << ") as previously entered cookie " | |
| 1903 << existing_cookie_it->second.Name(); | |
| 1904 | |
| 1905 if (existing_cookie_it == check_map.end()) { | |
| 1906 check_map.insert(TimeCookieMap::value_type( | |
| 1907 it->CreationDate().ToInternalValue(), *it)); | |
| 1908 } | |
| 1909 } | |
| 1910 } | |
| 1911 | |
| 1912 // Mainly a test of GetEffectiveDomain, or more specifically, of the | |
| 1913 // expected behavior of GetEffectiveDomain within the CookieMonster. | |
| 1914 TEST_F(CookieMonsterTest, GetKey) { | |
| 1915 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 1916 | |
| 1917 // This test is really only interesting if GetKey() actually does something. | |
| 1918 EXPECT_EQ("google.com", cm->GetKey("www.google.com")); | |
| 1919 EXPECT_EQ("google.izzie", cm->GetKey("www.google.izzie")); | |
| 1920 EXPECT_EQ("google.izzie", cm->GetKey(".google.izzie")); | |
| 1921 EXPECT_EQ("bbc.co.uk", cm->GetKey("bbc.co.uk")); | |
| 1922 EXPECT_EQ("bbc.co.uk", cm->GetKey("a.b.c.d.bbc.co.uk")); | |
| 1923 EXPECT_EQ("apple.com", cm->GetKey("a.b.c.d.apple.com")); | |
| 1924 EXPECT_EQ("apple.izzie", cm->GetKey("a.b.c.d.apple.izzie")); | |
| 1925 | |
| 1926 // Cases where the effective domain is null, so we use the host | |
| 1927 // as the key. | |
| 1928 EXPECT_EQ("co.uk", cm->GetKey("co.uk")); | |
| 1929 const std::string extension_name("iehocdgbbocmkdidlbnnfbmbinnahbae"); | |
| 1930 EXPECT_EQ(extension_name, cm->GetKey(extension_name)); | |
| 1931 EXPECT_EQ("com", cm->GetKey("com")); | |
| 1932 EXPECT_EQ("hostalias", cm->GetKey("hostalias")); | |
| 1933 EXPECT_EQ("localhost", cm->GetKey("localhost")); | |
| 1934 } | |
| 1935 | |
| 1936 // Test that cookies transfer from/to the backing store correctly. | |
| 1937 TEST_F(CookieMonsterTest, BackingStoreCommunication) { | |
| 1938 // Store details for cookies transforming through the backing store interface. | |
| 1939 | |
| 1940 base::Time current(base::Time::Now()); | |
| 1941 scoped_refptr<MockSimplePersistentCookieStore> store( | |
| 1942 new MockSimplePersistentCookieStore); | |
| 1943 base::Time new_access_time; | |
| 1944 base::Time expires(base::Time::Now() + base::TimeDelta::FromSeconds(100)); | |
| 1945 | |
| 1946 const CookiesInputInfo input_info[] = { | |
| 1947 {GURL("http://a.b.google.com"), "a", "1", "", "/path/to/cookie", expires, | |
| 1948 false, false, COOKIE_PRIORITY_DEFAULT}, | |
| 1949 {GURL("https://www.google.com"), "b", "2", ".google.com", | |
| 1950 "/path/from/cookie", expires + TimeDelta::FromSeconds(10), | |
| 1951 true, true, COOKIE_PRIORITY_DEFAULT}, | |
| 1952 {GURL("https://google.com"), "c", "3", "", "/another/path/to/cookie", | |
| 1953 base::Time::Now() + base::TimeDelta::FromSeconds(100), | |
| 1954 true, false, COOKIE_PRIORITY_DEFAULT} | |
| 1955 }; | |
| 1956 const int INPUT_DELETE = 1; | |
| 1957 | |
| 1958 // Create new cookies and flush them to the store. | |
| 1959 { | |
| 1960 scoped_refptr<CookieMonster> cmout(new CookieMonster(store.get(), NULL)); | |
| 1961 for (const CookiesInputInfo* p = input_info; | |
| 1962 p < &input_info[arraysize(input_info)]; | |
| 1963 p++) { | |
| 1964 EXPECT_TRUE(SetCookieWithDetails(cmout.get(), | |
| 1965 p->url, | |
| 1966 p->name, | |
| 1967 p->value, | |
| 1968 p->domain, | |
| 1969 p->path, | |
| 1970 p->expiration_time, | |
| 1971 p->secure, | |
| 1972 p->http_only, | |
| 1973 p->priority)); | |
| 1974 } | |
| 1975 GURL del_url(input_info[INPUT_DELETE].url.Resolve( | |
| 1976 input_info[INPUT_DELETE].path).spec()); | |
| 1977 DeleteCookie(cmout.get(), del_url, input_info[INPUT_DELETE].name); | |
| 1978 } | |
| 1979 | |
| 1980 // Create a new cookie monster and make sure that everything is correct | |
| 1981 { | |
| 1982 scoped_refptr<CookieMonster> cmin(new CookieMonster(store.get(), NULL)); | |
| 1983 CookieList cookies(GetAllCookies(cmin.get())); | |
| 1984 ASSERT_EQ(2u, cookies.size()); | |
| 1985 // Ordering is path length, then creation time. So second cookie | |
| 1986 // will come first, and we need to swap them. | |
| 1987 std::swap(cookies[0], cookies[1]); | |
| 1988 for (int output_index = 0; output_index < 2; output_index++) { | |
| 1989 int input_index = output_index * 2; | |
| 1990 const CookiesInputInfo* input = &input_info[input_index]; | |
| 1991 const CanonicalCookie* output = &cookies[output_index]; | |
| 1992 | |
| 1993 EXPECT_EQ(input->name, output->Name()); | |
| 1994 EXPECT_EQ(input->value, output->Value()); | |
| 1995 EXPECT_EQ(input->url.host(), output->Domain()); | |
| 1996 EXPECT_EQ(input->path, output->Path()); | |
| 1997 EXPECT_LE(current.ToInternalValue(), | |
| 1998 output->CreationDate().ToInternalValue()); | |
| 1999 EXPECT_EQ(input->secure, output->IsSecure()); | |
| 2000 EXPECT_EQ(input->http_only, output->IsHttpOnly()); | |
| 2001 EXPECT_TRUE(output->IsPersistent()); | |
| 2002 EXPECT_EQ(input->expiration_time.ToInternalValue(), | |
| 2003 output->ExpiryDate().ToInternalValue()); | |
| 2004 } | |
| 2005 } | |
| 2006 } | |
| 2007 | |
| 2008 TEST_F(CookieMonsterTest, CookieListOrdering) { | |
| 2009 // Put a random set of cookies into a monster and make sure | |
| 2010 // they're returned in the right order. | |
| 2011 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 2012 EXPECT_TRUE( | |
| 2013 SetCookie(cm.get(), GURL("http://d.c.b.a.google.com/aa/x.html"), "c=1")); | |
| 2014 EXPECT_TRUE(SetCookie(cm.get(), | |
| 2015 GURL("http://b.a.google.com/aa/bb/cc/x.html"), | |
| 2016 "d=1; domain=b.a.google.com")); | |
| 2017 EXPECT_TRUE(SetCookie(cm.get(), | |
| 2018 GURL("http://b.a.google.com/aa/bb/cc/x.html"), | |
| 2019 "a=4; domain=b.a.google.com")); | |
| 2020 EXPECT_TRUE(SetCookie(cm.get(), | |
| 2021 GURL("http://c.b.a.google.com/aa/bb/cc/x.html"), | |
| 2022 "e=1; domain=c.b.a.google.com")); | |
| 2023 EXPECT_TRUE(SetCookie( | |
| 2024 cm.get(), GURL("http://d.c.b.a.google.com/aa/bb/x.html"), "b=1")); | |
| 2025 EXPECT_TRUE(SetCookie( | |
| 2026 cm.get(), GURL("http://news.bbc.co.uk/midpath/x.html"), "g=10")); | |
| 2027 { | |
| 2028 unsigned int i = 0; | |
| 2029 CookieList cookies(GetAllCookiesForURL( | |
| 2030 cm.get(), GURL("http://d.c.b.a.google.com/aa/bb/cc/dd"))); | |
| 2031 ASSERT_EQ(5u, cookies.size()); | |
| 2032 EXPECT_EQ("d", cookies[i++].Name()); | |
| 2033 EXPECT_EQ("a", cookies[i++].Name()); | |
| 2034 EXPECT_EQ("e", cookies[i++].Name()); | |
| 2035 EXPECT_EQ("b", cookies[i++].Name()); | |
| 2036 EXPECT_EQ("c", cookies[i++].Name()); | |
| 2037 } | |
| 2038 | |
| 2039 { | |
| 2040 unsigned int i = 0; | |
| 2041 CookieList cookies(GetAllCookies(cm.get())); | |
| 2042 ASSERT_EQ(6u, cookies.size()); | |
| 2043 EXPECT_EQ("d", cookies[i++].Name()); | |
| 2044 EXPECT_EQ("a", cookies[i++].Name()); | |
| 2045 EXPECT_EQ("e", cookies[i++].Name()); | |
| 2046 EXPECT_EQ("g", cookies[i++].Name()); | |
| 2047 EXPECT_EQ("b", cookies[i++].Name()); | |
| 2048 EXPECT_EQ("c", cookies[i++].Name()); | |
| 2049 } | |
| 2050 } | |
| 2051 | |
| 2052 // This test and CookieMonstertest.TestGCTimes (in cookie_monster_perftest.cc) | |
| 2053 // are somewhat complementary twins. This test is probing for whether | |
| 2054 // garbage collection always happens when it should (i.e. that we actually | |
| 2055 // get rid of cookies when we should). The perftest is probing for | |
| 2056 // whether garbage collection happens when it shouldn't. See comments | |
| 2057 // before that test for more details. | |
| 2058 | |
| 2059 // Disabled on Windows, see crbug.com/126095 | |
| 2060 #if defined(OS_WIN) | |
| 2061 #define MAYBE_GarbageCollectionTriggers DISABLED_GarbageCollectionTriggers | |
| 2062 #else | |
| 2063 #define MAYBE_GarbageCollectionTriggers GarbageCollectionTriggers | |
| 2064 #endif | |
| 2065 | |
| 2066 TEST_F(CookieMonsterTest, MAYBE_GarbageCollectionTriggers) { | |
| 2067 // First we check to make sure that a whole lot of recent cookies | |
| 2068 // doesn't get rid of anything after garbage collection is checked for. | |
| 2069 { | |
| 2070 scoped_refptr<CookieMonster> cm( | |
| 2071 CreateMonsterForGC(CookieMonster::kMaxCookies * 2)); | |
| 2072 EXPECT_EQ(CookieMonster::kMaxCookies * 2, GetAllCookies(cm.get()).size()); | |
| 2073 SetCookie(cm.get(), GURL("http://newdomain.com"), "b=2"); | |
| 2074 EXPECT_EQ(CookieMonster::kMaxCookies * 2 + 1, | |
| 2075 GetAllCookies(cm.get()).size()); | |
| 2076 } | |
| 2077 | |
| 2078 // Now we explore a series of relationships between cookie last access | |
| 2079 // time and size of store to make sure we only get rid of cookies when | |
| 2080 // we really should. | |
| 2081 const struct TestCase { | |
| 2082 size_t num_cookies; | |
| 2083 size_t num_old_cookies; | |
| 2084 size_t expected_initial_cookies; | |
| 2085 // Indexed by ExpiryAndKeyScheme | |
| 2086 size_t expected_cookies_after_set; | |
| 2087 } test_cases[] = { | |
| 2088 { | |
| 2089 // A whole lot of recent cookies; gc shouldn't happen. | |
| 2090 CookieMonster::kMaxCookies * 2, | |
| 2091 0, | |
| 2092 CookieMonster::kMaxCookies * 2, | |
| 2093 CookieMonster::kMaxCookies * 2 + 1 | |
| 2094 }, { | |
| 2095 // Some old cookies, but still overflowing max. | |
| 2096 CookieMonster::kMaxCookies * 2, | |
| 2097 CookieMonster::kMaxCookies / 2, | |
| 2098 CookieMonster::kMaxCookies * 2, | |
| 2099 CookieMonster::kMaxCookies * 2 - CookieMonster::kMaxCookies / 2 + 1 | |
| 2100 }, { | |
| 2101 // Old cookies enough to bring us right down to our purge line. | |
| 2102 CookieMonster::kMaxCookies * 2, | |
| 2103 CookieMonster::kMaxCookies + CookieMonster::kPurgeCookies + 1, | |
| 2104 CookieMonster::kMaxCookies * 2, | |
| 2105 CookieMonster::kMaxCookies - CookieMonster::kPurgeCookies | |
| 2106 }, { | |
| 2107 // Old cookies enough to bring below our purge line (which we | |
| 2108 // shouldn't do). | |
| 2109 CookieMonster::kMaxCookies * 2, | |
| 2110 CookieMonster::kMaxCookies * 3 / 2, | |
| 2111 CookieMonster::kMaxCookies * 2, | |
| 2112 CookieMonster::kMaxCookies - CookieMonster::kPurgeCookies | |
| 2113 } | |
| 2114 }; | |
| 2115 | |
| 2116 for (int ci = 0; ci < static_cast<int>(arraysize(test_cases)); ++ci) { | |
| 2117 const TestCase *test_case = &test_cases[ci]; | |
| 2118 scoped_refptr<CookieMonster> cm( | |
| 2119 CreateMonsterFromStoreForGC( | |
| 2120 test_case->num_cookies, test_case->num_old_cookies, | |
| 2121 CookieMonster::kSafeFromGlobalPurgeDays * 2)); | |
| 2122 EXPECT_EQ(test_case->expected_initial_cookies, | |
| 2123 GetAllCookies(cm.get()).size()) << "For test case " << ci; | |
| 2124 // Will trigger GC | |
| 2125 SetCookie(cm.get(), GURL("http://newdomain.com"), "b=2"); | |
| 2126 EXPECT_EQ(test_case->expected_cookies_after_set, | |
| 2127 GetAllCookies(cm.get()).size()) << "For test case " << ci; | |
| 2128 } | |
| 2129 } | |
| 2130 | |
| 2131 // This test checks that keep expired cookies flag is working. | |
| 2132 TEST_F(CookieMonsterTest, KeepExpiredCookies) { | |
| 2133 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 2134 cm->SetKeepExpiredCookies(); | |
| 2135 CookieOptions options; | |
| 2136 | |
| 2137 // Set a persistent cookie. | |
| 2138 ASSERT_TRUE(SetCookieWithOptions( | |
| 2139 cm.get(), | |
| 2140 url_google_, | |
| 2141 std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT", | |
| 2142 options)); | |
| 2143 | |
| 2144 // Get the canonical cookie. | |
| 2145 CookieList cookie_list = GetAllCookies(cm.get()); | |
| 2146 ASSERT_EQ(1U, cookie_list.size()); | |
| 2147 | |
| 2148 // Use a past expiry date to delete the cookie. | |
| 2149 ASSERT_TRUE(SetCookieWithOptions( | |
| 2150 cm.get(), | |
| 2151 url_google_, | |
| 2152 std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-1977 22:50:13 GMT", | |
| 2153 options)); | |
| 2154 | |
| 2155 // Check that the cookie with the past expiry date is still there. | |
| 2156 // GetAllCookies() also triggers garbage collection. | |
| 2157 cookie_list = GetAllCookies(cm.get()); | |
| 2158 ASSERT_EQ(1U, cookie_list.size()); | |
| 2159 ASSERT_TRUE(cookie_list[0].IsExpired(Time::Now())); | |
| 2160 } | |
| 2161 | |
| 2162 namespace { | |
| 2163 | |
| 2164 // Mock PersistentCookieStore that keeps track of the number of Flush() calls. | |
| 2165 class FlushablePersistentStore : public CookieMonster::PersistentCookieStore { | |
| 2166 public: | |
| 2167 FlushablePersistentStore() : flush_count_(0) {} | |
| 2168 | |
| 2169 void Load(const LoadedCallback& loaded_callback) override { | |
| 2170 std::vector<CanonicalCookie*> out_cookies; | |
| 2171 base::MessageLoop::current()->PostTask( | |
| 2172 FROM_HERE, | |
| 2173 base::Bind(&net::LoadedCallbackTask::Run, | |
| 2174 new net::LoadedCallbackTask(loaded_callback, out_cookies))); | |
| 2175 } | |
| 2176 | |
| 2177 void LoadCookiesForKey(const std::string& key, | |
| 2178 const LoadedCallback& loaded_callback) override { | |
| 2179 Load(loaded_callback); | |
| 2180 } | |
| 2181 | |
| 2182 void AddCookie(const CanonicalCookie&) override {} | |
| 2183 void UpdateCookieAccessTime(const CanonicalCookie&) override {} | |
| 2184 void DeleteCookie(const CanonicalCookie&) override {} | |
| 2185 void SetForceKeepSessionState() override {} | |
| 2186 | |
| 2187 void Flush(const base::Closure& callback) override { | |
| 2188 ++flush_count_; | |
| 2189 if (!callback.is_null()) | |
| 2190 callback.Run(); | |
| 2191 } | |
| 2192 | |
| 2193 int flush_count() { | |
| 2194 return flush_count_; | |
| 2195 } | |
| 2196 | |
| 2197 private: | |
| 2198 ~FlushablePersistentStore() override {} | |
| 2199 | |
| 2200 volatile int flush_count_; | |
| 2201 }; | |
| 2202 | |
| 2203 // Counts the number of times Callback() has been run. | |
| 2204 class CallbackCounter : public base::RefCountedThreadSafe<CallbackCounter> { | |
| 2205 public: | |
| 2206 CallbackCounter() : callback_count_(0) {} | |
| 2207 | |
| 2208 void Callback() { | |
| 2209 ++callback_count_; | |
| 2210 } | |
| 2211 | |
| 2212 int callback_count() { | |
| 2213 return callback_count_; | |
| 2214 } | |
| 2215 | |
| 2216 private: | |
| 2217 friend class base::RefCountedThreadSafe<CallbackCounter>; | |
| 2218 ~CallbackCounter() {} | |
| 2219 | |
| 2220 volatile int callback_count_; | |
| 2221 }; | |
| 2222 | |
| 2223 } // namespace | |
| 2224 | |
| 2225 // Test that FlushStore() is forwarded to the store and callbacks are posted. | |
| 2226 TEST_F(CookieMonsterTest, FlushStore) { | |
| 2227 scoped_refptr<CallbackCounter> counter(new CallbackCounter()); | |
| 2228 scoped_refptr<FlushablePersistentStore> store(new FlushablePersistentStore()); | |
| 2229 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL)); | |
| 2230 | |
| 2231 ASSERT_EQ(0, store->flush_count()); | |
| 2232 ASSERT_EQ(0, counter->callback_count()); | |
| 2233 | |
| 2234 // Before initialization, FlushStore() should just run the callback. | |
| 2235 cm->FlushStore(base::Bind(&CallbackCounter::Callback, counter.get())); | |
| 2236 base::MessageLoop::current()->RunUntilIdle(); | |
| 2237 | |
| 2238 ASSERT_EQ(0, store->flush_count()); | |
| 2239 ASSERT_EQ(1, counter->callback_count()); | |
| 2240 | |
| 2241 // NULL callback is safe. | |
| 2242 cm->FlushStore(base::Closure()); | |
| 2243 base::MessageLoop::current()->RunUntilIdle(); | |
| 2244 | |
| 2245 ASSERT_EQ(0, store->flush_count()); | |
| 2246 ASSERT_EQ(1, counter->callback_count()); | |
| 2247 | |
| 2248 // After initialization, FlushStore() should delegate to the store. | |
| 2249 GetAllCookies(cm.get()); // Force init. | |
| 2250 cm->FlushStore(base::Bind(&CallbackCounter::Callback, counter.get())); | |
| 2251 base::MessageLoop::current()->RunUntilIdle(); | |
| 2252 | |
| 2253 ASSERT_EQ(1, store->flush_count()); | |
| 2254 ASSERT_EQ(2, counter->callback_count()); | |
| 2255 | |
| 2256 // NULL callback is still safe. | |
| 2257 cm->FlushStore(base::Closure()); | |
| 2258 base::MessageLoop::current()->RunUntilIdle(); | |
| 2259 | |
| 2260 ASSERT_EQ(2, store->flush_count()); | |
| 2261 ASSERT_EQ(2, counter->callback_count()); | |
| 2262 | |
| 2263 // If there's no backing store, FlushStore() is always a safe no-op. | |
| 2264 cm = new CookieMonster(NULL, NULL); | |
| 2265 GetAllCookies(cm.get()); // Force init. | |
| 2266 cm->FlushStore(base::Closure()); | |
| 2267 base::MessageLoop::current()->RunUntilIdle(); | |
| 2268 | |
| 2269 ASSERT_EQ(2, counter->callback_count()); | |
| 2270 | |
| 2271 cm->FlushStore(base::Bind(&CallbackCounter::Callback, counter.get())); | |
| 2272 base::MessageLoop::current()->RunUntilIdle(); | |
| 2273 | |
| 2274 ASSERT_EQ(3, counter->callback_count()); | |
| 2275 } | |
| 2276 | |
| 2277 TEST_F(CookieMonsterTest, HistogramCheck) { | |
| 2278 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 2279 // Should match call in InitializeHistograms, but doesn't really matter | |
| 2280 // since the histogram should have been initialized by the CM construction | |
| 2281 // above. | |
| 2282 base::HistogramBase* expired_histogram = | |
| 2283 base::Histogram::FactoryGet( | |
| 2284 "Cookie.ExpirationDurationMinutes", 1, 10 * 365 * 24 * 60, 50, | |
| 2285 base::Histogram::kUmaTargetedHistogramFlag); | |
| 2286 | |
| 2287 scoped_ptr<base::HistogramSamples> samples1( | |
| 2288 expired_histogram->SnapshotSamples()); | |
| 2289 ASSERT_TRUE( | |
| 2290 SetCookieWithDetails(cm.get(), | |
| 2291 GURL("http://fake.a.url"), | |
| 2292 "a", | |
| 2293 "b", | |
| 2294 "a.url", | |
| 2295 "/", | |
| 2296 base::Time::Now() + base::TimeDelta::FromMinutes(59), | |
| 2297 false, | |
| 2298 false, | |
| 2299 COOKIE_PRIORITY_DEFAULT)); | |
| 2300 | |
| 2301 scoped_ptr<base::HistogramSamples> samples2( | |
| 2302 expired_histogram->SnapshotSamples()); | |
| 2303 EXPECT_EQ(samples1->TotalCount() + 1, samples2->TotalCount()); | |
| 2304 | |
| 2305 // kValidCookieLine creates a session cookie. | |
| 2306 ASSERT_TRUE(SetCookie(cm.get(), url_google_, kValidCookieLine)); | |
| 2307 | |
| 2308 scoped_ptr<base::HistogramSamples> samples3( | |
| 2309 expired_histogram->SnapshotSamples()); | |
| 2310 EXPECT_EQ(samples2->TotalCount(), samples3->TotalCount()); | |
| 2311 } | |
| 2312 | |
| 2313 namespace { | |
| 2314 | |
| 2315 class MultiThreadedCookieMonsterTest : public CookieMonsterTest { | |
| 2316 public: | |
| 2317 MultiThreadedCookieMonsterTest() : other_thread_("CMTthread") {} | |
| 2318 | |
| 2319 // Helper methods for calling the asynchronous CookieMonster methods | |
| 2320 // from a different thread. | |
| 2321 | |
| 2322 void GetAllCookiesTask(CookieMonster* cm, | |
| 2323 GetCookieListCallback* callback) { | |
| 2324 cm->GetAllCookiesAsync( | |
| 2325 base::Bind(&GetCookieListCallback::Run, base::Unretained(callback))); | |
| 2326 } | |
| 2327 | |
| 2328 void GetAllCookiesForURLTask(CookieMonster* cm, | |
| 2329 const GURL& url, | |
| 2330 GetCookieListCallback* callback) { | |
| 2331 cm->GetAllCookiesForURLAsync( | |
| 2332 url, | |
| 2333 base::Bind(&GetCookieListCallback::Run, base::Unretained(callback))); | |
| 2334 } | |
| 2335 | |
| 2336 void GetAllCookiesForURLWithOptionsTask(CookieMonster* cm, | |
| 2337 const GURL& url, | |
| 2338 const CookieOptions& options, | |
| 2339 GetCookieListCallback* callback) { | |
| 2340 cm->GetAllCookiesForURLWithOptionsAsync( | |
| 2341 url, options, | |
| 2342 base::Bind(&GetCookieListCallback::Run, base::Unretained(callback))); | |
| 2343 } | |
| 2344 | |
| 2345 void SetCookieWithDetailsTask(CookieMonster* cm, const GURL& url, | |
| 2346 ResultSavingCookieCallback<bool>* callback) { | |
| 2347 // Define the parameters here instead of in the calling fucntion. | |
| 2348 // The maximum number of parameters for Bind function is 6. | |
| 2349 std::string name = "A"; | |
| 2350 std::string value = "B"; | |
| 2351 std::string domain = std::string(); | |
| 2352 std::string path = "/foo"; | |
| 2353 base::Time expiration_time = base::Time(); | |
| 2354 bool secure = false; | |
| 2355 bool http_only = false; | |
| 2356 CookiePriority priority = COOKIE_PRIORITY_DEFAULT; | |
| 2357 cm->SetCookieWithDetailsAsync( | |
| 2358 url, name, value, domain, path, expiration_time, secure, http_only, | |
| 2359 priority, | |
| 2360 base::Bind( | |
| 2361 &ResultSavingCookieCallback<bool>::Run, | |
| 2362 base::Unretained(callback))); | |
| 2363 } | |
| 2364 | |
| 2365 void DeleteAllCreatedBetweenTask(CookieMonster* cm, | |
| 2366 const base::Time& delete_begin, | |
| 2367 const base::Time& delete_end, | |
| 2368 ResultSavingCookieCallback<int>* callback) { | |
| 2369 cm->DeleteAllCreatedBetweenAsync( | |
| 2370 delete_begin, delete_end, | |
| 2371 base::Bind( | |
| 2372 &ResultSavingCookieCallback<int>::Run, base::Unretained(callback))); | |
| 2373 } | |
| 2374 | |
| 2375 void DeleteAllForHostTask(CookieMonster* cm, | |
| 2376 const GURL& url, | |
| 2377 ResultSavingCookieCallback<int>* callback) { | |
| 2378 cm->DeleteAllForHostAsync( | |
| 2379 url, | |
| 2380 base::Bind( | |
| 2381 &ResultSavingCookieCallback<int>::Run, base::Unretained(callback))); | |
| 2382 } | |
| 2383 | |
| 2384 void DeleteAllCreatedBetweenForHostTask( | |
| 2385 CookieMonster* cm, | |
| 2386 const base::Time delete_begin, | |
| 2387 const base::Time delete_end, | |
| 2388 const GURL& url, | |
| 2389 ResultSavingCookieCallback<int>* callback) { | |
| 2390 cm->DeleteAllCreatedBetweenForHostAsync( | |
| 2391 delete_begin, delete_end, url, | |
| 2392 base::Bind( | |
| 2393 &ResultSavingCookieCallback<int>::Run, | |
| 2394 base::Unretained(callback))); | |
| 2395 } | |
| 2396 | |
| 2397 void DeleteCanonicalCookieTask(CookieMonster* cm, | |
| 2398 const CanonicalCookie& cookie, | |
| 2399 ResultSavingCookieCallback<bool>* callback) { | |
| 2400 cm->DeleteCanonicalCookieAsync( | |
| 2401 cookie, | |
| 2402 base::Bind( | |
| 2403 &ResultSavingCookieCallback<bool>::Run, | |
| 2404 base::Unretained(callback))); | |
| 2405 } | |
| 2406 | |
| 2407 protected: | |
| 2408 void RunOnOtherThread(const base::Closure& task) { | |
| 2409 other_thread_.Start(); | |
| 2410 other_thread_.message_loop()->PostTask(FROM_HERE, task); | |
| 2411 RunFor(kTimeout); | |
| 2412 other_thread_.Stop(); | |
| 2413 } | |
| 2414 | |
| 2415 Thread other_thread_; | |
| 2416 }; | |
| 2417 | |
| 2418 } // namespace | |
| 2419 | |
| 2420 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckGetAllCookies) { | |
| 2421 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 2422 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B")); | |
| 2423 CookieList cookies = GetAllCookies(cm.get()); | |
| 2424 CookieList::const_iterator it = cookies.begin(); | |
| 2425 ASSERT_TRUE(it != cookies.end()); | |
| 2426 EXPECT_EQ("www.google.izzle", it->Domain()); | |
| 2427 EXPECT_EQ("A", it->Name()); | |
| 2428 ASSERT_TRUE(++it == cookies.end()); | |
| 2429 GetCookieListCallback callback(&other_thread_); | |
| 2430 base::Closure task = | |
| 2431 base::Bind(&net::MultiThreadedCookieMonsterTest::GetAllCookiesTask, | |
| 2432 base::Unretained(this), | |
| 2433 cm, &callback); | |
| 2434 RunOnOtherThread(task); | |
| 2435 EXPECT_TRUE(callback.did_run()); | |
| 2436 it = callback.cookies().begin(); | |
| 2437 ASSERT_TRUE(it != callback.cookies().end()); | |
| 2438 EXPECT_EQ("www.google.izzle", it->Domain()); | |
| 2439 EXPECT_EQ("A", it->Name()); | |
| 2440 ASSERT_TRUE(++it == callback.cookies().end()); | |
| 2441 } | |
| 2442 | |
| 2443 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckGetAllCookiesForURL) { | |
| 2444 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 2445 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B")); | |
| 2446 CookieList cookies = GetAllCookiesForURL(cm.get(), url_google_); | |
| 2447 CookieList::const_iterator it = cookies.begin(); | |
| 2448 ASSERT_TRUE(it != cookies.end()); | |
| 2449 EXPECT_EQ("www.google.izzle", it->Domain()); | |
| 2450 EXPECT_EQ("A", it->Name()); | |
| 2451 ASSERT_TRUE(++it == cookies.end()); | |
| 2452 GetCookieListCallback callback(&other_thread_); | |
| 2453 base::Closure task = | |
| 2454 base::Bind(&net::MultiThreadedCookieMonsterTest::GetAllCookiesForURLTask, | |
| 2455 base::Unretained(this), | |
| 2456 cm, url_google_, &callback); | |
| 2457 RunOnOtherThread(task); | |
| 2458 EXPECT_TRUE(callback.did_run()); | |
| 2459 it = callback.cookies().begin(); | |
| 2460 ASSERT_TRUE(it != callback.cookies().end()); | |
| 2461 EXPECT_EQ("www.google.izzle", it->Domain()); | |
| 2462 EXPECT_EQ("A", it->Name()); | |
| 2463 ASSERT_TRUE(++it == callback.cookies().end()); | |
| 2464 } | |
| 2465 | |
| 2466 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckGetAllCookiesForURLWithOpt) { | |
| 2467 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 2468 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B")); | |
| 2469 CookieOptions options; | |
| 2470 CookieList cookies = | |
| 2471 GetAllCookiesForURLWithOptions(cm.get(), url_google_, options); | |
| 2472 CookieList::const_iterator it = cookies.begin(); | |
| 2473 ASSERT_TRUE(it != cookies.end()); | |
| 2474 EXPECT_EQ("www.google.izzle", it->Domain()); | |
| 2475 EXPECT_EQ("A", it->Name()); | |
| 2476 ASSERT_TRUE(++it == cookies.end()); | |
| 2477 GetCookieListCallback callback(&other_thread_); | |
| 2478 base::Closure task = base::Bind( | |
| 2479 &net::MultiThreadedCookieMonsterTest::GetAllCookiesForURLWithOptionsTask, | |
| 2480 base::Unretained(this), | |
| 2481 cm, url_google_, options, &callback); | |
| 2482 RunOnOtherThread(task); | |
| 2483 EXPECT_TRUE(callback.did_run()); | |
| 2484 it = callback.cookies().begin(); | |
| 2485 ASSERT_TRUE(it != callback.cookies().end()); | |
| 2486 EXPECT_EQ("www.google.izzle", it->Domain()); | |
| 2487 EXPECT_EQ("A", it->Name()); | |
| 2488 ASSERT_TRUE(++it == callback.cookies().end()); | |
| 2489 } | |
| 2490 | |
| 2491 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckSetCookieWithDetails) { | |
| 2492 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 2493 EXPECT_TRUE(SetCookieWithDetails(cm.get(), | |
| 2494 url_google_foo_, | |
| 2495 "A", | |
| 2496 "B", | |
| 2497 std::string(), | |
| 2498 "/foo", | |
| 2499 base::Time(), | |
| 2500 false, | |
| 2501 false, | |
| 2502 COOKIE_PRIORITY_DEFAULT)); | |
| 2503 ResultSavingCookieCallback<bool> callback(&other_thread_); | |
| 2504 base::Closure task = base::Bind( | |
| 2505 &net::MultiThreadedCookieMonsterTest::SetCookieWithDetailsTask, | |
| 2506 base::Unretained(this), | |
| 2507 cm, url_google_foo_, &callback); | |
| 2508 RunOnOtherThread(task); | |
| 2509 EXPECT_TRUE(callback.did_run()); | |
| 2510 EXPECT_TRUE(callback.result()); | |
| 2511 } | |
| 2512 | |
| 2513 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckDeleteAllCreatedBetween) { | |
| 2514 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 2515 CookieOptions options; | |
| 2516 Time now = Time::Now(); | |
| 2517 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options)); | |
| 2518 EXPECT_EQ( | |
| 2519 1, | |
| 2520 DeleteAllCreatedBetween(cm.get(), now - TimeDelta::FromDays(99), Time())); | |
| 2521 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options)); | |
| 2522 ResultSavingCookieCallback<int> callback(&other_thread_); | |
| 2523 base::Closure task = base::Bind( | |
| 2524 &net::MultiThreadedCookieMonsterTest::DeleteAllCreatedBetweenTask, | |
| 2525 base::Unretained(this), | |
| 2526 cm, now - TimeDelta::FromDays(99), | |
| 2527 Time(), &callback); | |
| 2528 RunOnOtherThread(task); | |
| 2529 EXPECT_TRUE(callback.did_run()); | |
| 2530 EXPECT_EQ(1, callback.result()); | |
| 2531 } | |
| 2532 | |
| 2533 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckDeleteAllForHost) { | |
| 2534 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 2535 CookieOptions options; | |
| 2536 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options)); | |
| 2537 EXPECT_EQ(1, DeleteAllForHost(cm.get(), url_google_)); | |
| 2538 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options)); | |
| 2539 ResultSavingCookieCallback<int> callback(&other_thread_); | |
| 2540 base::Closure task = base::Bind( | |
| 2541 &net::MultiThreadedCookieMonsterTest::DeleteAllForHostTask, | |
| 2542 base::Unretained(this), | |
| 2543 cm, url_google_, &callback); | |
| 2544 RunOnOtherThread(task); | |
| 2545 EXPECT_TRUE(callback.did_run()); | |
| 2546 EXPECT_EQ(1, callback.result()); | |
| 2547 } | |
| 2548 | |
| 2549 TEST_F(MultiThreadedCookieMonsterTest, | |
| 2550 ThreadCheckDeleteAllCreatedBetweenForHost) { | |
| 2551 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 2552 GURL url_not_google("http://www.notgoogle.com"); | |
| 2553 | |
| 2554 CookieOptions options; | |
| 2555 Time now = Time::Now(); | |
| 2556 // ago1 < ago2 < ago3 < now. | |
| 2557 Time ago1 = now - TimeDelta::FromDays(101); | |
| 2558 Time ago2 = now - TimeDelta::FromDays(100); | |
| 2559 Time ago3 = now - TimeDelta::FromDays(99); | |
| 2560 | |
| 2561 // These 3 cookies match the first deletion. | |
| 2562 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options)); | |
| 2563 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "C=D", options)); | |
| 2564 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "Y=Z", options)); | |
| 2565 | |
| 2566 // This cookie does not match host. | |
| 2567 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_not_google, "E=F", options)); | |
| 2568 | |
| 2569 // This cookie does not match time range: [ago3, inf], for first deletion, but | |
| 2570 // matches for the second deletion. | |
| 2571 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "G=H", ago2)); | |
| 2572 | |
| 2573 // 1. First set of deletions. | |
| 2574 EXPECT_EQ( | |
| 2575 3, // Deletes A=B, C=D, Y=Z | |
| 2576 DeleteAllCreatedBetweenForHost( | |
| 2577 cm.get(), ago3, Time::Max(), url_google_)); | |
| 2578 | |
| 2579 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options)); | |
| 2580 ResultSavingCookieCallback<int> callback(&other_thread_); | |
| 2581 | |
| 2582 // 2. Second set of deletions. | |
| 2583 base::Closure task = base::Bind( | |
| 2584 &net::MultiThreadedCookieMonsterTest::DeleteAllCreatedBetweenForHostTask, | |
| 2585 base::Unretained(this), | |
| 2586 cm, ago1, Time(), url_google_, | |
| 2587 &callback); | |
| 2588 RunOnOtherThread(task); | |
| 2589 EXPECT_TRUE(callback.did_run()); | |
| 2590 EXPECT_EQ(2, callback.result()); // Deletes A=B, G=H. | |
| 2591 } | |
| 2592 | |
| 2593 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckDeleteCanonicalCookie) { | |
| 2594 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
| 2595 CookieOptions options; | |
| 2596 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options)); | |
| 2597 CookieList cookies = GetAllCookies(cm.get()); | |
| 2598 CookieList::iterator it = cookies.begin(); | |
| 2599 EXPECT_TRUE(DeleteCanonicalCookie(cm.get(), *it)); | |
| 2600 | |
| 2601 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options)); | |
| 2602 ResultSavingCookieCallback<bool> callback(&other_thread_); | |
| 2603 cookies = GetAllCookies(cm.get()); | |
| 2604 it = cookies.begin(); | |
| 2605 base::Closure task = base::Bind( | |
| 2606 &net::MultiThreadedCookieMonsterTest::DeleteCanonicalCookieTask, | |
| 2607 base::Unretained(this), | |
| 2608 cm, *it, &callback); | |
| 2609 RunOnOtherThread(task); | |
| 2610 EXPECT_TRUE(callback.did_run()); | |
| 2611 EXPECT_TRUE(callback.result()); | |
| 2612 } | |
| 2613 | |
| 2614 // Ensure that cookies for http, https, ws, and wss all share the same storage | |
| 2615 // and policies when GetAllCookiesForURLAsync is used. This test is part of | |
| 2616 // MultiThreadedCookieMonsterTest in order to test and use | |
| 2617 // GetAllCookiesForURLAsync, but it does not use any additional threads. | |
| 2618 TEST_F(MultiThreadedCookieMonsterTest, GetAllCookiesForURLEffectiveDomain) { | |
| 2619 std::vector<CanonicalCookie*> cookies; | |
| 2620 // This cookie will be freed by the CookieMonster. | |
| 2621 cookies.push_back(CanonicalCookie::Create(url_google_, kValidCookieLine, | |
| 2622 Time::Now(), CookieOptions())); | |
| 2623 CanonicalCookie cookie = *cookies[0]; | |
| 2624 scoped_refptr<NewMockPersistentCookieStore> store( | |
| 2625 new NewMockPersistentCookieStore); | |
| 2626 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL)); | |
| 2627 | |
| 2628 CookieMonster::PersistentCookieStore::LoadedCallback loaded_callback; | |
| 2629 ::testing::StrictMock<::testing::MockFunction<void(int)>> checkpoint; | |
| 2630 const std::string key = | |
| 2631 cookie_util::GetEffectiveDomain(url_google_.scheme(), url_google_.host()); | |
| 2632 | |
| 2633 ::testing::InSequence s; | |
| 2634 EXPECT_CALL(checkpoint, Call(0)); | |
| 2635 EXPECT_CALL(*store, Load(::testing::_)); | |
| 2636 EXPECT_CALL(*store, LoadCookiesForKey(key, ::testing::_)) | |
| 2637 .WillOnce(::testing::SaveArg<1>(&loaded_callback)); | |
| 2638 EXPECT_CALL(checkpoint, Call(1)); | |
| 2639 // LoadCookiesForKey will never be called after checkpoint.Call(1) although | |
| 2640 // we will call GetAllCookiesForURLAsync again, because all URLs below share | |
| 2641 // the same key. | |
| 2642 EXPECT_CALL(*store, LoadCookiesForKey(::testing::_, ::testing::_)).Times(0); | |
| 2643 | |
| 2644 GetCookieListCallback callback; | |
| 2645 checkpoint.Call(0); | |
| 2646 GetAllCookiesForURLTask(cm.get(), url_google_, &callback); | |
| 2647 checkpoint.Call(1); | |
| 2648 ASSERT_FALSE(callback.did_run()); | |
| 2649 // Pass the cookies to the CookieMonster. | |
| 2650 loaded_callback.Run(cookies); | |
| 2651 // Now GetAllCookiesForURLTask is done. | |
| 2652 ASSERT_TRUE(callback.did_run()); | |
| 2653 // See that the callback was called with the cookies. | |
| 2654 ASSERT_EQ(1u, callback.cookies().size()); | |
| 2655 EXPECT_TRUE(cookie.IsEquivalent(callback.cookies()[0])); | |
| 2656 | |
| 2657 // All urls in |urls| should share the same cookie domain. | |
| 2658 const GURL kUrls[] = { | |
| 2659 url_google_, | |
| 2660 url_google_secure_, | |
| 2661 GURL(kUrlGoogleWebSocket), | |
| 2662 GURL(kUrlGoogleWebSocketSecure), | |
| 2663 }; | |
| 2664 for (const GURL& url : kUrls) { | |
| 2665 // Call the function with |url| and verify it is done synchronously without | |
| 2666 // calling LoadCookiesForKey. | |
| 2667 GetCookieListCallback callback; | |
| 2668 GetAllCookiesForURLTask(cm.get(), url, &callback); | |
| 2669 ASSERT_TRUE(callback.did_run()); | |
| 2670 ASSERT_EQ(1u, callback.cookies().size()); | |
| 2671 EXPECT_TRUE(cookie.IsEquivalent(callback.cookies()[0])); | |
| 2672 } | |
| 2673 } | |
| 2674 | |
| 2675 TEST_F(CookieMonsterTest, InvalidExpiryTime) { | |
| 2676 std::string cookie_line = | |
| 2677 std::string(kValidCookieLine) + "; expires=Blarg arg arg"; | |
| 2678 scoped_ptr<CanonicalCookie> cookie( | |
| 2679 CanonicalCookie::Create(url_google_, cookie_line, Time::Now(), | |
| 2680 CookieOptions())); | |
| 2681 ASSERT_FALSE(cookie->IsPersistent()); | |
| 2682 } | |
| 2683 | |
| 2684 // Test that CookieMonster writes session cookies into the underlying | |
| 2685 // CookieStore if the "persist session cookies" option is on. | |
| 2686 TEST_F(CookieMonsterTest, PersistSessionCookies) { | |
| 2687 scoped_refptr<MockPersistentCookieStore> store( | |
| 2688 new MockPersistentCookieStore); | |
| 2689 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL)); | |
| 2690 cm->SetPersistSessionCookies(true); | |
| 2691 | |
| 2692 // All cookies set with SetCookie are session cookies. | |
| 2693 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B")); | |
| 2694 EXPECT_EQ("A=B", GetCookies(cm.get(), url_google_)); | |
| 2695 | |
| 2696 // The cookie was written to the backing store. | |
| 2697 EXPECT_EQ(1u, store->commands().size()); | |
| 2698 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type); | |
| 2699 EXPECT_EQ("A", store->commands()[0].cookie.Name()); | |
| 2700 EXPECT_EQ("B", store->commands()[0].cookie.Value()); | |
| 2701 | |
| 2702 // Modify the cookie. | |
| 2703 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=C")); | |
| 2704 EXPECT_EQ("A=C", GetCookies(cm.get(), url_google_)); | |
| 2705 EXPECT_EQ(3u, store->commands().size()); | |
| 2706 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type); | |
| 2707 EXPECT_EQ("A", store->commands()[1].cookie.Name()); | |
| 2708 EXPECT_EQ("B", store->commands()[1].cookie.Value()); | |
| 2709 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type); | |
| 2710 EXPECT_EQ("A", store->commands()[2].cookie.Name()); | |
| 2711 EXPECT_EQ("C", store->commands()[2].cookie.Value()); | |
| 2712 | |
| 2713 // Delete the cookie. | |
| 2714 DeleteCookie(cm.get(), url_google_, "A"); | |
| 2715 EXPECT_EQ("", GetCookies(cm.get(), url_google_)); | |
| 2716 EXPECT_EQ(4u, store->commands().size()); | |
| 2717 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type); | |
| 2718 EXPECT_EQ("A", store->commands()[3].cookie.Name()); | |
| 2719 EXPECT_EQ("C", store->commands()[3].cookie.Value()); | |
| 2720 } | |
| 2721 | |
| 2722 // Test the commands sent to the persistent cookie store. | |
| 2723 TEST_F(CookieMonsterTest, PersisentCookieStorageTest) { | |
| 2724 scoped_refptr<MockPersistentCookieStore> store( | |
| 2725 new MockPersistentCookieStore); | |
| 2726 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL)); | |
| 2727 | |
| 2728 // Add a cookie. | |
| 2729 EXPECT_TRUE(SetCookie( | |
| 2730 cm.get(), url_google_, "A=B; expires=Mon, 18-Apr-22 22:50:13 GMT")); | |
| 2731 this->MatchCookieLines("A=B", GetCookies(cm.get(), url_google_)); | |
| 2732 ASSERT_EQ(1u, store->commands().size()); | |
| 2733 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type); | |
| 2734 // Remove it. | |
| 2735 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B; max-age=0")); | |
| 2736 this->MatchCookieLines(std::string(), GetCookies(cm.get(), url_google_)); | |
| 2737 ASSERT_EQ(2u, store->commands().size()); | |
| 2738 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type); | |
| 2739 | |
| 2740 // Add a cookie. | |
| 2741 EXPECT_TRUE(SetCookie( | |
| 2742 cm.get(), url_google_, "A=B; expires=Mon, 18-Apr-22 22:50:13 GMT")); | |
| 2743 this->MatchCookieLines("A=B", GetCookies(cm.get(), url_google_)); | |
| 2744 ASSERT_EQ(3u, store->commands().size()); | |
| 2745 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type); | |
| 2746 // Overwrite it. | |
| 2747 EXPECT_TRUE(SetCookie( | |
| 2748 cm.get(), url_google_, "A=Foo; expires=Mon, 18-Apr-22 22:50:14 GMT")); | |
| 2749 this->MatchCookieLines("A=Foo", GetCookies(cm.get(), url_google_)); | |
| 2750 ASSERT_EQ(5u, store->commands().size()); | |
| 2751 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type); | |
| 2752 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[4].type); | |
| 2753 | |
| 2754 // Create some non-persistent cookies and check that they don't go to the | |
| 2755 // persistent storage. | |
| 2756 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=Bar")); | |
| 2757 this->MatchCookieLines("A=Foo; B=Bar", GetCookies(cm.get(), url_google_)); | |
| 2758 EXPECT_EQ(5u, store->commands().size()); | |
| 2759 } | |
| 2760 | |
| 2761 // Test to assure that cookies with control characters are purged appropriately. | |
| 2762 // See http://crbug.com/238041 for background. | |
| 2763 TEST_F(CookieMonsterTest, ControlCharacterPurge) { | |
| 2764 const Time now1(Time::Now()); | |
| 2765 const Time now2(Time::Now() + TimeDelta::FromSeconds(1)); | |
| 2766 const Time now3(Time::Now() + TimeDelta::FromSeconds(2)); | |
| 2767 const Time later(now1 + TimeDelta::FromDays(1)); | |
| 2768 const GURL url("http://host/path"); | |
| 2769 const std::string domain("host"); | |
| 2770 const std::string path("/path"); | |
| 2771 | |
| 2772 scoped_refptr<MockPersistentCookieStore> store( | |
| 2773 new MockPersistentCookieStore); | |
| 2774 | |
| 2775 std::vector<CanonicalCookie*> initial_cookies; | |
| 2776 | |
| 2777 AddCookieToList(domain, | |
| 2778 "foo=bar; path=" + path, | |
| 2779 now1, | |
| 2780 &initial_cookies); | |
| 2781 | |
| 2782 // We have to manually build this cookie because it contains a control | |
| 2783 // character, and our cookie line parser rejects control characters. | |
| 2784 CanonicalCookie *cc = new CanonicalCookie(url, "baz", "\x05" "boo", domain, | |
| 2785 path, now2, later, now2, false, | |
| 2786 false, COOKIE_PRIORITY_DEFAULT); | |
| 2787 initial_cookies.push_back(cc); | |
| 2788 | |
| 2789 AddCookieToList(domain, | |
| 2790 "hello=world; path=" + path, | |
| 2791 now3, | |
| 2792 &initial_cookies); | |
| 2793 | |
| 2794 // Inject our initial cookies into the mock PersistentCookieStore. | |
| 2795 store->SetLoadExpectation(true, initial_cookies); | |
| 2796 | |
| 2797 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL)); | |
| 2798 | |
| 2799 EXPECT_EQ("foo=bar; hello=world", GetCookies(cm.get(), url)); | |
| 2800 } | |
| 2801 | |
| 2802 class CookieMonsterNotificationTest : public CookieMonsterTest { | |
| 2803 public: | |
| 2804 CookieMonsterNotificationTest() | |
| 2805 : test_url_("http://www.google.com/foo"), | |
| 2806 store_(new MockPersistentCookieStore), | |
| 2807 monster_(new CookieMonster(store_.get(), NULL)) {} | |
| 2808 | |
| 2809 ~CookieMonsterNotificationTest() override {} | |
| 2810 | |
| 2811 CookieMonster* monster() { return monster_.get(); } | |
| 2812 | |
| 2813 protected: | |
| 2814 const GURL test_url_; | |
| 2815 | |
| 2816 private: | |
| 2817 scoped_refptr<MockPersistentCookieStore> store_; | |
| 2818 scoped_refptr<CookieMonster> monster_; | |
| 2819 }; | |
| 2820 | |
| 2821 void RecordCookieChanges(std::vector<net::CanonicalCookie>* out_cookies, | |
| 2822 std::vector<bool>* out_removes, | |
| 2823 const net::CanonicalCookie& cookie, | |
| 2824 bool removed) { | |
| 2825 DCHECK(out_cookies); | |
| 2826 out_cookies->push_back(cookie); | |
| 2827 if (out_removes) | |
| 2828 out_removes->push_back(removed); | |
| 2829 } | |
| 2830 | |
| 2831 TEST_F(CookieMonsterNotificationTest, NoNotifyWithNoCookie) { | |
| 2832 std::vector<net::CanonicalCookie> cookies; | |
| 2833 scoped_ptr<CookieStore::CookieChangedSubscription> sub( | |
| 2834 monster()->AddCallbackForCookie(test_url_, "abc", | |
| 2835 base::Bind(&RecordCookieChanges, &cookies, nullptr))); | |
| 2836 base::MessageLoop::current()->RunUntilIdle(); | |
| 2837 EXPECT_EQ(0U, cookies.size()); | |
| 2838 } | |
| 2839 | |
| 2840 TEST_F(CookieMonsterNotificationTest, NoNotifyWithInitialCookie) { | |
| 2841 std::vector<net::CanonicalCookie> cookies; | |
| 2842 SetCookie(monster(), test_url_, "abc=def"); | |
| 2843 base::MessageLoop::current()->RunUntilIdle(); | |
| 2844 scoped_ptr<CookieStore::CookieChangedSubscription> sub( | |
| 2845 monster()->AddCallbackForCookie(test_url_, "abc", | |
| 2846 base::Bind(&RecordCookieChanges, &cookies, nullptr))); | |
| 2847 base::MessageLoop::current()->RunUntilIdle(); | |
| 2848 EXPECT_EQ(0U, cookies.size()); | |
| 2849 } | |
| 2850 | |
| 2851 TEST_F(CookieMonsterNotificationTest, NotifyOnSet) { | |
| 2852 std::vector<net::CanonicalCookie> cookies; | |
| 2853 std::vector<bool> removes; | |
| 2854 scoped_ptr<CookieStore::CookieChangedSubscription> sub( | |
| 2855 monster()->AddCallbackForCookie(test_url_, "abc", | |
| 2856 base::Bind(&RecordCookieChanges, &cookies, &removes))); | |
| 2857 SetCookie(monster(), test_url_, "abc=def"); | |
| 2858 base::MessageLoop::current()->RunUntilIdle(); | |
| 2859 EXPECT_EQ(1U, cookies.size()); | |
| 2860 EXPECT_EQ(1U, removes.size()); | |
| 2861 | |
| 2862 EXPECT_EQ("abc", cookies[0].Name()); | |
| 2863 EXPECT_EQ("def", cookies[0].Value()); | |
| 2864 EXPECT_FALSE(removes[0]); | |
| 2865 } | |
| 2866 | |
| 2867 TEST_F(CookieMonsterNotificationTest, NotifyOnDelete) { | |
| 2868 std::vector<net::CanonicalCookie> cookies; | |
| 2869 std::vector<bool> removes; | |
| 2870 scoped_ptr<CookieStore::CookieChangedSubscription> sub( | |
| 2871 monster()->AddCallbackForCookie(test_url_, "abc", | |
| 2872 base::Bind(&RecordCookieChanges, &cookies, &removes))); | |
| 2873 SetCookie(monster(), test_url_, "abc=def"); | |
| 2874 base::MessageLoop::current()->RunUntilIdle(); | |
| 2875 EXPECT_EQ(1U, cookies.size()); | |
| 2876 EXPECT_EQ(1U, removes.size()); | |
| 2877 | |
| 2878 DeleteCookie(monster(), test_url_, "abc"); | |
| 2879 base::MessageLoop::current()->RunUntilIdle(); | |
| 2880 EXPECT_EQ(2U, cookies.size()); | |
| 2881 EXPECT_EQ(2U, removes.size()); | |
| 2882 | |
| 2883 EXPECT_EQ("abc", cookies[1].Name()); | |
| 2884 EXPECT_EQ("def", cookies[1].Value()); | |
| 2885 EXPECT_TRUE(removes[1]); | |
| 2886 } | |
| 2887 | |
| 2888 TEST_F(CookieMonsterNotificationTest, NotifyOnUpdate) { | |
| 2889 std::vector<net::CanonicalCookie> cookies; | |
| 2890 std::vector<bool> removes; | |
| 2891 scoped_ptr<CookieStore::CookieChangedSubscription> sub( | |
| 2892 monster()->AddCallbackForCookie(test_url_, "abc", | |
| 2893 base::Bind(&RecordCookieChanges, &cookies, &removes))); | |
| 2894 SetCookie(monster(), test_url_, "abc=def"); | |
| 2895 base::MessageLoop::current()->RunUntilIdle(); | |
| 2896 EXPECT_EQ(1U, cookies.size()); | |
| 2897 | |
| 2898 // Replacing an existing cookie is actually a two-phase delete + set | |
| 2899 // operation, so we get an extra notification. | |
| 2900 SetCookie(monster(), test_url_, "abc=ghi"); | |
| 2901 base::MessageLoop::current()->RunUntilIdle(); | |
| 2902 | |
| 2903 EXPECT_EQ(3U, cookies.size()); | |
| 2904 EXPECT_EQ(3U, removes.size()); | |
| 2905 | |
| 2906 EXPECT_EQ("abc", cookies[1].Name()); | |
| 2907 EXPECT_EQ("def", cookies[1].Value()); | |
| 2908 EXPECT_TRUE(removes[1]); | |
| 2909 | |
| 2910 EXPECT_EQ("abc", cookies[2].Name()); | |
| 2911 EXPECT_EQ("ghi", cookies[2].Value()); | |
| 2912 EXPECT_FALSE(removes[2]); | |
| 2913 } | |
| 2914 | |
| 2915 TEST_F(CookieMonsterNotificationTest, MultipleNotifies) { | |
| 2916 std::vector<net::CanonicalCookie> cookies0; | |
| 2917 std::vector<net::CanonicalCookie> cookies1; | |
| 2918 scoped_ptr<CookieStore::CookieChangedSubscription> sub0( | |
| 2919 monster()->AddCallbackForCookie(test_url_, "abc", | |
| 2920 base::Bind(&RecordCookieChanges, &cookies0, nullptr))); | |
| 2921 scoped_ptr<CookieStore::CookieChangedSubscription> sub1( | |
| 2922 monster()->AddCallbackForCookie(test_url_, "def", | |
| 2923 base::Bind(&RecordCookieChanges, &cookies1, nullptr))); | |
| 2924 SetCookie(monster(), test_url_, "abc=def"); | |
| 2925 base::MessageLoop::current()->RunUntilIdle(); | |
| 2926 EXPECT_EQ(1U, cookies0.size()); | |
| 2927 EXPECT_EQ(0U, cookies1.size()); | |
| 2928 SetCookie(monster(), test_url_, "def=abc"); | |
| 2929 base::MessageLoop::current()->RunUntilIdle(); | |
| 2930 EXPECT_EQ(1U, cookies0.size()); | |
| 2931 EXPECT_EQ(1U, cookies1.size()); | |
| 2932 } | |
| 2933 | |
| 2934 TEST_F(CookieMonsterNotificationTest, MultipleSameNotifies) { | |
| 2935 std::vector<net::CanonicalCookie> cookies0; | |
| 2936 std::vector<net::CanonicalCookie> cookies1; | |
| 2937 scoped_ptr<CookieStore::CookieChangedSubscription> sub0( | |
| 2938 monster()->AddCallbackForCookie(test_url_, "abc", | |
| 2939 base::Bind(&RecordCookieChanges, &cookies0, nullptr))); | |
| 2940 scoped_ptr<CookieStore::CookieChangedSubscription> sub1( | |
| 2941 monster()->AddCallbackForCookie(test_url_, "abc", | |
| 2942 base::Bind(&RecordCookieChanges, &cookies1, nullptr))); | |
| 2943 SetCookie(monster(), test_url_, "abc=def"); | |
| 2944 base::MessageLoop::current()->RunUntilIdle(); | |
| 2945 EXPECT_EQ(1U, cookies0.size()); | |
| 2946 EXPECT_EQ(1U, cookies0.size()); | |
| 2947 } | |
| 2948 | |
| 2949 } // namespace net | |
| OLD | NEW |