cookie_monster_unittest.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1// Copyright (c) 2006-2008 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 <time.h> 6 7#include <string> 8 9#include "base/basictypes.h" 10#include "base/platform_thread.h" 11#include "base/ref_counted.h" 12#include "base/scoped_ptr.h" 13#include "base/string_util.h" 14#include "base/time.h" 15#include "googleurl/src/gurl.h" 16#include "net/base/cookie_monster.h" 17#include "testing/gtest/include/gtest/gtest.h" 18 19using base::Time; 20using base::TimeDelta; 21 22namespace { 23 24class ParsedCookieTest : public testing::Test { }; 25class CookieMonsterTest : public testing::Test { }; 26 27// Describes a call to one of the 3 functions of PersistentCookieStore. 28struct CookieStoreCommand { 29 enum Type { 30 ADD, 31 UPDATE_ACCESS_TIME, 32 REMOVE, 33 }; 34 35 CookieStoreCommand(Type type, 36 const std::string& key, 37 const net::CookieMonster::CanonicalCookie& cookie) 38 : type(type), key(key), cookie(cookie) {} 39 40 Type type; 41 std::string key; // Only applicable to the ADD command. 42 net::CookieMonster::CanonicalCookie cookie; 43}; 44 45// Implementation of PersistentCookieStore that captures the 46// received commands and saves them to a list. 47// The result of calls to Load() can be configured using SetLoadExpectation(). 48class MockPersistentCookieStore 49 : public net::CookieMonster::PersistentCookieStore { 50 public: 51 typedef std::vector<CookieStoreCommand> CommandList; 52 53 MockPersistentCookieStore() : load_return_value_(true) { 54 } 55 56 virtual bool Load( 57 std::vector<net::CookieMonster::KeyedCanonicalCookie>* out_cookies) { 58 bool ok = load_return_value_; 59 if (ok) 60 *out_cookies = load_result_; 61 return ok; 62 } 63 64 virtual void AddCookie(const std::string& key, 65 const net::CookieMonster::CanonicalCookie& cookie) { 66 commands_.push_back( 67 CookieStoreCommand(CookieStoreCommand::ADD, key, cookie)); 68 } 69 70 virtual void UpdateCookieAccessTime( 71 const net::CookieMonster::CanonicalCookie& cookie) { 72 commands_.push_back(CookieStoreCommand( 73 CookieStoreCommand::UPDATE_ACCESS_TIME, std::string(), cookie)); 74 } 75 76 virtual void DeleteCookie( 77 const net::CookieMonster::CanonicalCookie& cookie) { 78 commands_.push_back( 79 CookieStoreCommand(CookieStoreCommand::REMOVE, std::string(), cookie)); 80 } 81 82 void SetLoadExpectation( 83 bool return_value, 84 const std::vector<net::CookieMonster::KeyedCanonicalCookie>& result) { 85 load_return_value_ = return_value; 86 load_result_ = result; 87 } 88 89 const CommandList& commands() const { 90 return commands_; 91 } 92 93 private: 94 CommandList commands_; 95 96 // Deferred result to use when Load() is called. 97 bool load_return_value_; 98 std::vector<net::CookieMonster::KeyedCanonicalCookie> load_result_; 99 100 DISALLOW_COPY_AND_ASSIGN(MockPersistentCookieStore); 101}; 102 103// Mock for CookieMonster::Delegate 104class MockCookieMonsterDelegate : public net::CookieMonster::Delegate { 105 public: 106 typedef std::pair<net::CookieMonster::CanonicalCookie, bool> 107 CookieNotification; 108 109 MockCookieMonsterDelegate() {} 110 111 virtual void OnCookieChanged( 112 const net::CookieMonster::CanonicalCookie& cookie, 113 bool removed) { 114 CookieNotification notification(cookie, removed); 115 changes_.push_back(notification); 116 } 117 118 const std::vector<CookieNotification>& changes() const { return changes_; } 119 120 void reset() { changes_.clear(); } 121 122 private: 123 virtual ~MockCookieMonsterDelegate() {} 124 125 std::vector<CookieNotification> changes_; 126 127 DISALLOW_COPY_AND_ASSIGN(MockCookieMonsterDelegate); 128}; 129 130// Helper to build a list of KeyedCanonicalCookies. 131void AddKeyedCookieToList( 132 const std::string& key, 133 const std::string& cookie_line, 134 const Time& creation_time, 135 std::vector<net::CookieMonster::KeyedCanonicalCookie>* out_list) { 136 137 // Parse the cookie line. 138 net::CookieMonster::ParsedCookie pc(cookie_line); 139 EXPECT_TRUE(pc.IsValid()); 140 141 // This helper is simplistic in interpreting a parsed cookie, in order to 142 // avoid duplicated CookieMonster's CanonPath() and CanonExpiration() 143 // functions. Would be nice to export them, and re-use here. 144 EXPECT_FALSE(pc.HasMaxAge()); 145 EXPECT_TRUE(pc.HasPath()); 146 Time cookie_expires = pc.HasExpires() ? 147 net::CookieMonster::ParseCookieTime(pc.Expires()) : Time(); 148 std::string cookie_path = pc.Path(); 149 150 scoped_ptr<net::CookieMonster::CanonicalCookie> cookie( 151 new net::CookieMonster::CanonicalCookie( 152 pc.Name(), pc.Value(), key, cookie_path, 153 pc.IsSecure(), pc.IsHttpOnly(), 154 creation_time, creation_time, 155 !cookie_expires.is_null(), 156 cookie_expires)); 157 158 out_list->push_back( 159 net::CookieMonster::KeyedCanonicalCookie( 160 key, cookie.release())); 161} 162 163// Helper for DeleteAllForHost test; repopulates CM with same layout 164// each time. 165const char* kTopLevelDomainPlus1 = "http://www.harvard.edu"; 166const char* kTopLevelDomainPlus2 = "http://www.math.harvard.edu"; 167const char* kTopLevelDomainPlus2Secure = "https://www.math.harvard.edu"; 168const char* kTopLevelDomainPlus3 = 169 "http://www.bourbaki.math.harvard.edu"; 170const char* kOtherDomain = "http://www.mit.edu"; 171 172void PopulateCmForDeleteAllForHost(scoped_refptr<net::CookieMonster> cm) { 173 GURL url_top_level_domain_plus_1(kTopLevelDomainPlus1); 174 GURL url_top_level_domain_plus_2(kTopLevelDomainPlus2); 175 GURL url_top_level_domain_plus_2_secure(kTopLevelDomainPlus2Secure); 176 GURL url_top_level_domain_plus_3(kTopLevelDomainPlus3); 177 GURL url_other(kOtherDomain); 178 179 cm->DeleteAll(true); 180 181 // Static population for probe: 182 // * Three levels of domain cookie (.b.a, .c.b.a, .d.c.b.a) 183 // * Three levels of host cookie (w.b.a, w.c.b.a, w.d.c.b.a) 184 // * http_only cookie (w.c.b.a) 185 // * Two secure cookies (.c.b.a, w.c.b.a) 186 // * Two domain path cookies (.c.b.a/dir1, .c.b.a/dir1/dir2) 187 // * Two host path cookies (w.c.b.a/dir1, w.c.b.a/dir1/dir2) 188 189 // Domain cookies 190 EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_1, 191 "dom_1", "X", ".harvard.edu", "/", 192 base::Time(), false, false)); 193 EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2, 194 "dom_2", "X", ".math.harvard.edu", "/", 195 base::Time(), false, false)); 196 EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_3, 197 "dom_3", "X", 198 ".bourbaki.math.harvard.edu", "/", 199 base::Time(), false, false)); 200 201 // Host cookies 202 EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_1, 203 "host_1", "X", "", "/", 204 base::Time(), false, false)); 205 EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2, 206 "host_2", "X", "", "/", 207 base::Time(), false, false)); 208 EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_3, 209 "host_3", "X", "", "/", 210 base::Time(), false, false)); 211 212 // Http_only cookie 213 EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2, 214 "httpo_check", "X", "", "/", 215 base::Time(), false, true)); 216 217 // Secure cookies 218 EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2_secure, 219 "sec_dom", "X", ".math.harvard.edu", 220 "/", base::Time(), true, false)); 221 EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2_secure, 222 "sec_host", "X", "", "/", 223 base::Time(), true, false)); 224 225 // Domain path cookies 226 EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2, 227 "dom_path_1", "X", 228 ".math.harvard.edu", "/dir1", 229 base::Time(), false, false)); 230 EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2, 231 "dom_path_2", "X", 232 ".math.harvard.edu", "/dir1/dir2", 233 base::Time(), false, false)); 234 235 // Host path cookies 236 EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2, 237 "host_path_1", "X", 238 "", "/dir1", 239 base::Time(), false, false)); 240 EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2, 241 "host_path_2", "X", 242 "", "/dir1/dir2", 243 base::Time(), false, false)); 244 245 EXPECT_EQ(13U, cm->GetAllCookies().size()); 246} 247 248} // namespace 249 250 251TEST(ParsedCookieTest, TestBasic) { 252 net::CookieMonster::ParsedCookie pc("a=b"); 253 EXPECT_TRUE(pc.IsValid()); 254 EXPECT_FALSE(pc.IsSecure()); 255 EXPECT_EQ("a", pc.Name()); 256 EXPECT_EQ("b", pc.Value()); 257} 258 259TEST(ParsedCookieTest, TestQuoted) { 260 // These are some quoting cases which the major browsers all 261 // handle differently. I've tested Internet Explorer 6, Opera 9.6, 262 // Firefox 3, and Safari Windows 3.2.1. We originally tried to match 263 // Firefox closely, however we now match Internet Explorer and Safari. 264 const char* values[] = { 265 // Trailing whitespace after a quoted value. The whitespace after 266 // the quote is stripped in all browsers. 267 "\"zzz \" ", "\"zzz \"", 268 // Handling a quoted value with a ';', like FOO="zz;pp" ; 269 // IE and Safari: "zz; 270 // Firefox and Opera: "zz;pp" 271 "\"zz;pp\" ;", "\"zz", 272 // Handling a value with multiple quoted parts, like FOO="zzz " "ppp" ; 273 // IE and Safari: "zzz " "ppp"; 274 // Firefox: "zzz "; 275 // Opera: <rejects cookie> 276 "\"zzz \" \"ppp\" ", "\"zzz \" \"ppp\"", 277 // A quote in a value that didn't start quoted. like FOO=A"B ; 278 // IE, Safari, and Firefox: A"B; 279 // Opera: <rejects cookie> 280 "A\"B", "A\"B", 281 }; 282 283 for (size_t i = 0; i < arraysize(values); i += 2) { 284 std::string input(values[i]); 285 std::string expected(values[i + 1]); 286 287 net::CookieMonster::ParsedCookie pc( 288 "aBc=" + input + " ; path=\"/\" ; httponly "); 289 EXPECT_TRUE(pc.IsValid()); 290 EXPECT_FALSE(pc.IsSecure()); 291 EXPECT_TRUE(pc.IsHttpOnly()); 292 EXPECT_TRUE(pc.HasPath()); 293 EXPECT_EQ("aBc", pc.Name()); 294 EXPECT_EQ(expected, pc.Value()); 295 296 // If a path was quoted, the path attribute keeps the quotes. This will 297 // make the cookie effectively useless, but path parameters aren't supposed 298 // to be quoted. Bug 1261605. 299 EXPECT_EQ("\"/\"", pc.Path()); 300 } 301} 302 303TEST(ParsedCookieTest, TestNameless) { 304 net::CookieMonster::ParsedCookie pc("BLAHHH; path=/; secure;"); 305 EXPECT_TRUE(pc.IsValid()); 306 EXPECT_TRUE(pc.IsSecure()); 307 EXPECT_TRUE(pc.HasPath()); 308 EXPECT_EQ("/", pc.Path()); 309 EXPECT_EQ("", pc.Name()); 310 EXPECT_EQ("BLAHHH", pc.Value()); 311} 312 313TEST(ParsedCookieTest, TestAttributeCase) { 314 net::CookieMonster::ParsedCookie pc("BLAHHH; Path=/; sECuRe; httpONLY"); 315 EXPECT_TRUE(pc.IsValid()); 316 EXPECT_TRUE(pc.IsSecure()); 317 EXPECT_TRUE(pc.IsHttpOnly()); 318 EXPECT_TRUE(pc.HasPath()); 319 EXPECT_EQ("/", pc.Path()); 320 EXPECT_EQ("", pc.Name()); 321 EXPECT_EQ("BLAHHH", pc.Value()); 322 EXPECT_EQ(3U, pc.NumberOfAttributes()); 323} 324 325TEST(ParsedCookieTest, TestDoubleQuotedNameless) { 326 net::CookieMonster::ParsedCookie pc("\"BLA\\\"HHH\"; path=/; secure;"); 327 EXPECT_TRUE(pc.IsValid()); 328 EXPECT_TRUE(pc.IsSecure()); 329 EXPECT_TRUE(pc.HasPath()); 330 EXPECT_EQ("/", pc.Path()); 331 EXPECT_EQ("", pc.Name()); 332 EXPECT_EQ("\"BLA\\\"HHH\"", pc.Value()); 333 EXPECT_EQ(2U, pc.NumberOfAttributes()); 334} 335 336TEST(ParsedCookieTest, QuoteOffTheEnd) { 337 net::CookieMonster::ParsedCookie pc("a=\"B"); 338 EXPECT_TRUE(pc.IsValid()); 339 EXPECT_EQ("a", pc.Name()); 340 EXPECT_EQ("\"B", pc.Value()); 341 EXPECT_EQ(0U, pc.NumberOfAttributes()); 342} 343 344TEST(ParsedCookieTest, MissingName) { 345 net::CookieMonster::ParsedCookie pc("=ABC"); 346 EXPECT_TRUE(pc.IsValid()); 347 EXPECT_EQ("", pc.Name()); 348 EXPECT_EQ("ABC", pc.Value()); 349 EXPECT_EQ(0U, pc.NumberOfAttributes()); 350} 351 352TEST(ParsedCookieTest, MissingValue) { 353 net::CookieMonster::ParsedCookie pc("ABC=; path = /wee"); 354 EXPECT_TRUE(pc.IsValid()); 355 EXPECT_EQ("ABC", pc.Name()); 356 EXPECT_EQ("", pc.Value()); 357 EXPECT_TRUE(pc.HasPath()); 358 EXPECT_EQ("/wee", pc.Path()); 359 EXPECT_EQ(1U, pc.NumberOfAttributes()); 360} 361 362TEST(ParsedCookieTest, Whitespace) { 363 net::CookieMonster::ParsedCookie pc(" A = BC ;secure;;; httponly"); 364 EXPECT_TRUE(pc.IsValid()); 365 EXPECT_EQ("A", pc.Name()); 366 EXPECT_EQ("BC", pc.Value()); 367 EXPECT_FALSE(pc.HasPath()); 368 EXPECT_FALSE(pc.HasDomain()); 369 EXPECT_TRUE(pc.IsSecure()); 370 EXPECT_TRUE(pc.IsHttpOnly()); 371 // We parse anything between ; as attributes, so we end up with two 372 // attributes with an empty string name and value. 373 EXPECT_EQ(4U, pc.NumberOfAttributes()); 374} 375TEST(ParsedCookieTest, MultipleEquals) { 376 net::CookieMonster::ParsedCookie pc(" A=== BC ;secure;;; httponly"); 377 EXPECT_TRUE(pc.IsValid()); 378 EXPECT_EQ("A", pc.Name()); 379 EXPECT_EQ("== BC", pc.Value()); 380 EXPECT_FALSE(pc.HasPath()); 381 EXPECT_FALSE(pc.HasDomain()); 382 EXPECT_TRUE(pc.IsSecure()); 383 EXPECT_TRUE(pc.IsHttpOnly()); 384 EXPECT_EQ(4U, pc.NumberOfAttributes()); 385} 386 387TEST(ParsedCookieTest, QuotedTrailingWhitespace) { 388 net::CookieMonster::ParsedCookie pc("ANCUUID=\"zohNumRKgI0oxyhSsV3Z7D\" ; " 389 "expires=Sun, 18-Apr-2027 21:06:29 GMT ; " 390 "path=/ ; "); 391 EXPECT_TRUE(pc.IsValid()); 392 EXPECT_EQ("ANCUUID", pc.Name()); 393 // Stripping whitespace after the quotes matches all other major browsers. 394 EXPECT_EQ("\"zohNumRKgI0oxyhSsV3Z7D\"", pc.Value()); 395 EXPECT_TRUE(pc.HasExpires()); 396 EXPECT_TRUE(pc.HasPath()); 397 EXPECT_EQ("/", pc.Path()); 398 EXPECT_EQ(2U, pc.NumberOfAttributes()); 399} 400 401TEST(ParsedCookieTest, TrailingWhitespace) { 402 net::CookieMonster::ParsedCookie pc("ANCUUID=zohNumRKgI0oxyhSsV3Z7D ; " 403 "expires=Sun, 18-Apr-2027 21:06:29 GMT ; " 404 "path=/ ; "); 405 EXPECT_TRUE(pc.IsValid()); 406 EXPECT_EQ("ANCUUID", pc.Name()); 407 EXPECT_EQ("zohNumRKgI0oxyhSsV3Z7D", pc.Value()); 408 EXPECT_TRUE(pc.HasExpires()); 409 EXPECT_TRUE(pc.HasPath()); 410 EXPECT_EQ("/", pc.Path()); 411 EXPECT_EQ(2U, pc.NumberOfAttributes()); 412} 413 414TEST(ParsedCookieTest, TooManyPairs) { 415 std::string blankpairs; 416 blankpairs.resize(net::CookieMonster::ParsedCookie::kMaxPairs - 1, ';'); 417 418 net::CookieMonster::ParsedCookie pc1(blankpairs + "secure"); 419 EXPECT_TRUE(pc1.IsValid()); 420 EXPECT_TRUE(pc1.IsSecure()); 421 422 net::CookieMonster::ParsedCookie pc2(blankpairs + ";secure"); 423 EXPECT_TRUE(pc2.IsValid()); 424 EXPECT_FALSE(pc2.IsSecure()); 425} 426 427// TODO some better test cases for invalid cookies. 428TEST(ParsedCookieTest, InvalidWhitespace) { 429 net::CookieMonster::ParsedCookie pc(" "); 430 EXPECT_FALSE(pc.IsValid()); 431} 432 433TEST(ParsedCookieTest, InvalidTooLong) { 434 std::string maxstr; 435 maxstr.resize(net::CookieMonster::ParsedCookie::kMaxCookieSize, 'a'); 436 437 net::CookieMonster::ParsedCookie pc1(maxstr); 438 EXPECT_TRUE(pc1.IsValid()); 439 440 net::CookieMonster::ParsedCookie pc2(maxstr + "A"); 441 EXPECT_FALSE(pc2.IsValid()); 442} 443 444TEST(ParsedCookieTest, InvalidEmpty) { 445 net::CookieMonster::ParsedCookie pc(""); 446 EXPECT_FALSE(pc.IsValid()); 447} 448 449TEST(ParsedCookieTest, EmbeddedTerminator) { 450 net::CookieMonster::ParsedCookie pc1("AAA=BB\0ZYX"); 451 net::CookieMonster::ParsedCookie pc2("AAA=BB\rZYX"); 452 net::CookieMonster::ParsedCookie pc3("AAA=BB\nZYX"); 453 EXPECT_TRUE(pc1.IsValid()); 454 EXPECT_EQ("AAA", pc1.Name()); 455 EXPECT_EQ("BB", pc1.Value()); 456 EXPECT_TRUE(pc2.IsValid()); 457 EXPECT_EQ("AAA", pc2.Name()); 458 EXPECT_EQ("BB", pc2.Value()); 459 EXPECT_TRUE(pc3.IsValid()); 460 EXPECT_EQ("AAA", pc3.Name()); 461 EXPECT_EQ("BB", pc3.Value()); 462} 463 464TEST(ParsedCookieTest, ParseTokensAndValues) { 465 EXPECT_EQ("hello", 466 net::CookieMonster::ParsedCookie::ParseTokenString( 467 "hello\nworld")); 468 EXPECT_EQ("fs!!@", 469 net::CookieMonster::ParsedCookie::ParseTokenString( 470 "fs!!@;helloworld")); 471 EXPECT_EQ("hello world\tgood", 472 net::CookieMonster::ParsedCookie::ParseTokenString( 473 "hello world\tgood\rbye")); 474 EXPECT_EQ("A", 475 net::CookieMonster::ParsedCookie::ParseTokenString( 476 "A=B=C;D=E")); 477 EXPECT_EQ("hello", 478 net::CookieMonster::ParsedCookie::ParseValueString( 479 "hello\nworld")); 480 EXPECT_EQ("fs!!@", 481 net::CookieMonster::ParsedCookie::ParseValueString( 482 "fs!!@;helloworld")); 483 EXPECT_EQ("hello world\tgood", 484 net::CookieMonster::ParsedCookie::ParseValueString( 485 "hello world\tgood\rbye")); 486 EXPECT_EQ("A=B=C", 487 net::CookieMonster::ParsedCookie::ParseValueString( 488 "A=B=C;D=E")); 489} 490 491static const char kUrlGoogle[] = "http://www.google.izzle"; 492static const char kUrlGoogleSecure[] = "https://www.google.izzle"; 493static const char kUrlFtp[] = "ftp://ftp.google.izzle/"; 494static const char kValidCookieLine[] = "A=B; path=/"; 495static const char kValidDomainCookieLine[] = "A=B; path=/; domain=google.izzle"; 496 497TEST(CookieMonsterTest, DomainTest) { 498 GURL url_google(kUrlGoogle); 499 500 scoped_refptr<MockPersistentCookieStore> store( 501 new MockPersistentCookieStore); 502 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, NULL)); 503 EXPECT_TRUE(cm->SetCookie(url_google, "A=B")); 504 EXPECT_EQ("A=B", cm->GetCookies(url_google)); 505 EXPECT_TRUE(cm->SetCookie(url_google, "C=D; domain=.google.izzle")); 506 EXPECT_EQ("A=B; C=D", cm->GetCookies(url_google)); 507 508 // Verify that A=B was set as a host cookie rather than a domain 509 // cookie -- should not be accessible from a sub sub-domain. 510 EXPECT_EQ("C=D", cm->GetCookies(GURL("http://foo.www.google.izzle"))); 511 512 // Test and make sure we find domain cookies on the same domain. 513 EXPECT_TRUE(cm->SetCookie(url_google, "E=F; domain=.www.google.izzle")); 514 EXPECT_EQ("A=B; C=D; E=F", cm->GetCookies(url_google)); 515 516 // Test setting a domain= that doesn't start w/ a dot, should 517 // treat it as a domain cookie, as if there was a pre-pended dot. 518 EXPECT_TRUE(cm->SetCookie(url_google, "G=H; domain=www.google.izzle")); 519 EXPECT_EQ("A=B; C=D; E=F; G=H", cm->GetCookies(url_google)); 520 521 // Test domain enforcement, should fail on a sub-domain or something too deep. 522 EXPECT_FALSE(cm->SetCookie(url_google, "I=J; domain=.izzle")); 523 EXPECT_EQ("", cm->GetCookies(GURL("http://a.izzle"))); 524 EXPECT_FALSE(cm->SetCookie(url_google, "K=L; domain=.bla.www.google.izzle")); 525 EXPECT_EQ("C=D; E=F; G=H", 526 cm->GetCookies(GURL("http://bla.www.google.izzle"))); 527 EXPECT_EQ("A=B; C=D; E=F; G=H", cm->GetCookies(url_google)); 528 529 // Nothing was persisted to the backing store. 530 EXPECT_EQ(0u, store->commands().size()); 531} 532 533// FireFox recognizes domains containing trailing periods as valid. 534// IE and Safari do not. Assert the expected policy here. 535TEST(CookieMonsterTest, DomainWithTrailingDotTest) { 536 scoped_refptr<MockPersistentCookieStore> store( 537 new MockPersistentCookieStore); 538 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, NULL)); 539 GURL url_google("http://www.google.com"); 540 541 EXPECT_FALSE(cm->SetCookie(url_google, "a=1; domain=.www.google.com.")); 542 EXPECT_FALSE(cm->SetCookie(url_google, "b=2; domain=.www.google.com..")); 543 EXPECT_EQ("", cm->GetCookies(url_google)); 544 545 // Nothing was persisted to the backing store. 546 EXPECT_EQ(0u, store->commands().size()); 547} 548 549// Test that cookies can bet set on higher level domains. 550// http://b/issue?id=896491 551TEST(CookieMonsterTest, ValidSubdomainTest) { 552 scoped_refptr<MockPersistentCookieStore> store( 553 new MockPersistentCookieStore); 554 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, NULL)); 555 GURL url_abcd("http://a.b.c.d.com"); 556 GURL url_bcd("http://b.c.d.com"); 557 GURL url_cd("http://c.d.com"); 558 GURL url_d("http://d.com"); 559 560 EXPECT_TRUE(cm->SetCookie(url_abcd, "a=1; domain=.a.b.c.d.com")); 561 EXPECT_TRUE(cm->SetCookie(url_abcd, "b=2; domain=.b.c.d.com")); 562 EXPECT_TRUE(cm->SetCookie(url_abcd, "c=3; domain=.c.d.com")); 563 EXPECT_TRUE(cm->SetCookie(url_abcd, "d=4; domain=.d.com")); 564 565 EXPECT_EQ("a=1; b=2; c=3; d=4", cm->GetCookies(url_abcd)); 566 EXPECT_EQ("b=2; c=3; d=4", cm->GetCookies(url_bcd)); 567 EXPECT_EQ("c=3; d=4", cm->GetCookies(url_cd)); 568 EXPECT_EQ("d=4", cm->GetCookies(url_d)); 569 570 // Check that the same cookie can exist on different sub-domains. 571 EXPECT_TRUE(cm->SetCookie(url_bcd, "X=bcd; domain=.b.c.d.com")); 572 EXPECT_TRUE(cm->SetCookie(url_bcd, "X=cd; domain=.c.d.com")); 573 EXPECT_EQ("b=2; c=3; d=4; X=bcd; X=cd", cm->GetCookies(url_bcd)); 574 EXPECT_EQ("c=3; d=4; X=cd", cm->GetCookies(url_cd)); 575 576 // Nothing was persisted to the backing store. 577 EXPECT_EQ(0u, store->commands().size()); 578} 579 580// Test that setting a cookie which specifies an invalid domain has 581// no side-effect. An invalid domain in this context is one which does 582// not match the originating domain. 583// http://b/issue?id=896472 584TEST(CookieMonsterTest, InvalidDomainTest) { 585 { 586 scoped_refptr<MockPersistentCookieStore> store( 587 new MockPersistentCookieStore); 588 589 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, NULL)); 590 GURL url_foobar("http://foo.bar.com"); 591 592 // More specific sub-domain than allowed. 593 EXPECT_FALSE(cm->SetCookie(url_foobar, "a=1; domain=.yo.foo.bar.com")); 594 595 EXPECT_FALSE(cm->SetCookie(url_foobar, "b=2; domain=.foo.com")); 596 EXPECT_FALSE(cm->SetCookie(url_foobar, "c=3; domain=.bar.foo.com")); 597 598 // Different TLD, but the rest is a substring. 599 EXPECT_FALSE(cm->SetCookie(url_foobar, "d=4; domain=.foo.bar.com.net")); 600 601 // A substring that isn't really a parent domain. 602 EXPECT_FALSE(cm->SetCookie(url_foobar, "e=5; domain=ar.com")); 603 604 // Completely invalid domains: 605 EXPECT_FALSE(cm->SetCookie(url_foobar, "f=6; domain=.")); 606 EXPECT_FALSE(cm->SetCookie(url_foobar, "g=7; domain=/")); 607 EXPECT_FALSE(cm->SetCookie(url_foobar, "h=8; domain=http://foo.bar.com")); 608 EXPECT_FALSE(cm->SetCookie(url_foobar, "i=9; domain=..foo.bar.com")); 609 EXPECT_FALSE(cm->SetCookie(url_foobar, "j=10; domain=..bar.com")); 610 611 // Make sure there isn't something quirky in the domain canonicalization 612 // that supports full URL semantics. 613 EXPECT_FALSE(cm->SetCookie(url_foobar, "k=11; domain=.foo.bar.com?blah")); 614 EXPECT_FALSE(cm->SetCookie(url_foobar, "l=12; domain=.foo.bar.com/blah")); 615 EXPECT_FALSE(cm->SetCookie(url_foobar, "m=13; domain=.foo.bar.com:80")); 616 EXPECT_FALSE(cm->SetCookie(url_foobar, "n=14; domain=.foo.bar.com:")); 617 EXPECT_FALSE(cm->SetCookie(url_foobar, "o=15; domain=.foo.bar.com#sup")); 618 619 EXPECT_EQ("", cm->GetCookies(url_foobar)); 620 621 // Nothing was persisted to the backing store. 622 EXPECT_EQ(0u, store->commands().size()); 623 } 624 625 { 626 // Make sure the cookie code hasn't gotten its subdomain string handling 627 // reversed, missed a suffix check, etc. It's important here that the two 628 // hosts below have the same domain + registry. 629 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 630 GURL url_foocom("http://foo.com.com"); 631 EXPECT_FALSE(cm->SetCookie(url_foocom, "a=1; domain=.foo.com.com.com")); 632 EXPECT_EQ("", cm->GetCookies(url_foocom)); 633 } 634} 635 636// Test the behavior of omitting dot prefix from domain, should 637// function the same as FireFox. 638// http://b/issue?id=889898 639TEST(CookieMonsterTest, DomainWithoutLeadingDotTest) { 640 { // The omission of dot results in setting a domain cookie. 641 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 642 GURL url_hosted("http://manage.hosted.filefront.com"); 643 GURL url_filefront("http://www.filefront.com"); 644 EXPECT_TRUE(cm->SetCookie(url_hosted, "sawAd=1; domain=filefront.com")); 645 EXPECT_EQ("sawAd=1", cm->GetCookies(url_hosted)); 646 EXPECT_EQ("sawAd=1", cm->GetCookies(url_filefront)); 647 } 648 649 { // Even when the domains match exactly, don't consider it host cookie. 650 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 651 GURL url("http://www.google.com"); 652 EXPECT_TRUE(cm->SetCookie(url, "a=1; domain=www.google.com")); 653 EXPECT_EQ("a=1", cm->GetCookies(url)); 654 EXPECT_EQ("a=1", cm->GetCookies(GURL("http://sub.www.google.com"))); 655 EXPECT_EQ("", cm->GetCookies(GURL("http://something-else.com"))); 656 } 657} 658 659// Test that the domain specified in cookie string is treated case-insensitive 660// http://b/issue?id=896475. 661TEST(CookieMonsterTest, CaseInsensitiveDomainTest) { 662 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 663 GURL url_google("http://www.google.com"); 664 EXPECT_TRUE(cm->SetCookie(url_google, "a=1; domain=.GOOGLE.COM")); 665 EXPECT_TRUE(cm->SetCookie(url_google, "b=2; domain=.wWw.gOOgLE.coM")); 666 EXPECT_EQ("a=1; b=2", cm->GetCookies(url_google)); 667} 668 669TEST(CookieMonsterTest, TestIpAddress) { 670 GURL url_ip("http://1.2.3.4/weee"); 671 { 672 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 673 EXPECT_TRUE(cm->SetCookie(url_ip, kValidCookieLine)); 674 EXPECT_EQ("A=B", cm->GetCookies(url_ip)); 675 } 676 677 { // IP addresses should not be able to set domain cookies. 678 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 679 EXPECT_FALSE(cm->SetCookie(url_ip, "b=2; domain=.1.2.3.4")); 680 EXPECT_FALSE(cm->SetCookie(url_ip, "c=3; domain=.3.4")); 681 EXPECT_EQ("", cm->GetCookies(url_ip)); 682 // It should be allowed to set a cookie if domain= matches the IP address 683 // exactly. This matches IE/Firefox, even though it seems a bit wrong. 684 EXPECT_FALSE(cm->SetCookie(url_ip, "b=2; domain=1.2.3.3")); 685 EXPECT_EQ("", cm->GetCookies(url_ip)); 686 EXPECT_TRUE(cm->SetCookie(url_ip, "b=2; domain=1.2.3.4")); 687 EXPECT_EQ("b=2", cm->GetCookies(url_ip)); 688 } 689} 690 691// Test host cookies, and setting of cookies on TLD. 692TEST(CookieMonsterTest, TestNonDottedAndTLD) { 693 { 694 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 695 GURL url("http://com/"); 696 // Allow setting on "com", (but only as a host cookie). 697 EXPECT_TRUE(cm->SetCookie(url, "a=1")); 698 EXPECT_FALSE(cm->SetCookie(url, "b=2; domain=.com")); 699 EXPECT_FALSE(cm->SetCookie(url, "c=3; domain=com")); 700 EXPECT_EQ("a=1", cm->GetCookies(url)); 701 // Make sure it doesn't show up for a normal .com, it should be a host 702 // not a domain cookie. 703 EXPECT_EQ("", cm->GetCookies(GURL("http://hopefully-no-cookies.com/"))); 704 EXPECT_EQ("", cm->GetCookies(GURL("http://.com/"))); 705 } 706 707 { // http://com. should be treated the same as http://com. 708 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 709 GURL url("http://com./index.html"); 710 EXPECT_TRUE(cm->SetCookie(url, "a=1")); 711 EXPECT_EQ("a=1", cm->GetCookies(url)); 712 EXPECT_EQ("", cm->GetCookies(GURL("http://hopefully-no-cookies.com./"))); 713 } 714 715 { // Should not be able to set host cookie from a subdomain. 716 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 717 GURL url("http://a.b"); 718 EXPECT_FALSE(cm->SetCookie(url, "a=1; domain=.b")); 719 EXPECT_FALSE(cm->SetCookie(url, "b=2; domain=b")); 720 EXPECT_EQ("", cm->GetCookies(url)); 721 } 722 723 { // Same test as above, but explicitly on a known TLD (com). 724 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 725 GURL url("http://google.com"); 726 EXPECT_FALSE(cm->SetCookie(url, "a=1; domain=.com")); 727 EXPECT_FALSE(cm->SetCookie(url, "b=2; domain=com")); 728 EXPECT_EQ("", cm->GetCookies(url)); 729 } 730 731 { // Make sure can't set cookie on TLD which is dotted. 732 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 733 GURL url("http://google.co.uk"); 734 EXPECT_FALSE(cm->SetCookie(url, "a=1; domain=.co.uk")); 735 EXPECT_FALSE(cm->SetCookie(url, "b=2; domain=.uk")); 736 EXPECT_EQ("", cm->GetCookies(url)); 737 EXPECT_EQ("", cm->GetCookies(GURL("http://something-else.co.uk"))); 738 EXPECT_EQ("", cm->GetCookies(GURL("http://something-else.uk"))); 739 } 740 741 { // Intranet URLs should only be able to set host cookies. 742 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 743 GURL url("http://b"); 744 EXPECT_TRUE(cm->SetCookie(url, "a=1")); 745 EXPECT_FALSE(cm->SetCookie(url, "b=2; domain=.b")); 746 EXPECT_FALSE(cm->SetCookie(url, "c=3; domain=b")); 747 EXPECT_EQ("a=1", cm->GetCookies(url)); 748 } 749} 750 751// Test reading/writing cookies when the domain ends with a period, 752// as in "www.google.com." 753TEST(CookieMonsterTest, TestHostEndsWithDot) { 754 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 755 GURL url("http://www.google.com"); 756 GURL url_with_dot("http://www.google.com."); 757 EXPECT_TRUE(cm->SetCookie(url, "a=1")); 758 EXPECT_EQ("a=1", cm->GetCookies(url)); 759 760 // Do not share cookie space with the dot version of domain. 761 // Note: this is not what FireFox does, but it _is_ what IE+Safari do. 762 EXPECT_FALSE(cm->SetCookie(url, "b=2; domain=.www.google.com.")); 763 EXPECT_EQ("a=1", cm->GetCookies(url)); 764 765 EXPECT_TRUE(cm->SetCookie(url_with_dot, "b=2; domain=.google.com.")); 766 EXPECT_EQ("b=2", cm->GetCookies(url_with_dot)); 767 768 // Make sure there weren't any side effects. 769 EXPECT_EQ(cm->GetCookies(GURL("http://hopefully-no-cookies.com/")), ""); 770 EXPECT_EQ("", cm->GetCookies(GURL("http://.com/"))); 771} 772 773TEST(CookieMonsterTest, InvalidScheme) { 774 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 775 EXPECT_FALSE(cm->SetCookie(GURL(kUrlFtp), kValidCookieLine)); 776} 777 778TEST(CookieMonsterTest, InvalidScheme_Read) { 779 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 780 EXPECT_TRUE(cm->SetCookie(GURL(kUrlGoogle), kValidDomainCookieLine)); 781 EXPECT_EQ("", cm->GetCookies(GURL(kUrlFtp))); 782} 783 784TEST(CookieMonsterTest, PathTest) { 785 std::string url("http://www.google.izzle"); 786 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 787 EXPECT_TRUE(cm->SetCookie(GURL(url), "A=B; path=/wee")); 788 EXPECT_EQ("A=B", cm->GetCookies(GURL(url + "/wee"))); 789 EXPECT_EQ("A=B", cm->GetCookies(GURL(url + "/wee/"))); 790 EXPECT_EQ("A=B", cm->GetCookies(GURL(url + "/wee/war"))); 791 EXPECT_EQ("A=B", cm->GetCookies(GURL(url + "/wee/war/more/more"))); 792 EXPECT_EQ("", cm->GetCookies(GURL(url + "/weehee"))); 793 EXPECT_EQ("", cm->GetCookies(GURL(url + "/"))); 794 795 // If we add a 0 length path, it should default to / 796 EXPECT_TRUE(cm->SetCookie(GURL(url), "A=C; path=")); 797 EXPECT_EQ("A=B; A=C", cm->GetCookies(GURL(url + "/wee"))); 798 EXPECT_EQ("A=C", cm->GetCookies(GURL(url + "/"))); 799} 800 801TEST(CookieMonsterTest, HttpOnlyTest) { 802 GURL url_google(kUrlGoogle); 803 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 804 net::CookieOptions options; 805 options.set_include_httponly(); 806 807 // Create a httponly cookie. 808 EXPECT_TRUE(cm->SetCookieWithOptions(url_google, "A=B; httponly", options)); 809 810 // Check httponly read protection. 811 EXPECT_EQ("", cm->GetCookies(url_google)); 812 EXPECT_EQ("A=B", cm->GetCookiesWithOptions(url_google, options)); 813 814 // Check httponly overwrite protection. 815 EXPECT_FALSE(cm->SetCookie(url_google, "A=C")); 816 EXPECT_EQ("", cm->GetCookies(url_google)); 817 EXPECT_EQ("A=B", cm->GetCookiesWithOptions(url_google, options)); 818 EXPECT_TRUE(cm->SetCookieWithOptions(url_google, "A=C", options)); 819 EXPECT_EQ("A=C", cm->GetCookies(url_google)); 820 821 // Check httponly create protection. 822 EXPECT_FALSE(cm->SetCookie(url_google, "B=A; httponly")); 823 EXPECT_EQ("A=C", cm->GetCookiesWithOptions(url_google, options)); 824 EXPECT_TRUE(cm->SetCookieWithOptions(url_google, "B=A; httponly", options)); 825 EXPECT_EQ("A=C; B=A", cm->GetCookiesWithOptions(url_google, options)); 826 EXPECT_EQ("A=C", cm->GetCookies(url_google)); 827} 828 829namespace { 830 831struct CookieDateParsingCase { 832 const char* str; 833 const bool valid; 834 const time_t epoch; 835}; 836 837struct DomainIsHostOnlyCase { 838 const char* str; 839 const bool is_host_only; 840}; 841 842} // namespace 843 844TEST(CookieMonsterTest, TestCookieDateParsing) { 845 const CookieDateParsingCase tests[] = { 846 { "Sat, 15-Apr-17 21:01:22 GMT", true, 1492290082 }, 847 { "Thu, 19-Apr-2007 16:00:00 GMT", true, 1176998400 }, 848 { "Wed, 25 Apr 2007 21:02:13 GMT", true, 1177534933 }, 849 { "Thu, 19/Apr\\2007 16:00:00 GMT", true, 1176998400 }, 850 { "Fri, 1 Jan 2010 01:01:50 GMT", true, 1262307710 }, 851 { "Wednesday, 1-Jan-2003 00:00:00 GMT", true, 1041379200 }, 852 { ", 1-Jan-2003 00:00:00 GMT", true, 1041379200 }, 853 { " 1-Jan-2003 00:00:00 GMT", true, 1041379200 }, 854 { "1-Jan-2003 00:00:00 GMT", true, 1041379200 }, 855 { "Wed,18-Apr-07 22:50:12 GMT", true, 1176936612 }, 856 { "WillyWonka , 18-Apr-07 22:50:12 GMT", true, 1176936612 }, 857 { "WillyWonka , 18-Apr-07 22:50:12", true, 1176936612 }, 858 { "WillyWonka , 18-apr-07 22:50:12", true, 1176936612 }, 859 { "Mon, 18-Apr-1977 22:50:13 GMT", true, 230251813 }, 860 { "Mon, 18-Apr-77 22:50:13 GMT", true, 230251813 }, 861 // If the cookie came in with the expiration quoted (which in terms of 862 // the RFC you shouldn't do), we will get string quoted. Bug 1261605. 863 { "\"Sat, 15-Apr-17\\\"21:01:22\\\"GMT\"", true, 1492290082 }, 864 // Test with full month names and partial names. 865 { "Partyday, 18- April-07 22:50:12", true, 1176936612 }, 866 { "Partyday, 18 - Apri-07 22:50:12", true, 1176936612 }, 867 { "Wednes, 1-Januar-2003 00:00:00 GMT", true, 1041379200 }, 868 // Test that we always take GMT even with other time zones or bogus 869 // values. The RFC says everything should be GMT, and in the worst case 870 // we are 24 hours off because of zone issues. 871 { "Sat, 15-Apr-17 21:01:22", true, 1492290082 }, 872 { "Sat, 15-Apr-17 21:01:22 GMT-2", true, 1492290082 }, 873 { "Sat, 15-Apr-17 21:01:22 GMT BLAH", true, 1492290082 }, 874 { "Sat, 15-Apr-17 21:01:22 GMT-0400", true, 1492290082 }, 875 { "Sat, 15-Apr-17 21:01:22 GMT-0400 (EDT)",true, 1492290082 }, 876 { "Sat, 15-Apr-17 21:01:22 DST", true, 1492290082 }, 877 { "Sat, 15-Apr-17 21:01:22 -0400", true, 1492290082 }, 878 { "Sat, 15-Apr-17 21:01:22 (hello there)", true, 1492290082 }, 879 // Test that if we encounter multiple : fields, that we take the first 880 // that correctly parses. 881 { "Sat, 15-Apr-17 21:01:22 11:22:33", true, 1492290082 }, 882 { "Sat, 15-Apr-17 ::00 21:01:22", true, 1492290082 }, 883 { "Sat, 15-Apr-17 boink:z 21:01:22", true, 1492290082 }, 884 // We take the first, which in this case is invalid. 885 { "Sat, 15-Apr-17 91:22:33 21:01:22", false, 0 }, 886 // amazon.com formats their cookie expiration like this. 887 { "Thu Apr 18 22:50:12 2007 GMT", true, 1176936612 }, 888 // Test that hh:mm:ss can occur anywhere. 889 { "22:50:12 Thu Apr 18 2007 GMT", true, 1176936612 }, 890 { "Thu 22:50:12 Apr 18 2007 GMT", true, 1176936612 }, 891 { "Thu Apr 22:50:12 18 2007 GMT", true, 1176936612 }, 892 { "Thu Apr 18 22:50:12 2007 GMT", true, 1176936612 }, 893 { "Thu Apr 18 2007 22:50:12 GMT", true, 1176936612 }, 894 { "Thu Apr 18 2007 GMT 22:50:12", true, 1176936612 }, 895 // Test that the day and year can be anywhere if they are unambigious. 896 { "Sat, 15-Apr-17 21:01:22 GMT", true, 1492290082 }, 897 { "15-Sat, Apr-17 21:01:22 GMT", true, 1492290082 }, 898 { "15-Sat, Apr 21:01:22 GMT 17", true, 1492290082 }, 899 { "15-Sat, Apr 21:01:22 GMT 2017", true, 1492290082 }, 900 { "15 Apr 21:01:22 2017", true, 1492290082 }, 901 { "15 17 Apr 21:01:22", true, 1492290082 }, 902 { "Apr 15 17 21:01:22", true, 1492290082 }, 903 { "Apr 15 21:01:22 17", true, 1492290082 }, 904 { "2017 April 15 21:01:22", true, 1492290082 }, 905 { "15 April 2017 21:01:22", true, 1492290082 }, 906 // Some invalid dates 907 { "98 April 17 21:01:22", false, 0 }, 908 { "Thu, 012-Aug-2008 20:49:07 GMT", false, 0 }, 909 { "Thu, 12-Aug-31841 20:49:07 GMT", false, 0 }, 910 { "Thu, 12-Aug-9999999999 20:49:07 GMT", false, 0 }, 911 { "Thu, 999999999999-Aug-2007 20:49:07 GMT", false, 0 }, 912 { "Thu, 12-Aug-2007 20:61:99999999999 GMT", false, 0 }, 913 { "IAintNoDateFool", false, 0 }, 914 }; 915 916 Time parsed_time; 917 for (size_t i = 0; i < arraysize(tests); ++i) { 918 parsed_time = net::CookieMonster::ParseCookieTime(tests[i].str); 919 if (!tests[i].valid) { 920 EXPECT_FALSE(!parsed_time.is_null()) << tests[i].str; 921 continue; 922 } 923 EXPECT_TRUE(!parsed_time.is_null()) << tests[i].str; 924 EXPECT_EQ(tests[i].epoch, parsed_time.ToTimeT()) << tests[i].str; 925 } 926} 927 928TEST(CookieMonsterTest, TestDomainIsHostOnly) { 929 const DomainIsHostOnlyCase tests[] = { 930 { "", true }, 931 { "www.google.com", true }, 932 { ".google.com", false } 933 }; 934 935 for (size_t i = 0; i < arraysize(tests); ++i) { 936 EXPECT_EQ(tests[i].is_host_only, 937 net::CookieMonster::DomainIsHostOnly(tests[i].str)); 938 } 939} 940 941TEST(CookieMonsterTest, TestCookieDeletion) { 942 GURL url_google(kUrlGoogle); 943 scoped_refptr<MockPersistentCookieStore> store( 944 new MockPersistentCookieStore); 945 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, NULL)); 946 947 // Create a session cookie. 948 EXPECT_TRUE(cm->SetCookie(url_google, kValidCookieLine)); 949 EXPECT_EQ("A=B", cm->GetCookies(url_google)); 950 // Delete it via Max-Age. 951 EXPECT_TRUE(cm->SetCookie(url_google, 952 std::string(kValidCookieLine) + "; max-age=0")); 953 EXPECT_EQ("", cm->GetCookies(url_google)); 954 955 // Create a session cookie. 956 EXPECT_TRUE(cm->SetCookie(url_google, kValidCookieLine)); 957 EXPECT_EQ("A=B", cm->GetCookies(url_google)); 958 // Delete it via Expires. 959 EXPECT_TRUE(cm->SetCookie(url_google, 960 std::string(kValidCookieLine) + 961 "; expires=Mon, 18-Apr-1977 22:50:13 GMT")); 962 EXPECT_EQ("", cm->GetCookies(url_google)); 963 964 // Create a persistent cookie. 965 EXPECT_TRUE(cm->SetCookie(url_google, 966 std::string(kValidCookieLine) + 967 "; expires=Mon, 18-Apr-22 22:50:13 GMT")); 968 ASSERT_EQ(1u, store->commands().size()); 969 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type); 970 971 EXPECT_EQ("A=B", cm->GetCookies(url_google)); 972 // Delete it via Max-Age. 973 EXPECT_TRUE(cm->SetCookie(url_google, 974 std::string(kValidCookieLine) + "; max-age=0")); 975 ASSERT_EQ(2u, store->commands().size()); 976 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type); 977 EXPECT_EQ("", cm->GetCookies(url_google)); 978 979 // Create a persistent cookie. 980 EXPECT_TRUE(cm->SetCookie(url_google, 981 std::string(kValidCookieLine) + 982 "; expires=Mon, 18-Apr-22 22:50:13 GMT")); 983 ASSERT_EQ(3u, store->commands().size()); 984 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type); 985 EXPECT_EQ("A=B", cm->GetCookies(url_google)); 986 // Delete it via Expires. 987 EXPECT_TRUE(cm->SetCookie(url_google, 988 std::string(kValidCookieLine) + 989 "; expires=Mon, 18-Apr-1977 22:50:13 GMT")); 990 ASSERT_EQ(4u, store->commands().size()); 991 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type); 992 EXPECT_EQ("", cm->GetCookies(url_google)); 993 994 // Create a persistent cookie. 995 EXPECT_TRUE(cm->SetCookie(url_google, 996 std::string(kValidCookieLine) + 997 "; expires=Mon, 18-Apr-22 22:50:13 GMT")); 998 ASSERT_EQ(5u, store->commands().size()); 999 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[4].type); 1000 EXPECT_EQ("A=B", cm->GetCookies(url_google)); 1001 // Delete it via Expires, with a unix epoch of 0. 1002 EXPECT_TRUE(cm->SetCookie(url_google, 1003 std::string(kValidCookieLine) + 1004 "; expires=Thu, 1-Jan-1970 00:00:00 GMT")); 1005 ASSERT_EQ(6u, store->commands().size()); 1006 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[5].type); 1007 EXPECT_EQ("", cm->GetCookies(url_google)); 1008} 1009 1010TEST(CookieMonsterTest, TestCookieDeleteAll) { 1011 GURL url_google(kUrlGoogle); 1012 scoped_refptr<MockPersistentCookieStore> store( 1013 new MockPersistentCookieStore); 1014 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, NULL)); 1015 net::CookieOptions options; 1016 options.set_include_httponly(); 1017 1018 EXPECT_TRUE(cm->SetCookie(url_google, kValidCookieLine)); 1019 EXPECT_EQ("A=B", cm->GetCookies(url_google)); 1020 1021 EXPECT_TRUE(cm->SetCookieWithOptions(url_google, "C=D; httponly", options)); 1022 EXPECT_EQ("A=B; C=D", cm->GetCookiesWithOptions(url_google, options)); 1023 1024 EXPECT_EQ(2, cm->DeleteAll(false)); 1025 EXPECT_EQ("", cm->GetCookiesWithOptions(url_google, options)); 1026 1027 EXPECT_EQ(0u, store->commands().size()); 1028 1029 // Create a persistent cookie. 1030 EXPECT_TRUE(cm->SetCookie(url_google, 1031 std::string(kValidCookieLine) + 1032 "; expires=Mon, 18-Apr-22 22:50:13 GMT")); 1033 ASSERT_EQ(1u, store->commands().size()); 1034 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type); 1035 1036 EXPECT_EQ(1, cm->DeleteAll(true)); // sync_to_store = true. 1037 ASSERT_EQ(2u, store->commands().size()); 1038 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type); 1039 1040 EXPECT_EQ("", cm->GetCookiesWithOptions(url_google, options)); 1041} 1042 1043TEST(CookieMonsterTest, TestCookieDeleteAllCreatedAfterTimestamp) { 1044 GURL url_google(kUrlGoogle); 1045 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 1046 Time now = Time::Now(); 1047 1048 // Nothing has been added so nothing should be deleted. 1049 EXPECT_EQ(0, cm->DeleteAllCreatedAfter(now - TimeDelta::FromDays(99), false)); 1050 1051 // Create 3 cookies with creation date of today, yesterday and the day before. 1052 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-0=Now", now)); 1053 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-1=Yesterday", 1054 now - TimeDelta::FromDays(1))); 1055 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-2=DayBefore", 1056 now - TimeDelta::FromDays(2))); 1057 1058 // Try to delete everything from now onwards. 1059 EXPECT_EQ(1, cm->DeleteAllCreatedAfter(now, false)); 1060 // Now delete the one cookie created in the last day. 1061 EXPECT_EQ(1, cm->DeleteAllCreatedAfter(now - TimeDelta::FromDays(1), false)); 1062 // Now effectively delete all cookies just created (1 is remaining). 1063 EXPECT_EQ(1, cm->DeleteAllCreatedAfter(now - TimeDelta::FromDays(99), false)); 1064 1065 // Make sure everything is gone. 1066 EXPECT_EQ(0, cm->DeleteAllCreatedAfter(Time(), false)); 1067 // Really make sure everything is gone. 1068 EXPECT_EQ(0, cm->DeleteAll(false)); 1069} 1070 1071TEST(CookieMonsterTest, TestCookieDeleteAllCreatedBetweenTimestamps) { 1072 GURL url_google(kUrlGoogle); 1073 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 1074 Time now = Time::Now(); 1075 1076 // Nothing has been added so nothing should be deleted. 1077 EXPECT_EQ(0, cm->DeleteAllCreatedAfter(now - TimeDelta::FromDays(99), false)); 1078 1079 // Create 3 cookies with creation date of today, yesterday and the day before. 1080 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-0=Now", now)); 1081 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-1=Yesterday", 1082 now - TimeDelta::FromDays(1))); 1083 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-2=DayBefore", 1084 now - TimeDelta::FromDays(2))); 1085 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-3=ThreeDays", 1086 now - TimeDelta::FromDays(3))); 1087 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-7=LastWeek", 1088 now - TimeDelta::FromDays(7))); 1089 1090 // Try to delete threedays and the daybefore. 1091 EXPECT_EQ(2, cm->DeleteAllCreatedBetween(now - TimeDelta::FromDays(3), 1092 now - TimeDelta::FromDays(1), 1093 false)); 1094 1095 // Try to delete yesterday, also make sure that delete_end is not 1096 // inclusive. 1097 EXPECT_EQ(1, cm->DeleteAllCreatedBetween(now - TimeDelta::FromDays(2), 1098 now, 1099 false)); 1100 1101 // Make sure the delete_begin is inclusive. 1102 EXPECT_EQ(1, cm->DeleteAllCreatedBetween(now - TimeDelta::FromDays(7), 1103 now, 1104 false)); 1105 1106 // Delete the last (now) item. 1107 EXPECT_EQ(1, cm->DeleteAllCreatedAfter(Time(), false)); 1108 1109 // Really make sure everything is gone. 1110 EXPECT_EQ(0, cm->DeleteAll(false)); 1111} 1112 1113TEST(CookieMonsterTest, TestSecure) { 1114 GURL url_google(kUrlGoogle); 1115 GURL url_google_secure(kUrlGoogleSecure); 1116 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 1117 1118 EXPECT_TRUE(cm->SetCookie(url_google, "A=B")); 1119 EXPECT_EQ("A=B", cm->GetCookies(url_google)); 1120 EXPECT_EQ("A=B", cm->GetCookies(url_google_secure)); 1121 1122 EXPECT_TRUE(cm->SetCookie(url_google_secure, "A=B; secure")); 1123 // The secure should overwrite the non-secure. 1124 EXPECT_EQ("", cm->GetCookies(url_google)); 1125 EXPECT_EQ("A=B", cm->GetCookies(url_google_secure)); 1126 1127 EXPECT_TRUE(cm->SetCookie(url_google_secure, "D=E; secure")); 1128 EXPECT_EQ("", cm->GetCookies(url_google)); 1129 EXPECT_EQ("A=B; D=E", cm->GetCookies(url_google_secure)); 1130 1131 EXPECT_TRUE(cm->SetCookie(url_google_secure, "A=B")); 1132 // The non-secure should overwrite the secure. 1133 EXPECT_EQ("A=B", cm->GetCookies(url_google)); 1134 EXPECT_EQ("D=E; A=B", cm->GetCookies(url_google_secure)); 1135} 1136 1137static Time GetFirstCookieAccessDate(net::CookieMonster* cm) { 1138 const net::CookieMonster::CookieList all_cookies(cm->GetAllCookies()); 1139 return all_cookies.front().LastAccessDate(); 1140} 1141 1142static const int kLastAccessThresholdMilliseconds = 200; 1143 1144TEST(CookieMonsterTest, TestLastAccess) { 1145 GURL url_google(kUrlGoogle); 1146 scoped_refptr<net::CookieMonster> cm( 1147 new net::CookieMonster(NULL, NULL, kLastAccessThresholdMilliseconds)); 1148 1149 EXPECT_TRUE(cm->SetCookie(url_google, "A=B")); 1150 const Time last_access_date(GetFirstCookieAccessDate(cm)); 1151 1152 // Reading the cookie again immediately shouldn't update the access date, 1153 // since we're inside the threshold. 1154 EXPECT_EQ("A=B", cm->GetCookies(url_google)); 1155 EXPECT_TRUE(last_access_date == GetFirstCookieAccessDate(cm)); 1156 1157 // Reading after a short wait should update the access date. 1158 PlatformThread::Sleep(kLastAccessThresholdMilliseconds + 20); 1159 EXPECT_EQ("A=B", cm->GetCookies(url_google)); 1160 EXPECT_FALSE(last_access_date == GetFirstCookieAccessDate(cm)); 1161} 1162 1163static int CountInString(const std::string& str, char c) { 1164 int count = 0; 1165 for (std::string::const_iterator it = str.begin(); 1166 it != str.end(); ++it) { 1167 if (*it == c) 1168 ++count; 1169 } 1170 return count; 1171} 1172 1173TEST(CookieMonsterTest, TestHostGarbageCollection) { 1174 GURL url_google(kUrlGoogle); 1175 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 1176 // Add a bunch of cookies on a single host, should purge them. 1177 for (int i = 0; i < 101; i++) { 1178 std::string cookie = StringPrintf("a%03d=b", i); 1179 EXPECT_TRUE(cm->SetCookie(url_google, cookie)); 1180 std::string cookies = cm->GetCookies(url_google); 1181 // Make sure we find it in the cookies. 1182 EXPECT_TRUE(cookies.find(cookie) != std::string::npos); 1183 // Count the number of cookies. 1184 EXPECT_LE(CountInString(cookies, '='), 70); 1185 } 1186} 1187 1188TEST(CookieMonsterTest, TestTotalGarbageCollection) { 1189 scoped_refptr<net::CookieMonster> cm( 1190 new net::CookieMonster(NULL, NULL, kLastAccessThresholdMilliseconds)); 1191 1192 // Add a bunch of cookies on a bunch of host, some should get purged. 1193 const GURL sticky_cookie("http://a0000.izzle"); 1194 for (int i = 0; i < 4000; ++i) { 1195 GURL url(StringPrintf("http://a%04d.izzle", i)); 1196 EXPECT_TRUE(cm->SetCookie(url, "a=b")); 1197 EXPECT_EQ("a=b", cm->GetCookies(url)); 1198 1199 // Keep touching the first cookie to ensure it's not purged (since it will 1200 // always have the most recent access time). 1201 if (!(i % 500)) { 1202 // Ensure the timestamps will be different enough to update. 1203 PlatformThread::Sleep(kLastAccessThresholdMilliseconds + 20); 1204 EXPECT_EQ("a=b", cm->GetCookies(sticky_cookie)); 1205 } 1206 } 1207 1208 // Check that cookies that still exist. 1209 for (int i = 0; i < 4000; ++i) { 1210 GURL url(StringPrintf("http://a%04d.izzle", i)); 1211 if ((i == 0) || (i > 1001)) { 1212 // Cookies should still be around. 1213 EXPECT_FALSE(cm->GetCookies(url).empty()); 1214 } else if (i < 701) { 1215 // Cookies should have gotten purged. 1216 EXPECT_TRUE(cm->GetCookies(url).empty()); 1217 } 1218 } 1219} 1220 1221// Formerly NetUtilTest.CookieTest back when we used wininet's cookie handling. 1222TEST(CookieMonsterTest, NetUtilCookieTest) { 1223 const GURL test_url("http://mojo.jojo.google.izzle/"); 1224 1225 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 1226 1227 EXPECT_TRUE(cm->SetCookie(test_url, "foo=bar")); 1228 std::string value = cm->GetCookies(test_url); 1229 EXPECT_EQ("foo=bar", value); 1230 1231 // test that we can retrieve all cookies: 1232 EXPECT_TRUE(cm->SetCookie(test_url, "x=1")); 1233 EXPECT_TRUE(cm->SetCookie(test_url, "y=2")); 1234 1235 std::string result = cm->GetCookies(test_url); 1236 EXPECT_FALSE(result.empty()); 1237 EXPECT_NE(result.find("x=1"), std::string::npos) << result; 1238 EXPECT_NE(result.find("y=2"), std::string::npos) << result; 1239} 1240 1241static bool FindAndDeleteCookie(net::CookieMonster* cm, 1242 const std::string& domain, 1243 const std::string& name) { 1244 net::CookieMonster::CookieList cookies = cm->GetAllCookies(); 1245 for (net::CookieMonster::CookieList::iterator it = cookies.begin(); 1246 it != cookies.end(); ++it) 1247 if (it->Domain() == domain && it->Name() == name) 1248 return cm->DeleteCookie(domain, *it, false); 1249 return false; 1250} 1251 1252TEST(CookieMonsterTest, TestDeleteSingleCookie) { 1253 GURL url_google(kUrlGoogle); 1254 1255 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 1256 1257 EXPECT_TRUE(cm->SetCookie(url_google, "A=B")); 1258 EXPECT_TRUE(cm->SetCookie(url_google, "C=D")); 1259 EXPECT_TRUE(cm->SetCookie(url_google, "E=F")); 1260 EXPECT_EQ("A=B; C=D; E=F", cm->GetCookies(url_google)); 1261 1262 EXPECT_TRUE(FindAndDeleteCookie(cm, url_google.host(), "C")); 1263 EXPECT_EQ("A=B; E=F", cm->GetCookies(url_google)); 1264 1265 EXPECT_FALSE(FindAndDeleteCookie(cm, "random.host", "E")); 1266 EXPECT_EQ("A=B; E=F", cm->GetCookies(url_google)); 1267} 1268 1269TEST(CookieMonsterTest, SetCookieableSchemes) { 1270 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 1271 scoped_refptr<net::CookieMonster> cm_foo(new net::CookieMonster(NULL, NULL)); 1272 1273 // Only cm_foo should allow foo:// cookies. 1274 const char* kSchemes[] = {"foo"}; 1275 cm_foo->SetCookieableSchemes(kSchemes, 1); 1276 1277 GURL foo_url("foo://host/path"); 1278 GURL http_url("http://host/path"); 1279 1280 EXPECT_TRUE(cm->SetCookie(http_url, "x=1")); 1281 EXPECT_FALSE(cm->SetCookie(foo_url, "x=1")); 1282 EXPECT_TRUE(cm_foo->SetCookie(foo_url, "x=1")); 1283 EXPECT_FALSE(cm_foo->SetCookie(http_url, "x=1")); 1284} 1285 1286TEST(CookieMonsterTest, GetAllCookiesForURL) { 1287 GURL url_google(kUrlGoogle); 1288 GURL url_google_secure(kUrlGoogleSecure); 1289 1290 scoped_refptr<net::CookieMonster> cm( 1291 new net::CookieMonster(NULL, NULL, kLastAccessThresholdMilliseconds)); 1292 1293 // Create an httponly cookie. 1294 net::CookieOptions options; 1295 options.set_include_httponly(); 1296 1297 EXPECT_TRUE(cm->SetCookieWithOptions(url_google, "A=B; httponly", options)); 1298 EXPECT_TRUE(cm->SetCookieWithOptions(url_google, 1299 "C=D; domain=.google.izzle", 1300 options)); 1301 EXPECT_TRUE(cm->SetCookieWithOptions(url_google_secure, 1302 "E=F; domain=.google.izzle; secure", 1303 options)); 1304 1305 const Time last_access_date(GetFirstCookieAccessDate(cm)); 1306 1307 PlatformThread::Sleep(kLastAccessThresholdMilliseconds + 20); 1308 1309 // Check cookies for url. 1310 net::CookieMonster::CookieList cookies = 1311 cm->GetAllCookiesForURL(url_google); 1312 net::CookieMonster::CookieList::iterator it = cookies.begin(); 1313 1314 ASSERT_TRUE(it != cookies.end()); 1315 EXPECT_EQ("www.google.izzle", it->Domain()); 1316 EXPECT_EQ("A", it->Name()); 1317 1318 ASSERT_TRUE(++it != cookies.end()); 1319 EXPECT_EQ(".google.izzle", it->Domain()); 1320 EXPECT_EQ("C", it->Name()); 1321 1322 ASSERT_TRUE(++it == cookies.end()); 1323 1324 // Test secure cookies. 1325 cookies = cm->GetAllCookiesForURL(url_google_secure); 1326 it = cookies.begin(); 1327 1328 ASSERT_TRUE(it != cookies.end()); 1329 EXPECT_EQ("www.google.izzle", it->Domain()); 1330 EXPECT_EQ("A", it->Name()); 1331 1332 ASSERT_TRUE(++it != cookies.end()); 1333 EXPECT_EQ(".google.izzle", it->Domain()); 1334 EXPECT_EQ("C", it->Name()); 1335 1336 ASSERT_TRUE(++it != cookies.end()); 1337 EXPECT_EQ(".google.izzle", it->Domain()); 1338 EXPECT_EQ("E", it->Name()); 1339 1340 ASSERT_TRUE(++it == cookies.end()); 1341 1342 // Reading after a short wait should not update the access date. 1343 EXPECT_TRUE(last_access_date == GetFirstCookieAccessDate(cm)); 1344} 1345 1346TEST(CookieMonsterTest, GetAllCookiesForURLPathMatching) { 1347 GURL url_google(kUrlGoogle); 1348 GURL url_google_foo("http://www.google.izzle/foo"); 1349 GURL url_google_bar("http://www.google.izzle/bar"); 1350 1351 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 1352 net::CookieOptions options; 1353 1354 EXPECT_TRUE(cm->SetCookieWithOptions(url_google_foo, 1355 "A=B; path=/foo;", 1356 options)); 1357 EXPECT_TRUE(cm->SetCookieWithOptions(url_google_bar, 1358 "C=D; path=/bar;", 1359 options)); 1360 EXPECT_TRUE(cm->SetCookieWithOptions(url_google, 1361 "E=F;", 1362 options)); 1363 1364 net::CookieMonster::CookieList cookies = 1365 cm->GetAllCookiesForURL(url_google_foo); 1366 net::CookieMonster::CookieList::iterator it = cookies.begin(); 1367 1368 ASSERT_TRUE(it != cookies.end()); 1369 EXPECT_EQ("A", it->Name()); 1370 EXPECT_EQ("/foo", it->Path()); 1371 1372 ASSERT_TRUE(++it != cookies.end()); 1373 EXPECT_EQ("E", it->Name()); 1374 EXPECT_EQ("/", it->Path()); 1375 1376 ASSERT_TRUE(++it == cookies.end()); 1377 1378 cookies = cm->GetAllCookiesForURL(url_google_bar); 1379 it = cookies.begin(); 1380 1381 ASSERT_TRUE(it != cookies.end()); 1382 EXPECT_EQ("C", it->Name()); 1383 EXPECT_EQ("/bar", it->Path()); 1384 1385 ASSERT_TRUE(++it != cookies.end()); 1386 EXPECT_EQ("E", it->Name()); 1387 EXPECT_EQ("/", it->Path()); 1388 1389 ASSERT_TRUE(++it == cookies.end()); 1390} 1391 1392TEST(CookieMonsterTest, DeleteCookieByName) { 1393 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 1394 GURL url_google(kUrlGoogle); 1395 1396 EXPECT_TRUE(cm->SetCookie(url_google, "A=A1; path=/")); 1397 EXPECT_TRUE(cm->SetCookie(url_google, "A=A2; path=/foo")); 1398 EXPECT_TRUE(cm->SetCookie(url_google, "A=A3; path=/bar")); 1399 EXPECT_TRUE(cm->SetCookie(url_google, "B=B1; path=/")); 1400 EXPECT_TRUE(cm->SetCookie(url_google, "B=B2; path=/foo")); 1401 EXPECT_TRUE(cm->SetCookie(url_google, "B=B3; path=/bar")); 1402 1403 cm->DeleteCookie(GURL(std::string(kUrlGoogle) + "/foo/bar"), "A"); 1404 1405 net::CookieMonster::CookieList cookies = cm->GetAllCookies(); 1406 size_t expected_size = 4; 1407 EXPECT_EQ(expected_size, cookies.size()); 1408 for (net::CookieMonster::CookieList::iterator it = cookies.begin(); 1409 it != cookies.end(); ++it) { 1410 EXPECT_NE("A1", it->Value()); 1411 EXPECT_NE("A2", it->Value()); 1412 } 1413} 1414 1415// Test that overwriting persistent cookies deletes the old one from the 1416// backing store. 1417TEST(CookieMonsterTest, OverwritePersistentCookie) { 1418 GURL url_google("http://www.google.com/"); 1419 GURL url_chromium("http://chromium.org"); 1420 scoped_refptr<MockPersistentCookieStore> store( 1421 new MockPersistentCookieStore); 1422 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, NULL)); 1423 1424 // Insert a cookie "a" for path "/path1" 1425 EXPECT_TRUE( 1426 cm->SetCookie(url_google, "a=val1; path=/path1; " 1427 "expires=Mon, 18-Apr-22 22:50:13 GMT")); 1428 ASSERT_EQ(1u, store->commands().size()); 1429 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type); 1430 1431 // Insert a cookie "b" for path "/path1" 1432 EXPECT_TRUE( 1433 cm->SetCookie(url_google, "b=val1; path=/path1; " 1434 "expires=Mon, 18-Apr-22 22:50:14 GMT")); 1435 ASSERT_EQ(2u, store->commands().size()); 1436 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[1].type); 1437 1438 // Insert a cookie "b" for path "/path1", that is httponly. This should 1439 // overwrite the non-http-only version. 1440 net::CookieOptions allow_httponly; 1441 allow_httponly.set_include_httponly(); 1442 EXPECT_TRUE( 1443 cm->SetCookieWithOptions(url_google, 1444 "b=val2; path=/path1; httponly; " 1445 "expires=Mon, 18-Apr-22 22:50:14 GMT", 1446 allow_httponly)); 1447 ASSERT_EQ(4u, store->commands().size()); 1448 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[2].type); 1449 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[3].type); 1450 1451 // Insert a cookie "a" for path "/path1". This should overwrite. 1452 EXPECT_TRUE(cm->SetCookie(url_google, 1453 "a=val33; path=/path1; " 1454 "expires=Mon, 18-Apr-22 22:50:14 GMT")); 1455 ASSERT_EQ(6u, store->commands().size()); 1456 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[4].type); 1457 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[5].type); 1458 1459 // Insert a cookie "a" for path "/path2". This should NOT overwrite 1460 // cookie "a", since the path is different. 1461 EXPECT_TRUE(cm->SetCookie(url_google, 1462 "a=val9; path=/path2; " 1463 "expires=Mon, 18-Apr-22 22:50:14 GMT")); 1464 ASSERT_EQ(7u, store->commands().size()); 1465 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[6].type); 1466 1467 // Insert a cookie "a" for path "/path1", but this time for "chromium.org". 1468 // Although the name and path match, the hostnames do not, so shouldn't 1469 // overwrite. 1470 EXPECT_TRUE(cm->SetCookie(url_chromium, 1471 "a=val99; path=/path1; " 1472 "expires=Mon, 18-Apr-22 22:50:14 GMT")); 1473 ASSERT_EQ(8u, store->commands().size()); 1474 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[7].type); 1475 1476 EXPECT_EQ("a=val33", cm->GetCookies(GURL("http://www.google.com/path1"))); 1477 EXPECT_EQ("a=val9", cm->GetCookies(GURL("http://www.google.com/path2"))); 1478 EXPECT_EQ("a=val99", cm->GetCookies(GURL("http://chromium.org/path1"))); 1479} 1480 1481// Tests importing from a persistent cookie store that contains duplicate 1482// equivalent cookies. This situation should be handled by removing the 1483// duplicate cookie (both from the in-memory cache, and from the backing store). 1484// 1485// This is a regression test for: http://crbug.com/17855. 1486TEST(CookieMonsterTest, DontImportDuplicateCookies) { 1487 GURL url_google("http://www.google.com/"); 1488 1489 scoped_refptr<MockPersistentCookieStore> store( 1490 new MockPersistentCookieStore); 1491 1492 // We will fill some initial cookies into the PersistentCookieStore, 1493 // to simulate a database with 4 duplicates. 1494 std::vector<net::CookieMonster::KeyedCanonicalCookie> initial_cookies; 1495 1496 // Insert 4 cookies with name "X" on path "/", with varying creation 1497 // dates. We expect only the most recent one to be preserved following 1498 // the import. 1499 1500 AddKeyedCookieToList("www.google.com", 1501 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", 1502 Time::Now() + TimeDelta::FromDays(3), 1503 &initial_cookies); 1504 1505 AddKeyedCookieToList("www.google.com", 1506 "X=2; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", 1507 Time::Now() + TimeDelta::FromDays(1), 1508 &initial_cookies); 1509 1510 // ===> This one is the WINNER (biggest creation time). <==== 1511 AddKeyedCookieToList("www.google.com", 1512 "X=3; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", 1513 Time::Now() + TimeDelta::FromDays(4), 1514 &initial_cookies); 1515 1516 AddKeyedCookieToList("www.google.com", 1517 "X=4; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", 1518 Time::Now(), 1519 &initial_cookies); 1520 1521 // Insert 2 cookies with name "X" on path "/2", with varying creation 1522 // dates. We expect only the most recent one to be preserved the import. 1523 1524 // ===> This one is the WINNER (biggest creation time). <==== 1525 AddKeyedCookieToList("www.google.com", 1526 "X=a1; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT", 1527 Time::Now() + TimeDelta::FromDays(9), 1528 &initial_cookies); 1529 1530 AddKeyedCookieToList("www.google.com", 1531 "X=a2; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT", 1532 Time::Now() + TimeDelta::FromDays(1), 1533 &initial_cookies); 1534 1535 // Insert 1 cookie with name "Y" on path "/". 1536 AddKeyedCookieToList("www.google.com", 1537 "Y=a; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", 1538 Time::Now() + TimeDelta::FromDays(9), 1539 &initial_cookies); 1540 1541 // Inject our initial cookies into the mock PersistentCookieStore. 1542 store->SetLoadExpectation(true, initial_cookies); 1543 1544 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, NULL)); 1545 1546 // Verify that duplicates were not imported for path "/". 1547 // (If this had failed, GetCookies() would have also returned X=1, X=2, X=4). 1548 EXPECT_EQ("X=3; Y=a", cm->GetCookies(GURL("http://www.google.com/"))); 1549 1550 // Verify that same-named cookie on a different path ("/x2") didn't get 1551 // messed up. 1552 EXPECT_EQ("X=a1; X=3; Y=a", 1553 cm->GetCookies(GURL("http://www.google.com/2/x"))); 1554 1555 // Verify that the PersistentCookieStore was told to kill its 4 duplicates. 1556 ASSERT_EQ(4u, store->commands().size()); 1557 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[0].type); 1558 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type); 1559 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[2].type); 1560 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type); 1561} 1562 1563TEST(CookieMonsterTest, Delegate) { 1564 GURL url_google(kUrlGoogle); 1565 1566 scoped_refptr<MockPersistentCookieStore> store( 1567 new MockPersistentCookieStore); 1568 scoped_refptr<MockCookieMonsterDelegate> delegate( 1569 new MockCookieMonsterDelegate); 1570 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, delegate)); 1571 1572 EXPECT_TRUE(cm->SetCookie(url_google, "A=B")); 1573 EXPECT_TRUE(cm->SetCookie(url_google, "C=D")); 1574 EXPECT_TRUE(cm->SetCookie(url_google, "E=F")); 1575 EXPECT_EQ("A=B; C=D; E=F", cm->GetCookies(url_google)); 1576 ASSERT_EQ(3u, delegate->changes().size()); 1577 EXPECT_EQ(false, delegate->changes()[0].second); 1578 EXPECT_EQ(url_google.host(), delegate->changes()[0].first.Domain()); 1579 EXPECT_EQ("A", delegate->changes()[0].first.Name()); 1580 EXPECT_EQ("B", delegate->changes()[0].first.Value()); 1581 EXPECT_EQ(url_google.host(), delegate->changes()[1].first.Domain()); 1582 EXPECT_EQ(false, delegate->changes()[1].second); 1583 EXPECT_EQ("C", delegate->changes()[1].first.Name()); 1584 EXPECT_EQ("D", delegate->changes()[1].first.Value()); 1585 EXPECT_EQ(url_google.host(), delegate->changes()[2].first.Domain()); 1586 EXPECT_EQ(false, delegate->changes()[2].second); 1587 EXPECT_EQ("E", delegate->changes()[2].first.Name()); 1588 EXPECT_EQ("F", delegate->changes()[2].first.Value()); 1589 delegate->reset(); 1590 1591 EXPECT_TRUE(FindAndDeleteCookie(cm, url_google.host(), "C")); 1592 EXPECT_EQ("A=B; E=F", cm->GetCookies(url_google)); 1593 ASSERT_EQ(1u, delegate->changes().size()); 1594 EXPECT_EQ(url_google.host(), delegate->changes()[0].first.Domain()); 1595 EXPECT_EQ(true, delegate->changes()[0].second); 1596 EXPECT_EQ("C", delegate->changes()[0].first.Name()); 1597 EXPECT_EQ("D", delegate->changes()[0].first.Value()); 1598 delegate->reset(); 1599 1600 EXPECT_FALSE(FindAndDeleteCookie(cm, "random.host", "E")); 1601 EXPECT_EQ("A=B; E=F", cm->GetCookies(url_google)); 1602 EXPECT_EQ(0u, delegate->changes().size()); 1603 1604 // Insert a cookie "a" for path "/path1" 1605 EXPECT_TRUE( 1606 cm->SetCookie(url_google, "a=val1; path=/path1; " 1607 "expires=Mon, 18-Apr-22 22:50:13 GMT")); 1608 ASSERT_EQ(1u, store->commands().size()); 1609 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type); 1610 ASSERT_EQ(1u, delegate->changes().size()); 1611 EXPECT_EQ(false, delegate->changes()[0].second); 1612 EXPECT_EQ(url_google.host(), delegate->changes()[0].first.Domain()); 1613 EXPECT_EQ("a", delegate->changes()[0].first.Name()); 1614 EXPECT_EQ("val1", delegate->changes()[0].first.Value()); 1615 delegate->reset(); 1616 1617 // Insert a cookie "a" for path "/path1", that is httponly. This should 1618 // overwrite the non-http-only version. 1619 net::CookieOptions allow_httponly; 1620 allow_httponly.set_include_httponly(); 1621 EXPECT_TRUE( 1622 cm->SetCookieWithOptions(url_google, 1623 "a=val2; path=/path1; httponly; " 1624 "expires=Mon, 18-Apr-22 22:50:14 GMT", 1625 allow_httponly)); 1626 ASSERT_EQ(3u, store->commands().size()); 1627 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type); 1628 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type); 1629 ASSERT_EQ(2u, delegate->changes().size()); 1630 EXPECT_EQ(url_google.host(), delegate->changes()[0].first.Domain()); 1631 EXPECT_EQ(true, delegate->changes()[0].second); 1632 EXPECT_EQ("a", delegate->changes()[0].first.Name()); 1633 EXPECT_EQ("val1", delegate->changes()[0].first.Value()); 1634 EXPECT_EQ(url_google.host(), delegate->changes()[1].first.Domain()); 1635 EXPECT_EQ(false, delegate->changes()[1].second); 1636 EXPECT_EQ("a", delegate->changes()[1].first.Name()); 1637 EXPECT_EQ("val2", delegate->changes()[1].first.Value()); 1638 delegate->reset(); 1639} 1640 1641TEST(CookieMonsterTest, SetCookieWithDetails) { 1642 GURL url_google(kUrlGoogle); 1643 GURL url_google_foo("http://www.google.izzle/foo"); 1644 GURL url_google_bar("http://www.google.izzle/bar"); 1645 GURL url_google_secure(kUrlGoogleSecure); 1646 1647 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 1648 1649 EXPECT_TRUE(cm->SetCookieWithDetails( 1650 url_google_foo, "A", "B", std::string(), "/foo", base::Time(), 1651 false, false)); 1652 EXPECT_TRUE(cm->SetCookieWithDetails( 1653 url_google_bar, "C", "D", "google.izzle", "/bar", base::Time(), 1654 false, true)); 1655 EXPECT_TRUE(cm->SetCookieWithDetails( 1656 url_google, "E", "F", std::string(), std::string(), base::Time(), 1657 true, false)); 1658 1659 // Test that malformed attributes fail to set the cookie. 1660 EXPECT_FALSE(cm->SetCookieWithDetails( 1661 url_google_foo, " A", "B", std::string(), "/foo", base::Time(), 1662 false, false)); 1663 EXPECT_FALSE(cm->SetCookieWithDetails( 1664 url_google_foo, "A;", "B", std::string(), "/foo", base::Time(), 1665 false, false)); 1666 EXPECT_FALSE(cm->SetCookieWithDetails( 1667 url_google_foo, "A=", "B", std::string(), "/foo", base::Time(), 1668 false, false)); 1669 EXPECT_FALSE(cm->SetCookieWithDetails( 1670 url_google_foo, "A", "B", "google.ozzzzzzle", "foo", base::Time(), 1671 false, false)); 1672 EXPECT_FALSE(cm->SetCookieWithDetails( 1673 url_google_foo, "A=", "B", std::string(), "foo", base::Time(), 1674 false, false)); 1675 1676 net::CookieMonster::CookieList cookies = 1677 cm->GetAllCookiesForURL(url_google_foo); 1678 net::CookieMonster::CookieList::iterator it = cookies.begin(); 1679 1680 ASSERT_TRUE(it != cookies.end()); 1681 EXPECT_EQ("A", it->Name()); 1682 EXPECT_EQ("B", it->Value()); 1683 EXPECT_EQ("www.google.izzle", it->Domain()); 1684 EXPECT_EQ("/foo", it->Path()); 1685 EXPECT_FALSE(it->DoesExpire()); 1686 EXPECT_FALSE(it->IsSecure()); 1687 EXPECT_FALSE(it->IsHttpOnly()); 1688 1689 ASSERT_TRUE(++it == cookies.end()); 1690 1691 cookies = cm->GetAllCookiesForURL(url_google_bar); 1692 it = cookies.begin(); 1693 1694 ASSERT_TRUE(it != cookies.end()); 1695 EXPECT_EQ("C", it->Name()); 1696 EXPECT_EQ("D", it->Value()); 1697 EXPECT_EQ(".google.izzle", it->Domain()); 1698 EXPECT_EQ("/bar", it->Path()); 1699 EXPECT_FALSE(it->IsSecure()); 1700 EXPECT_TRUE(it->IsHttpOnly()); 1701 1702 ASSERT_TRUE(++it == cookies.end()); 1703 1704 cookies = cm->GetAllCookiesForURL(url_google_secure); 1705 it = cookies.begin(); 1706 1707 ASSERT_TRUE(it != cookies.end()); 1708 EXPECT_EQ("E", it->Name()); 1709 EXPECT_EQ("F", it->Value()); 1710 EXPECT_EQ("/", it->Path()); 1711 EXPECT_EQ("www.google.izzle", it->Domain()); 1712 EXPECT_TRUE(it->IsSecure()); 1713 EXPECT_FALSE(it->IsHttpOnly()); 1714 1715 ASSERT_TRUE(++it == cookies.end()); 1716} 1717 1718 1719 1720TEST(CookieMonsterTest, DeleteAllForHost) { 1721 scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL)); 1722 1723 // Test probes: 1724 // * Non-secure URL, mid-level (http://w.c.b.a) 1725 // * Secure URL, mid-level (https://w.c.b.a) 1726 // * URL with path, mid-level (https:/w.c.b.a/dir1/xx) 1727 // All three tests should nuke only the midlevel host cookie, 1728 // the http_only cookie, the host secure cookie, and the two host 1729 // path cookies. http_only, secure, and paths are ignored by 1730 // this call, and domain cookies arent touched. 1731 PopulateCmForDeleteAllForHost(cm); 1732 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X", 1733 cm->GetCookies(GURL(kTopLevelDomainPlus3))); 1734 EXPECT_EQ("dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X", 1735 cm->GetCookies(GURL(kTopLevelDomainPlus2Secure))); 1736 EXPECT_EQ("dom_1=X; host_1=X", cm->GetCookies(GURL(kTopLevelDomainPlus1))); 1737 EXPECT_EQ("dom_path_2=X; host_path_2=X; dom_path_1=X; host_path_1=X; " 1738 "dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X", 1739 cm->GetCookies(GURL(kTopLevelDomainPlus2Secure + 1740 std::string("/dir1/dir2/xxx")))); 1741 1742 EXPECT_EQ(5, cm->DeleteAllForHost(GURL(kTopLevelDomainPlus2))); 1743 EXPECT_EQ(8U, cm->GetAllCookies().size()); 1744 1745 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X", 1746 cm->GetCookies(GURL(kTopLevelDomainPlus3))); 1747 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X", 1748 cm->GetCookies(GURL(kTopLevelDomainPlus2Secure))); 1749 EXPECT_EQ("dom_1=X; host_1=X", cm->GetCookies(GURL(kTopLevelDomainPlus1))); 1750 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X", 1751 cm->GetCookies(GURL(kTopLevelDomainPlus2Secure + 1752 std::string("/dir1/dir2/xxx")))); 1753 1754 PopulateCmForDeleteAllForHost(cm); 1755 EXPECT_EQ(5, cm->DeleteAllForHost(GURL(kTopLevelDomainPlus2Secure))); 1756 EXPECT_EQ(8U, cm->GetAllCookies().size()); 1757 1758 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X", 1759 cm->GetCookies(GURL(kTopLevelDomainPlus3))); 1760 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X", 1761 cm->GetCookies(GURL(kTopLevelDomainPlus2Secure))); 1762 EXPECT_EQ("dom_1=X; host_1=X", cm->GetCookies(GURL(kTopLevelDomainPlus1))); 1763 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X", 1764 cm->GetCookies(GURL(kTopLevelDomainPlus2Secure + 1765 std::string("/dir1/dir2/xxx")))); 1766 1767 PopulateCmForDeleteAllForHost(cm); 1768 EXPECT_EQ(5, cm->DeleteAllForHost(GURL(kTopLevelDomainPlus2Secure + 1769 std::string("/dir1/xxx")))); 1770 EXPECT_EQ(8U, cm->GetAllCookies().size()); 1771 1772 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X", 1773 cm->GetCookies(GURL(kTopLevelDomainPlus3))); 1774 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X", 1775 cm->GetCookies(GURL(kTopLevelDomainPlus2Secure))); 1776 EXPECT_EQ("dom_1=X; host_1=X", cm->GetCookies(GURL(kTopLevelDomainPlus1))); 1777 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X", 1778 cm->GetCookies(GURL(kTopLevelDomainPlus2Secure + 1779 std::string("/dir1/dir2/xxx")))); 1780 1781} 1782