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 #ifndef NET_COOKIES_COOKIE_STORE_UNITTEST_H_ 6 #define NET_COOKIES_COOKIE_STORE_UNITTEST_H_ 7 8 #include "base/bind.h" 9 #include "base/message_loop/message_loop.h" 10 #include "base/strings/string_tokenizer.h" 11 #include "base/threading/thread.h" 12 #include "net/cookies/cookie_monster.h" 13 #include "net/cookies/cookie_store.h" 14 #include "net/cookies/cookie_store_test_callbacks.h" 15 #include "testing/gtest/include/gtest/gtest.h" 16 #include "url/gurl.h" 17 18 // This file declares unittest templates that can be used to test common 19 // behavior of any CookieStore implementation. 20 // See cookie_monster_unittest.cc for an example of an implementation. 21 22 namespace net { 23 24 using base::Thread; 25 26 const int kTimeout = 1000; 27 28 const char kUrlFtp[] = "ftp://ftp.google.izzle/"; 29 const char kUrlGoogle[] = "http://www.google.izzle"; 30 const char kUrlGoogleFoo[] = "http://www.google.izzle/foo"; 31 const char kUrlGoogleBar[] = "http://www.google.izzle/bar"; 32 const char kUrlGoogleSecure[] = "https://www.google.izzle"; 33 const char kValidCookieLine[] = "A=B; path=/"; 34 const char kValidDomainCookieLine[] = "A=B; path=/; domain=google.izzle"; 35 36 // The CookieStoreTestTraits must have the following members: 37 // struct CookieStoreTestTraits { 38 // // Factory function. 39 // static scoped_refptr<CookieStore> Create(); 40 // 41 // // The cookie store is a CookieMonster. Only used to test 42 // // GetCookieMonster(). 43 // static const bool is_cookie_monster; 44 // 45 // // The cookie store supports cookies with the exclude_httponly() option. 46 // static const bool supports_http_only; 47 // 48 // // The cookie store is able to make the difference between the ".com" 49 // // and the "com" domains. 50 // static const bool supports_non_dotted_domains; 51 // 52 // // The cookie store handles the domains with trailing dots (such as "com.") 53 // // correctly. 54 // static const bool supports_trailing_dots; 55 // 56 // // The cookie store rejects cookies for invalid schemes such as ftp. 57 // static const bool filters_schemes; 58 // 59 // // The cookie store has a bug happening when a path is a substring of 60 // // another. 61 // static const bool has_path_prefix_bug; 62 // 63 // // Time to wait between two cookie insertions to ensure that cookies have 64 // // different creation times. 65 // static const int creation_time_granularity_in_ms; 66 // }; 67 68 template <class CookieStoreTestTraits> 69 class CookieStoreTest : public testing::Test { 70 protected: 71 CookieStoreTest() 72 : url_google_(kUrlGoogle), 73 url_google_secure_(kUrlGoogleSecure), 74 url_google_foo_(kUrlGoogleFoo), 75 url_google_bar_(kUrlGoogleBar) { 76 // This test may be used outside of the net test suite, and thus may not 77 // have a message loop. 78 if (!base::MessageLoop::current()) 79 message_loop_.reset(new base::MessageLoop); 80 weak_factory_.reset(new base::WeakPtrFactory<base::MessageLoop>( 81 base::MessageLoop::current())); 82 } 83 84 // Helper methods for the asynchronous Cookie Store API that call the 85 // asynchronous method and then pump the loop until the callback is invoked, 86 // finally returning the value. 87 88 std::string GetCookies(CookieStore* cs, const GURL& url) { 89 DCHECK(cs); 90 CookieOptions options; 91 if (!CookieStoreTestTraits::supports_http_only) 92 options.set_include_httponly(); 93 StringResultCookieCallback callback; 94 cs->GetCookiesWithOptionsAsync( 95 url, options, 96 base::Bind(&StringResultCookieCallback::Run, 97 base::Unretained(&callback))); 98 RunFor(kTimeout); 99 EXPECT_TRUE(callback.did_run()); 100 return callback.result(); 101 } 102 103 std::string GetCookiesWithOptions(CookieStore* cs, 104 const GURL& url, 105 const CookieOptions& options) { 106 DCHECK(cs); 107 StringResultCookieCallback callback; 108 cs->GetCookiesWithOptionsAsync( 109 url, options, base::Bind(&StringResultCookieCallback::Run, 110 base::Unretained(&callback))); 111 RunFor(kTimeout); 112 EXPECT_TRUE(callback.did_run()); 113 return callback.result(); 114 } 115 116 bool SetCookieWithOptions(CookieStore* cs, 117 const GURL& url, 118 const std::string& cookie_line, 119 const CookieOptions& options) { 120 DCHECK(cs); 121 ResultSavingCookieCallback<bool> callback; 122 cs->SetCookieWithOptionsAsync( 123 url, cookie_line, options, 124 base::Bind( 125 &ResultSavingCookieCallback<bool>::Run, 126 base::Unretained(&callback))); 127 RunFor(kTimeout); 128 EXPECT_TRUE(callback.did_run()); 129 return callback.result(); 130 } 131 132 bool SetCookieWithServerTime(CookieStore* cs, 133 const GURL& url, 134 const std::string& cookie_line, 135 const base::Time& server_time) { 136 CookieOptions options; 137 if (!CookieStoreTestTraits::supports_http_only) 138 options.set_include_httponly(); 139 options.set_server_time(server_time); 140 return SetCookieWithOptions(cs, url, cookie_line, options); 141 } 142 143 bool SetCookie(CookieStore* cs, 144 const GURL& url, 145 const std::string& cookie_line) { 146 CookieOptions options; 147 if (!CookieStoreTestTraits::supports_http_only) 148 options.set_include_httponly(); 149 return SetCookieWithOptions(cs, url, cookie_line, options); 150 } 151 152 void DeleteCookie(CookieStore* cs, 153 const GURL& url, 154 const std::string& cookie_name) { 155 DCHECK(cs); 156 NoResultCookieCallback callback; 157 cs->DeleteCookieAsync( 158 url, cookie_name, 159 base::Bind(&NoResultCookieCallback::Run, base::Unretained(&callback))); 160 RunFor(kTimeout); 161 EXPECT_TRUE(callback.did_run()); 162 } 163 164 int DeleteCreatedBetween(CookieStore* cs, 165 const base::Time& delete_begin, 166 const base::Time& delete_end) { 167 DCHECK(cs); 168 ResultSavingCookieCallback<int> callback; 169 cs->DeleteAllCreatedBetweenAsync( 170 delete_begin, delete_end, 171 base::Bind( 172 &ResultSavingCookieCallback<int>::Run, 173 base::Unretained(&callback))); 174 RunFor(kTimeout); 175 EXPECT_TRUE(callback.did_run()); 176 return callback.result(); 177 } 178 179 int DeleteAllCreatedBetweenForHost(CookieStore* cs, 180 const base::Time delete_begin, 181 const base::Time delete_end, 182 const GURL& url) { 183 DCHECK(cs); 184 ResultSavingCookieCallback<int> callback; 185 cs->DeleteAllCreatedBetweenForHostAsync( 186 delete_begin, delete_end, url, 187 base::Bind( 188 &ResultSavingCookieCallback<int>::Run, 189 base::Unretained(&callback))); 190 RunFor(kTimeout); 191 EXPECT_TRUE(callback.did_run()); 192 return callback.result(); 193 } 194 195 int DeleteSessionCookies(CookieStore* cs) { 196 DCHECK(cs); 197 ResultSavingCookieCallback<int> callback; 198 cs->DeleteSessionCookiesAsync( 199 base::Bind( 200 &ResultSavingCookieCallback<int>::Run, 201 base::Unretained(&callback))); 202 RunFor(kTimeout); 203 EXPECT_TRUE(callback.did_run()); 204 return callback.result(); 205 } 206 207 void RunFor(int ms) { 208 // Runs the test thread message loop for up to |ms| milliseconds. 209 base::MessageLoop::current()->PostDelayedTask( 210 FROM_HERE, 211 base::Bind(&base::MessageLoop::Quit, weak_factory_->GetWeakPtr()), 212 base::TimeDelta::FromMilliseconds(ms)); 213 base::MessageLoop::current()->Run(); 214 weak_factory_->InvalidateWeakPtrs(); 215 } 216 217 scoped_refptr<CookieStore> GetCookieStore() { 218 return CookieStoreTestTraits::Create(); 219 } 220 221 // Compares two cookie lines. 222 void MatchCookieLines(const std::string& line1, const std::string& line2) { 223 EXPECT_EQ(TokenizeCookieLine(line1), TokenizeCookieLine(line2)); 224 } 225 226 // Check the cookie line by polling until equality or a timeout is reached. 227 void MatchCookieLineWithTimeout(CookieStore* cs, 228 const GURL& url, 229 const std::string& line) { 230 std::string cookies = GetCookies(cs, url); 231 bool matched = (TokenizeCookieLine(line) == TokenizeCookieLine(cookies)); 232 base::Time polling_end_date = base::Time::Now() + 233 base::TimeDelta::FromMilliseconds( 234 CookieStoreTestTraits::creation_time_granularity_in_ms); 235 236 while (!matched && base::Time::Now() <= polling_end_date) { 237 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10)); 238 cookies = GetCookies(cs, url); 239 matched = (TokenizeCookieLine(line) == TokenizeCookieLine(cookies)); 240 } 241 242 EXPECT_TRUE(matched) << "\"" << cookies 243 << "\" does not match \"" << line << "\""; 244 } 245 246 GURL url_google_; 247 GURL url_google_secure_; 248 GURL url_google_foo_; 249 GURL url_google_bar_; 250 251 scoped_ptr<base::WeakPtrFactory<base::MessageLoop> > weak_factory_; 252 scoped_ptr<base::MessageLoop> message_loop_; 253 254 private: 255 // Returns a set of strings of type "name=value". Fails in case of duplicate. 256 std::set<std::string> TokenizeCookieLine(const std::string& line) { 257 std::set<std::string> tokens; 258 base::StringTokenizer tokenizer(line, " ;"); 259 while (tokenizer.GetNext()) 260 EXPECT_TRUE(tokens.insert(tokenizer.token()).second); 261 return tokens; 262 } 263 }; 264 265 TYPED_TEST_CASE_P(CookieStoreTest); 266 267 TYPED_TEST_P(CookieStoreTest, TypeTest) { 268 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 269 EXPECT_EQ(cs->GetCookieMonster(), 270 (TypeParam::is_cookie_monster) ? 271 static_cast<CookieMonster*>(cs.get()) : NULL); 272 } 273 274 TYPED_TEST_P(CookieStoreTest, DomainTest) { 275 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 276 EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, "A=B")); 277 this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_)); 278 EXPECT_TRUE(this->SetCookie( 279 cs.get(), this->url_google_, "C=D; domain=.google.izzle")); 280 this->MatchCookieLines("A=B; C=D", 281 this->GetCookies(cs.get(), this->url_google_)); 282 283 // Verify that A=B was set as a host cookie rather than a domain 284 // cookie -- should not be accessible from a sub sub-domain. 285 this->MatchCookieLines( 286 "C=D", this->GetCookies(cs.get(), GURL("http://foo.www.google.izzle"))); 287 288 // Test and make sure we find domain cookies on the same domain. 289 EXPECT_TRUE(this->SetCookie( 290 cs.get(), this->url_google_, "E=F; domain=.www.google.izzle")); 291 this->MatchCookieLines("A=B; C=D; E=F", 292 this->GetCookies(cs.get(), this->url_google_)); 293 294 // Test setting a domain= that doesn't start w/ a dot, should 295 // treat it as a domain cookie, as if there was a pre-pended dot. 296 EXPECT_TRUE(this->SetCookie( 297 cs.get(), this->url_google_, "G=H; domain=www.google.izzle")); 298 this->MatchCookieLines("A=B; C=D; E=F; G=H", 299 this->GetCookies(cs.get(), this->url_google_)); 300 301 // Test domain enforcement, should fail on a sub-domain or something too deep. 302 EXPECT_FALSE( 303 this->SetCookie(cs.get(), this->url_google_, "I=J; domain=.izzle")); 304 this->MatchCookieLines(std::string(), 305 this->GetCookies(cs.get(), GURL("http://a.izzle"))); 306 EXPECT_FALSE(this->SetCookie( 307 cs.get(), this->url_google_, "K=L; domain=.bla.www.google.izzle")); 308 this->MatchCookieLines( 309 "C=D; E=F; G=H", 310 this->GetCookies(cs.get(), GURL("http://bla.www.google.izzle"))); 311 this->MatchCookieLines("A=B; C=D; E=F; G=H", 312 this->GetCookies(cs.get(), this->url_google_)); 313 } 314 315 // FireFox recognizes domains containing trailing periods as valid. 316 // IE and Safari do not. Assert the expected policy here. 317 TYPED_TEST_P(CookieStoreTest, DomainWithTrailingDotTest) { 318 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 319 EXPECT_FALSE(this->SetCookie( 320 cs.get(), this->url_google_, "a=1; domain=.www.google.com.")); 321 EXPECT_FALSE(this->SetCookie( 322 cs.get(), this->url_google_, "b=2; domain=.www.google.com..")); 323 this->MatchCookieLines(std::string(), 324 this->GetCookies(cs.get(), this->url_google_)); 325 } 326 327 // Test that cookies can bet set on higher level domains. 328 // http://b/issue?id=896491 329 TYPED_TEST_P(CookieStoreTest, ValidSubdomainTest) { 330 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 331 GURL url_abcd("http://a.b.c.d.com"); 332 GURL url_bcd("http://b.c.d.com"); 333 GURL url_cd("http://c.d.com"); 334 GURL url_d("http://d.com"); 335 336 EXPECT_TRUE(this->SetCookie(cs.get(), url_abcd, "a=1; domain=.a.b.c.d.com")); 337 EXPECT_TRUE(this->SetCookie(cs.get(), url_abcd, "b=2; domain=.b.c.d.com")); 338 EXPECT_TRUE(this->SetCookie(cs.get(), url_abcd, "c=3; domain=.c.d.com")); 339 EXPECT_TRUE(this->SetCookie(cs.get(), url_abcd, "d=4; domain=.d.com")); 340 341 this->MatchCookieLines("a=1; b=2; c=3; d=4", 342 this->GetCookies(cs.get(), url_abcd)); 343 this->MatchCookieLines("b=2; c=3; d=4", this->GetCookies(cs.get(), url_bcd)); 344 this->MatchCookieLines("c=3; d=4", this->GetCookies(cs.get(), url_cd)); 345 this->MatchCookieLines("d=4", this->GetCookies(cs.get(), url_d)); 346 347 // Check that the same cookie can exist on different sub-domains. 348 EXPECT_TRUE(this->SetCookie(cs.get(), url_bcd, "X=bcd; domain=.b.c.d.com")); 349 EXPECT_TRUE(this->SetCookie(cs.get(), url_bcd, "X=cd; domain=.c.d.com")); 350 this->MatchCookieLines("b=2; c=3; d=4; X=bcd; X=cd", 351 this->GetCookies(cs.get(), url_bcd)); 352 this->MatchCookieLines("c=3; d=4; X=cd", this->GetCookies(cs.get(), url_cd)); 353 } 354 355 // Test that setting a cookie which specifies an invalid domain has 356 // no side-effect. An invalid domain in this context is one which does 357 // not match the originating domain. 358 // http://b/issue?id=896472 359 TYPED_TEST_P(CookieStoreTest, InvalidDomainTest) { 360 { 361 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 362 GURL url_foobar("http://foo.bar.com"); 363 364 // More specific sub-domain than allowed. 365 EXPECT_FALSE( 366 this->SetCookie(cs.get(), url_foobar, "a=1; domain=.yo.foo.bar.com")); 367 368 EXPECT_FALSE(this->SetCookie(cs.get(), url_foobar, "b=2; domain=.foo.com")); 369 EXPECT_FALSE( 370 this->SetCookie(cs.get(), url_foobar, "c=3; domain=.bar.foo.com")); 371 372 // Different TLD, but the rest is a substring. 373 EXPECT_FALSE( 374 this->SetCookie(cs.get(), url_foobar, "d=4; domain=.foo.bar.com.net")); 375 376 // A substring that isn't really a parent domain. 377 EXPECT_FALSE(this->SetCookie(cs.get(), url_foobar, "e=5; domain=ar.com")); 378 379 // Completely invalid domains: 380 EXPECT_FALSE(this->SetCookie(cs.get(), url_foobar, "f=6; domain=.")); 381 EXPECT_FALSE(this->SetCookie(cs.get(), url_foobar, "g=7; domain=/")); 382 EXPECT_FALSE(this->SetCookie( 383 cs.get(), url_foobar, "h=8; domain=http://foo.bar.com")); 384 EXPECT_FALSE( 385 this->SetCookie(cs.get(), url_foobar, "i=9; domain=..foo.bar.com")); 386 EXPECT_FALSE( 387 this->SetCookie(cs.get(), url_foobar, "j=10; domain=..bar.com")); 388 389 // Make sure there isn't something quirky in the domain canonicalization 390 // that supports full URL semantics. 391 EXPECT_FALSE(this->SetCookie( 392 cs.get(), url_foobar, "k=11; domain=.foo.bar.com?blah")); 393 EXPECT_FALSE(this->SetCookie( 394 cs.get(), url_foobar, "l=12; domain=.foo.bar.com/blah")); 395 EXPECT_FALSE( 396 this->SetCookie(cs.get(), url_foobar, "m=13; domain=.foo.bar.com:80")); 397 EXPECT_FALSE( 398 this->SetCookie(cs.get(), url_foobar, "n=14; domain=.foo.bar.com:")); 399 EXPECT_FALSE( 400 this->SetCookie(cs.get(), url_foobar, "o=15; domain=.foo.bar.com#sup")); 401 402 this->MatchCookieLines(std::string(), 403 this->GetCookies(cs.get(), url_foobar)); 404 } 405 406 { 407 // Make sure the cookie code hasn't gotten its subdomain string handling 408 // reversed, missed a suffix check, etc. It's important here that the two 409 // hosts below have the same domain + registry. 410 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 411 GURL url_foocom("http://foo.com.com"); 412 EXPECT_FALSE( 413 this->SetCookie(cs.get(), url_foocom, "a=1; domain=.foo.com.com.com")); 414 this->MatchCookieLines(std::string(), 415 this->GetCookies(cs.get(), url_foocom)); 416 } 417 } 418 419 // Test the behavior of omitting dot prefix from domain, should 420 // function the same as FireFox. 421 // http://b/issue?id=889898 422 TYPED_TEST_P(CookieStoreTest, DomainWithoutLeadingDotTest) { 423 { // The omission of dot results in setting a domain cookie. 424 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 425 GURL url_hosted("http://manage.hosted.filefront.com"); 426 GURL url_filefront("http://www.filefront.com"); 427 EXPECT_TRUE( 428 this->SetCookie(cs.get(), url_hosted, "sawAd=1; domain=filefront.com")); 429 this->MatchCookieLines("sawAd=1", this->GetCookies(cs.get(), url_hosted)); 430 this->MatchCookieLines("sawAd=1", 431 this->GetCookies(cs.get(), url_filefront)); 432 } 433 434 { // Even when the domains match exactly, don't consider it host cookie. 435 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 436 GURL url("http://www.google.com"); 437 EXPECT_TRUE(this->SetCookie(cs.get(), url, "a=1; domain=www.google.com")); 438 this->MatchCookieLines("a=1", this->GetCookies(cs.get(), url)); 439 this->MatchCookieLines( 440 "a=1", this->GetCookies(cs.get(), GURL("http://sub.www.google.com"))); 441 this->MatchCookieLines( 442 std::string(), 443 this->GetCookies(cs.get(), GURL("http://something-else.com"))); 444 } 445 } 446 447 // Test that the domain specified in cookie string is treated case-insensitive 448 // http://b/issue?id=896475. 449 TYPED_TEST_P(CookieStoreTest, CaseInsensitiveDomainTest) { 450 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 451 GURL url("http://www.google.com"); 452 EXPECT_TRUE(this->SetCookie(cs.get(), url, "a=1; domain=.GOOGLE.COM")); 453 EXPECT_TRUE(this->SetCookie(cs.get(), url, "b=2; domain=.wWw.gOOgLE.coM")); 454 this->MatchCookieLines("a=1; b=2", this->GetCookies(cs.get(), url)); 455 } 456 457 TYPED_TEST_P(CookieStoreTest, TestIpAddress) { 458 GURL url_ip("http://1.2.3.4/weee"); 459 { 460 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 461 EXPECT_TRUE(this->SetCookie(cs.get(), url_ip, kValidCookieLine)); 462 this->MatchCookieLines("A=B", this->GetCookies(cs.get(), url_ip)); 463 } 464 465 { // IP addresses should not be able to set domain cookies. 466 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 467 EXPECT_FALSE(this->SetCookie(cs.get(), url_ip, "b=2; domain=.1.2.3.4")); 468 EXPECT_FALSE(this->SetCookie(cs.get(), url_ip, "c=3; domain=.3.4")); 469 this->MatchCookieLines(std::string(), this->GetCookies(cs.get(), url_ip)); 470 // It should be allowed to set a cookie if domain= matches the IP address 471 // exactly. This matches IE/Firefox, even though it seems a bit wrong. 472 EXPECT_FALSE(this->SetCookie(cs.get(), url_ip, "b=2; domain=1.2.3.3")); 473 this->MatchCookieLines(std::string(), this->GetCookies(cs.get(), url_ip)); 474 EXPECT_TRUE(this->SetCookie(cs.get(), url_ip, "b=2; domain=1.2.3.4")); 475 this->MatchCookieLines("b=2", this->GetCookies(cs.get(), url_ip)); 476 } 477 } 478 479 // Test host cookies, and setting of cookies on TLD. 480 TYPED_TEST_P(CookieStoreTest, TestNonDottedAndTLD) { 481 { 482 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 483 GURL url("http://com/"); 484 // Allow setting on "com", (but only as a host cookie). 485 EXPECT_TRUE(this->SetCookie(cs.get(), url, "a=1")); 486 EXPECT_FALSE(this->SetCookie(cs.get(), url, "b=2; domain=.com")); 487 EXPECT_FALSE(this->SetCookie(cs.get(), url, "c=3; domain=com")); 488 this->MatchCookieLines("a=1", this->GetCookies(cs.get(), url)); 489 // Make sure it doesn't show up for a normal .com, it should be a host 490 // not a domain cookie. 491 this->MatchCookieLines( 492 std::string(), 493 this->GetCookies(cs.get(), GURL("http://hopefully-no-cookies.com/"))); 494 if (TypeParam::supports_non_dotted_domains) { 495 this->MatchCookieLines(std::string(), 496 this->GetCookies(cs.get(), GURL("http://.com/"))); 497 } 498 } 499 500 { 501 // http://com. should be treated the same as http://com. 502 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 503 GURL url("http://com./index.html"); 504 if (TypeParam::supports_trailing_dots) { 505 EXPECT_TRUE(this->SetCookie(cs.get(), url, "a=1")); 506 this->MatchCookieLines("a=1", this->GetCookies(cs.get(), url)); 507 this->MatchCookieLines( 508 std::string(), 509 this->GetCookies(cs.get(), 510 GURL("http://hopefully-no-cookies.com./"))); 511 } else { 512 EXPECT_FALSE(this->SetCookie(cs.get(), url, "a=1")); 513 } 514 } 515 516 { // Should not be able to set host cookie from a subdomain. 517 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 518 GURL url("http://a.b"); 519 EXPECT_FALSE(this->SetCookie(cs.get(), url, "a=1; domain=.b")); 520 EXPECT_FALSE(this->SetCookie(cs.get(), url, "b=2; domain=b")); 521 this->MatchCookieLines(std::string(), this->GetCookies(cs.get(), url)); 522 } 523 524 { // Same test as above, but explicitly on a known TLD (com). 525 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 526 GURL url("http://google.com"); 527 EXPECT_FALSE(this->SetCookie(cs.get(), url, "a=1; domain=.com")); 528 EXPECT_FALSE(this->SetCookie(cs.get(), url, "b=2; domain=com")); 529 this->MatchCookieLines(std::string(), this->GetCookies(cs.get(), url)); 530 } 531 532 { // Make sure can't set cookie on TLD which is dotted. 533 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 534 GURL url("http://google.co.uk"); 535 EXPECT_FALSE(this->SetCookie(cs.get(), url, "a=1; domain=.co.uk")); 536 EXPECT_FALSE(this->SetCookie(cs.get(), url, "b=2; domain=.uk")); 537 this->MatchCookieLines(std::string(), this->GetCookies(cs.get(), url)); 538 this->MatchCookieLines( 539 std::string(), 540 this->GetCookies(cs.get(), GURL("http://something-else.co.uk"))); 541 this->MatchCookieLines( 542 std::string(), 543 this->GetCookies(cs.get(), GURL("http://something-else.uk"))); 544 } 545 546 { // Intranet URLs should only be able to set host cookies. 547 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 548 GURL url("http://b"); 549 EXPECT_TRUE(this->SetCookie(cs.get(), url, "a=1")); 550 EXPECT_FALSE(this->SetCookie(cs.get(), url, "b=2; domain=.b")); 551 EXPECT_FALSE(this->SetCookie(cs.get(), url, "c=3; domain=b")); 552 this->MatchCookieLines("a=1", this->GetCookies(cs.get(), url)); 553 } 554 } 555 556 // Test reading/writing cookies when the domain ends with a period, 557 // as in "www.google.com." 558 TYPED_TEST_P(CookieStoreTest, TestHostEndsWithDot) { 559 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 560 GURL url("http://www.google.com"); 561 GURL url_with_dot("http://www.google.com."); 562 EXPECT_TRUE(this->SetCookie(cs.get(), url, "a=1")); 563 this->MatchCookieLines("a=1", this->GetCookies(cs.get(), url)); 564 565 if (TypeParam::supports_trailing_dots) { 566 // Do not share cookie space with the dot version of domain. 567 // Note: this is not what FireFox does, but it _is_ what IE+Safari do. 568 EXPECT_FALSE( 569 this->SetCookie(cs.get(), url, "b=2; domain=.www.google.com.")); 570 this->MatchCookieLines("a=1", this->GetCookies(cs.get(), url)); 571 572 EXPECT_TRUE( 573 this->SetCookie(cs.get(), url_with_dot, "b=2; domain=.google.com.")); 574 this->MatchCookieLines("b=2", this->GetCookies(cs.get(), url_with_dot)); 575 } else { 576 EXPECT_TRUE(this->SetCookie(cs.get(), url, "b=2; domain=.www.google.com.")); 577 EXPECT_FALSE( 578 this->SetCookie(cs.get(), url_with_dot, "b=2; domain=.google.com.")); 579 } 580 581 // Make sure there weren't any side effects. 582 this->MatchCookieLines( 583 std::string(), 584 this->GetCookies(cs.get(), GURL("http://hopefully-no-cookies.com/"))); 585 this->MatchCookieLines(std::string(), 586 this->GetCookies(cs.get(), GURL("http://.com/"))); 587 } 588 589 TYPED_TEST_P(CookieStoreTest, InvalidScheme) { 590 if (!TypeParam::filters_schemes) 591 return; 592 593 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 594 EXPECT_FALSE(this->SetCookie(cs.get(), GURL(kUrlFtp), kValidCookieLine)); 595 } 596 597 TYPED_TEST_P(CookieStoreTest, InvalidScheme_Read) { 598 if (!TypeParam::filters_schemes) 599 return; 600 601 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 602 EXPECT_TRUE( 603 this->SetCookie(cs.get(), GURL(kUrlGoogle), kValidDomainCookieLine)); 604 this->MatchCookieLines(std::string(), 605 this->GetCookies(cs.get(), GURL(kUrlFtp))); 606 } 607 608 TYPED_TEST_P(CookieStoreTest, PathTest) { 609 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 610 std::string url("http://www.google.izzle"); 611 EXPECT_TRUE(this->SetCookie(cs.get(), GURL(url), "A=B; path=/wee")); 612 this->MatchCookieLines("A=B", this->GetCookies(cs.get(), GURL(url + "/wee"))); 613 this->MatchCookieLines("A=B", 614 this->GetCookies(cs.get(), GURL(url + "/wee/"))); 615 this->MatchCookieLines("A=B", 616 this->GetCookies(cs.get(), GURL(url + "/wee/war"))); 617 this->MatchCookieLines( 618 "A=B", this->GetCookies(cs.get(), GURL(url + "/wee/war/more/more"))); 619 if (!TypeParam::has_path_prefix_bug) 620 this->MatchCookieLines(std::string(), 621 this->GetCookies(cs.get(), GURL(url + "/weehee"))); 622 this->MatchCookieLines(std::string(), 623 this->GetCookies(cs.get(), GURL(url + "/"))); 624 625 // If we add a 0 length path, it should default to / 626 EXPECT_TRUE(this->SetCookie(cs.get(), GURL(url), "A=C; path=")); 627 this->MatchCookieLines("A=B; A=C", 628 this->GetCookies(cs.get(), GURL(url + "/wee"))); 629 this->MatchCookieLines("A=C", this->GetCookies(cs.get(), GURL(url + "/"))); 630 } 631 632 TYPED_TEST_P(CookieStoreTest, EmptyExpires) { 633 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 634 CookieOptions options; 635 if (!TypeParam::supports_http_only) 636 options.set_include_httponly(); 637 GURL url("http://www7.ipdl.inpit.go.jp/Tokujitu/tjkta.ipdl?N0000=108"); 638 std::string set_cookie_line = 639 "ACSTM=20130308043820420042; path=/; domain=ipdl.inpit.go.jp; Expires="; 640 std::string cookie_line = "ACSTM=20130308043820420042"; 641 642 this->SetCookieWithOptions(cs.get(), url, set_cookie_line, options); 643 this->MatchCookieLines(cookie_line, 644 this->GetCookiesWithOptions(cs.get(), url, options)); 645 646 options.set_server_time(base::Time::Now() - base::TimeDelta::FromHours(1)); 647 this->SetCookieWithOptions(cs.get(), url, set_cookie_line, options); 648 this->MatchCookieLines(cookie_line, 649 this->GetCookiesWithOptions(cs.get(), url, options)); 650 651 options.set_server_time(base::Time::Now() + base::TimeDelta::FromHours(1)); 652 this->SetCookieWithOptions(cs.get(), url, set_cookie_line, options); 653 this->MatchCookieLines(cookie_line, 654 this->GetCookiesWithOptions(cs.get(), url, options)); 655 } 656 657 TYPED_TEST_P(CookieStoreTest, HttpOnlyTest) { 658 if (!TypeParam::supports_http_only) 659 return; 660 661 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 662 CookieOptions options; 663 options.set_include_httponly(); 664 665 // Create a httponly cookie. 666 EXPECT_TRUE(this->SetCookieWithOptions( 667 cs.get(), this->url_google_, "A=B; httponly", options)); 668 669 // Check httponly read protection. 670 this->MatchCookieLines(std::string(), 671 this->GetCookies(cs.get(), this->url_google_)); 672 this->MatchCookieLines( 673 "A=B", this->GetCookiesWithOptions(cs.get(), this->url_google_, options)); 674 675 // Check httponly overwrite protection. 676 EXPECT_FALSE(this->SetCookie(cs.get(), this->url_google_, "A=C")); 677 this->MatchCookieLines(std::string(), 678 this->GetCookies(cs.get(), this->url_google_)); 679 this->MatchCookieLines( 680 "A=B", this->GetCookiesWithOptions(cs.get(), this->url_google_, options)); 681 EXPECT_TRUE( 682 this->SetCookieWithOptions(cs.get(), this->url_google_, "A=C", options)); 683 this->MatchCookieLines("A=C", this->GetCookies(cs.get(), this->url_google_)); 684 685 // Check httponly create protection. 686 EXPECT_FALSE(this->SetCookie(cs.get(), this->url_google_, "B=A; httponly")); 687 this->MatchCookieLines( 688 "A=C", this->GetCookiesWithOptions(cs.get(), this->url_google_, options)); 689 EXPECT_TRUE(this->SetCookieWithOptions( 690 cs.get(), this->url_google_, "B=A; httponly", options)); 691 this->MatchCookieLines( 692 "A=C; B=A", 693 this->GetCookiesWithOptions(cs.get(), this->url_google_, options)); 694 this->MatchCookieLines("A=C", this->GetCookies(cs.get(), this->url_google_)); 695 } 696 697 TYPED_TEST_P(CookieStoreTest, TestCookieDeletion) { 698 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 699 700 // Create a session cookie. 701 EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, kValidCookieLine)); 702 this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_)); 703 // Delete it via Max-Age. 704 EXPECT_TRUE(this->SetCookie(cs.get(), 705 this->url_google_, 706 std::string(kValidCookieLine) + "; max-age=0")); 707 this->MatchCookieLineWithTimeout(cs.get(), this->url_google_, std::string()); 708 709 // Create a session cookie. 710 EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, kValidCookieLine)); 711 this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_)); 712 // Delete it via Expires. 713 EXPECT_TRUE(this->SetCookie(cs.get(), 714 this->url_google_, 715 std::string(kValidCookieLine) + 716 "; expires=Mon, 18-Apr-1977 22:50:13 GMT")); 717 this->MatchCookieLines(std::string(), 718 this->GetCookies(cs.get(), this->url_google_)); 719 720 // Create a persistent cookie. 721 EXPECT_TRUE(this->SetCookie( 722 cs.get(), 723 this->url_google_, 724 std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT")); 725 726 this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_)); 727 // Delete it via Max-Age. 728 EXPECT_TRUE(this->SetCookie(cs.get(), 729 this->url_google_, 730 std::string(kValidCookieLine) + "; max-age=0")); 731 this->MatchCookieLineWithTimeout(cs.get(), this->url_google_, std::string()); 732 733 // Create a persistent cookie. 734 EXPECT_TRUE(this->SetCookie( 735 cs.get(), 736 this->url_google_, 737 std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT")); 738 this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_)); 739 // Delete it via Expires. 740 EXPECT_TRUE(this->SetCookie(cs.get(), 741 this->url_google_, 742 std::string(kValidCookieLine) + 743 "; expires=Mon, 18-Apr-1977 22:50:13 GMT")); 744 this->MatchCookieLines(std::string(), 745 this->GetCookies(cs.get(), this->url_google_)); 746 747 // Create a persistent cookie. 748 EXPECT_TRUE(this->SetCookie( 749 cs.get(), 750 this->url_google_, 751 std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT")); 752 this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_)); 753 // Check that it is not deleted with significant enough clock skew. 754 base::Time server_time; 755 EXPECT_TRUE(base::Time::FromString("Sun, 17-Apr-1977 22:50:13 GMT", 756 &server_time)); 757 EXPECT_TRUE(this->SetCookieWithServerTime( 758 cs.get(), 759 this->url_google_, 760 std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-1977 22:50:13 GMT", 761 server_time)); 762 this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_)); 763 764 // Create a persistent cookie. 765 EXPECT_TRUE(this->SetCookie( 766 cs.get(), 767 this->url_google_, 768 std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT")); 769 this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_)); 770 // Delete it via Expires, with a unix epoch of 0. 771 EXPECT_TRUE(this->SetCookie(cs.get(), 772 this->url_google_, 773 std::string(kValidCookieLine) + 774 "; expires=Thu, 1-Jan-1970 00:00:00 GMT")); 775 this->MatchCookieLines(std::string(), 776 this->GetCookies(cs.get(), this->url_google_)); 777 } 778 779 TYPED_TEST_P(CookieStoreTest, TestDeleteAllCreatedBetween) { 780 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 781 const base::Time last_month = base::Time::Now() - 782 base::TimeDelta::FromDays(30); 783 const base::Time last_minute = base::Time::Now() - 784 base::TimeDelta::FromMinutes(1); 785 const base::Time next_minute = base::Time::Now() + 786 base::TimeDelta::FromMinutes(1); 787 const base::Time next_month = base::Time::Now() + 788 base::TimeDelta::FromDays(30); 789 790 // Add a cookie. 791 EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, "A=B")); 792 // Check that the cookie is in the store. 793 this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_)); 794 795 // Remove cookies in empty intervals. 796 EXPECT_EQ(0, this->DeleteCreatedBetween(cs.get(), last_month, last_minute)); 797 EXPECT_EQ(0, this->DeleteCreatedBetween(cs.get(), next_minute, next_month)); 798 // Check that the cookie is still there. 799 this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_)); 800 801 // Remove the cookie with an interval defined by two dates. 802 EXPECT_EQ(1, this->DeleteCreatedBetween(cs.get(), last_minute, next_minute)); 803 // Check that the cookie disappeared. 804 this->MatchCookieLines(std::string(), 805 this->GetCookies(cs.get(), this->url_google_)); 806 807 // Add another cookie. 808 EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, "C=D")); 809 // Check that the cookie is in the store. 810 this->MatchCookieLines("C=D", this->GetCookies(cs.get(), this->url_google_)); 811 812 // Remove the cookie with a null ending time. 813 EXPECT_EQ(1, this->DeleteCreatedBetween(cs.get(), last_minute, base::Time())); 814 // Check that the cookie disappeared. 815 this->MatchCookieLines(std::string(), 816 this->GetCookies(cs.get(), this->url_google_)); 817 } 818 819 TYPED_TEST_P(CookieStoreTest, TestDeleteAllCreatedBetweenForHost) { 820 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 821 GURL url_not_google("http://www.notgoogle.com"); 822 base::Time now = base::Time::Now(); 823 824 // These 3 cookies match the time range and host. 825 EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, "A=B")); 826 EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, "C=D")); 827 EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, "Y=Z")); 828 829 // This cookie does not match host. 830 EXPECT_TRUE(this->SetCookie(cs.get(), url_not_google, "E=F")); 831 832 // Delete cookies. 833 EXPECT_EQ( 834 3, // Deletes A=B, C=D, Y=Z 835 this->DeleteAllCreatedBetweenForHost( 836 cs.get(), now, base::Time::Max(), this->url_google_)); 837 } 838 839 TYPED_TEST_P(CookieStoreTest, TestSecure) { 840 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 841 842 EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, "A=B")); 843 this->MatchCookieLines("A=B", 844 this->GetCookies(cs.get(), this->url_google_)); 845 this->MatchCookieLines( 846 "A=B", this->GetCookies(cs.get(), this->url_google_secure_)); 847 848 EXPECT_TRUE( 849 this->SetCookie(cs.get(), this->url_google_secure_, "A=B; secure")); 850 // The secure should overwrite the non-secure. 851 this->MatchCookieLines(std::string(), 852 this->GetCookies(cs.get(), this->url_google_)); 853 this->MatchCookieLines("A=B", 854 this->GetCookies(cs.get(), this->url_google_secure_)); 855 856 EXPECT_TRUE( 857 this->SetCookie(cs.get(), this->url_google_secure_, "D=E; secure")); 858 this->MatchCookieLines(std::string(), 859 this->GetCookies(cs.get(), this->url_google_)); 860 this->MatchCookieLines("A=B; D=E", 861 this->GetCookies(cs.get(), this->url_google_secure_)); 862 863 EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_secure_, "A=B")); 864 // The non-secure should overwrite the secure. 865 this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_)); 866 this->MatchCookieLines("D=E; A=B", 867 this->GetCookies(cs.get(), this->url_google_secure_)); 868 } 869 870 static const int kLastAccessThresholdMilliseconds = 200; 871 872 // Formerly NetUtilTest.CookieTest back when we used wininet's cookie handling. 873 TYPED_TEST_P(CookieStoreTest, NetUtilCookieTest) { 874 const GURL test_url("http://mojo.jojo.google.izzle/"); 875 876 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 877 878 EXPECT_TRUE(this->SetCookie(cs.get(), test_url, "foo=bar")); 879 std::string value = this->GetCookies(cs.get(), test_url); 880 this->MatchCookieLines("foo=bar", value); 881 882 // test that we can retrieve all cookies: 883 EXPECT_TRUE(this->SetCookie(cs.get(), test_url, "x=1")); 884 EXPECT_TRUE(this->SetCookie(cs.get(), test_url, "y=2")); 885 886 std::string result = this->GetCookies(cs.get(), test_url); 887 EXPECT_FALSE(result.empty()); 888 EXPECT_NE(result.find("x=1"), std::string::npos) << result; 889 EXPECT_NE(result.find("y=2"), std::string::npos) << result; 890 } 891 892 TYPED_TEST_P(CookieStoreTest, OverwritePersistentCookie) { 893 GURL url_google("http://www.google.com/"); 894 GURL url_chromium("http://chromium.org"); 895 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 896 897 // Insert a cookie "a" for path "/path1" 898 EXPECT_TRUE(this->SetCookie(cs.get(), 899 url_google, 900 "a=val1; path=/path1; " 901 "expires=Mon, 18-Apr-22 22:50:13 GMT")); 902 903 // Insert a cookie "b" for path "/path1" 904 EXPECT_TRUE(this->SetCookie(cs.get(), 905 url_google, 906 "b=val1; path=/path1; " 907 "expires=Mon, 18-Apr-22 22:50:14 GMT")); 908 909 // Insert a cookie "b" for path "/path1", that is httponly. This should 910 // overwrite the non-http-only version. 911 CookieOptions allow_httponly; 912 allow_httponly.set_include_httponly(); 913 EXPECT_TRUE(this->SetCookieWithOptions(cs.get(), 914 url_google, 915 "b=val2; path=/path1; httponly; " 916 "expires=Mon, 18-Apr-22 22:50:14 GMT", 917 allow_httponly)); 918 919 // Insert a cookie "a" for path "/path1". This should overwrite. 920 EXPECT_TRUE(this->SetCookie(cs.get(), 921 url_google, 922 "a=val33; path=/path1; " 923 "expires=Mon, 18-Apr-22 22:50:14 GMT")); 924 925 // Insert a cookie "a" for path "/path2". This should NOT overwrite 926 // cookie "a", since the path is different. 927 EXPECT_TRUE(this->SetCookie(cs.get(), 928 url_google, 929 "a=val9; path=/path2; " 930 "expires=Mon, 18-Apr-22 22:50:14 GMT")); 931 932 // Insert a cookie "a" for path "/path1", but this time for "chromium.org". 933 // Although the name and path match, the hostnames do not, so shouldn't 934 // overwrite. 935 EXPECT_TRUE(this->SetCookie(cs.get(), 936 url_chromium, 937 "a=val99; path=/path1; " 938 "expires=Mon, 18-Apr-22 22:50:14 GMT")); 939 940 if (TypeParam::supports_http_only) { 941 this->MatchCookieLines( 942 "a=val33", 943 this->GetCookies(cs.get(), GURL("http://www.google.com/path1"))); 944 } else { 945 this->MatchCookieLines( 946 "a=val33; b=val2", 947 this->GetCookies(cs.get(), GURL("http://www.google.com/path1"))); 948 } 949 this->MatchCookieLines( 950 "a=val9", 951 this->GetCookies(cs.get(), GURL("http://www.google.com/path2"))); 952 this->MatchCookieLines( 953 "a=val99", this->GetCookies(cs.get(), GURL("http://chromium.org/path1"))); 954 } 955 956 TYPED_TEST_P(CookieStoreTest, CookieOrdering) { 957 // Put a random set of cookies into a store and make sure they're returned in 958 // the right order. 959 // Cookies should be sorted by path length and creation time, as per RFC6265. 960 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 961 EXPECT_TRUE(this->SetCookie( 962 cs.get(), GURL("http://d.c.b.a.google.com/aa/x.html"), "c=1")); 963 EXPECT_TRUE(this->SetCookie(cs.get(), 964 GURL("http://b.a.google.com/aa/bb/cc/x.html"), 965 "d=1; domain=b.a.google.com")); 966 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds( 967 TypeParam::creation_time_granularity_in_ms)); 968 EXPECT_TRUE(this->SetCookie(cs.get(), 969 GURL("http://b.a.google.com/aa/bb/cc/x.html"), 970 "a=4; domain=b.a.google.com")); 971 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds( 972 TypeParam::creation_time_granularity_in_ms)); 973 EXPECT_TRUE(this->SetCookie(cs.get(), 974 GURL("http://c.b.a.google.com/aa/bb/cc/x.html"), 975 "e=1; domain=c.b.a.google.com")); 976 EXPECT_TRUE(this->SetCookie( 977 cs.get(), GURL("http://d.c.b.a.google.com/aa/bb/x.html"), "b=1")); 978 EXPECT_TRUE(this->SetCookie( 979 cs.get(), GURL("http://news.bbc.co.uk/midpath/x.html"), "g=10")); 980 EXPECT_EQ("d=1; a=4; e=1; b=1; c=1", 981 this->GetCookies(cs.get(), 982 GURL("http://d.c.b.a.google.com/aa/bb/cc/dd"))); 983 } 984 985 TYPED_TEST_P(CookieStoreTest, DeleteSessionCookie) { 986 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 987 // Create a session cookie and a persistent cookie. 988 EXPECT_TRUE(this->SetCookie( 989 cs.get(), this->url_google_, std::string(kValidCookieLine))); 990 EXPECT_TRUE(this->SetCookie(cs.get(), 991 this->url_google_, 992 "C=D; path=/; domain=google.izzle;" 993 "expires=Mon, 18-Apr-22 22:50:13 GMT")); 994 this->MatchCookieLines("A=B; C=D", 995 this->GetCookies(cs.get(), this->url_google_)); 996 // Delete the session cookie. 997 this->DeleteSessionCookies(cs.get()); 998 // Check that the session cookie has been deleted but not the persistent one. 999 EXPECT_EQ("C=D", this->GetCookies(cs.get(), this->url_google_)); 1000 } 1001 1002 REGISTER_TYPED_TEST_CASE_P(CookieStoreTest, 1003 TypeTest, 1004 DomainTest, 1005 DomainWithTrailingDotTest, 1006 ValidSubdomainTest, 1007 InvalidDomainTest, 1008 DomainWithoutLeadingDotTest, 1009 CaseInsensitiveDomainTest, 1010 TestIpAddress, 1011 TestNonDottedAndTLD, 1012 TestHostEndsWithDot, 1013 InvalidScheme, 1014 InvalidScheme_Read, 1015 PathTest, 1016 EmptyExpires, 1017 HttpOnlyTest, 1018 TestCookieDeletion, 1019 TestDeleteAllCreatedBetween, 1020 TestDeleteAllCreatedBetweenForHost, 1021 TestSecure, 1022 NetUtilCookieTest, 1023 OverwritePersistentCookie, 1024 CookieOrdering, 1025 DeleteSessionCookie); 1026 1027 template<class CookieStoreTestTraits> 1028 class MultiThreadedCookieStoreTest : 1029 public CookieStoreTest<CookieStoreTestTraits> { 1030 public: 1031 MultiThreadedCookieStoreTest() : other_thread_("CMTthread") {} 1032 1033 // Helper methods for calling the asynchronous CookieStore methods 1034 // from a different thread. 1035 1036 void GetCookiesTask(CookieStore* cs, 1037 const GURL& url, 1038 StringResultCookieCallback* callback) { 1039 CookieOptions options; 1040 if (!CookieStoreTestTraits::supports_http_only) 1041 options.set_include_httponly(); 1042 cs->GetCookiesWithOptionsAsync( 1043 url, options, 1044 base::Bind(&StringResultCookieCallback::Run, 1045 base::Unretained(callback))); 1046 } 1047 1048 void GetCookiesWithOptionsTask(CookieStore* cs, 1049 const GURL& url, 1050 const CookieOptions& options, 1051 StringResultCookieCallback* callback) { 1052 cs->GetCookiesWithOptionsAsync( 1053 url, options, 1054 base::Bind(&StringResultCookieCallback::Run, 1055 base::Unretained(callback))); 1056 } 1057 1058 void SetCookieWithOptionsTask(CookieStore* cs, 1059 const GURL& url, 1060 const std::string& cookie_line, 1061 const CookieOptions& options, 1062 ResultSavingCookieCallback<bool>* callback) { 1063 cs->SetCookieWithOptionsAsync( 1064 url, cookie_line, options, 1065 base::Bind( 1066 &ResultSavingCookieCallback<bool>::Run, 1067 base::Unretained(callback))); 1068 } 1069 1070 void DeleteCookieTask(CookieStore* cs, 1071 const GURL& url, 1072 const std::string& cookie_name, 1073 NoResultCookieCallback* callback) { 1074 cs->DeleteCookieAsync( 1075 url, cookie_name, 1076 base::Bind(&NoResultCookieCallback::Run, base::Unretained(callback))); 1077 } 1078 1079 void DeleteSessionCookiesTask(CookieStore* cs, 1080 ResultSavingCookieCallback<int>* callback) { 1081 cs->DeleteSessionCookiesAsync( 1082 base::Bind( 1083 &ResultSavingCookieCallback<int>::Run, 1084 base::Unretained(callback))); 1085 } 1086 1087 protected: 1088 void RunOnOtherThread(const base::Closure& task) { 1089 other_thread_.Start(); 1090 other_thread_.message_loop()->PostTask(FROM_HERE, task); 1091 CookieStoreTest<CookieStoreTestTraits>::RunFor(kTimeout); 1092 other_thread_.Stop(); 1093 } 1094 1095 Thread other_thread_; 1096 }; 1097 1098 TYPED_TEST_CASE_P(MultiThreadedCookieStoreTest); 1099 1100 // TODO(ycxiao): Eventually, we will need to create a separate thread, create 1101 // the cookie store on that thread (or at least its store, i.e., the DB 1102 // thread). 1103 TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckGetCookies) { 1104 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 1105 EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, "A=B")); 1106 this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_)); 1107 StringResultCookieCallback callback(&this->other_thread_); 1108 base::Closure task = base::Bind( 1109 &net::MultiThreadedCookieStoreTest<TypeParam>::GetCookiesTask, 1110 base::Unretained(this), 1111 cs, this->url_google_, &callback); 1112 this->RunOnOtherThread(task); 1113 EXPECT_TRUE(callback.did_run()); 1114 EXPECT_EQ("A=B", callback.result()); 1115 } 1116 1117 TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckGetCookiesWithOptions) { 1118 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 1119 CookieOptions options; 1120 if (!TypeParam::supports_http_only) 1121 options.set_include_httponly(); 1122 EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, "A=B")); 1123 this->MatchCookieLines( 1124 "A=B", this->GetCookiesWithOptions(cs.get(), this->url_google_, options)); 1125 StringResultCookieCallback callback(&this->other_thread_); 1126 base::Closure task = base::Bind( 1127 &net::MultiThreadedCookieStoreTest<TypeParam>::GetCookiesWithOptionsTask, 1128 base::Unretained(this), 1129 cs, this->url_google_, options, &callback); 1130 this->RunOnOtherThread(task); 1131 EXPECT_TRUE(callback.did_run()); 1132 EXPECT_EQ("A=B", callback.result()); 1133 } 1134 1135 TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckSetCookieWithOptions) { 1136 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 1137 CookieOptions options; 1138 if (!TypeParam::supports_http_only) 1139 options.set_include_httponly(); 1140 EXPECT_TRUE( 1141 this->SetCookieWithOptions(cs.get(), this->url_google_, "A=B", options)); 1142 ResultSavingCookieCallback<bool> callback(&this->other_thread_); 1143 base::Closure task = base::Bind( 1144 &net::MultiThreadedCookieStoreTest<TypeParam>::SetCookieWithOptionsTask, 1145 base::Unretained(this), 1146 cs, this->url_google_, "A=B", options, &callback); 1147 this->RunOnOtherThread(task); 1148 EXPECT_TRUE(callback.did_run()); 1149 EXPECT_TRUE(callback.result()); 1150 } 1151 1152 TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckDeleteCookie) { 1153 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 1154 CookieOptions options; 1155 if (!TypeParam::supports_http_only) 1156 options.set_include_httponly(); 1157 EXPECT_TRUE( 1158 this->SetCookieWithOptions(cs.get(), this->url_google_, "A=B", options)); 1159 this->DeleteCookie(cs.get(), this->url_google_, "A"); 1160 EXPECT_TRUE( 1161 this->SetCookieWithOptions(cs.get(), this->url_google_, "A=B", options)); 1162 NoResultCookieCallback callback(&this->other_thread_); 1163 base::Closure task = base::Bind( 1164 &net::MultiThreadedCookieStoreTest<TypeParam>::DeleteCookieTask, 1165 base::Unretained(this), 1166 cs, this->url_google_, "A", &callback); 1167 this->RunOnOtherThread(task); 1168 EXPECT_TRUE(callback.did_run()); 1169 } 1170 1171 TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckDeleteSessionCookies) { 1172 scoped_refptr<CookieStore> cs(this->GetCookieStore()); 1173 CookieOptions options; 1174 if (!TypeParam::supports_http_only) 1175 options.set_include_httponly(); 1176 EXPECT_TRUE( 1177 this->SetCookieWithOptions(cs.get(), this->url_google_, "A=B", options)); 1178 EXPECT_TRUE( 1179 this->SetCookieWithOptions(cs.get(), 1180 this->url_google_, 1181 "B=C; expires=Mon, 18-Apr-22 22:50:13 GMT", 1182 options)); 1183 EXPECT_EQ(1, this->DeleteSessionCookies(cs.get())); 1184 EXPECT_EQ(0, this->DeleteSessionCookies(cs.get())); 1185 EXPECT_TRUE( 1186 this->SetCookieWithOptions(cs.get(), this->url_google_, "A=B", options)); 1187 ResultSavingCookieCallback<int> callback(&this->other_thread_); 1188 base::Closure task = base::Bind( 1189 &net::MultiThreadedCookieStoreTest<TypeParam>::DeleteSessionCookiesTask, 1190 base::Unretained(this), 1191 cs, &callback); 1192 this->RunOnOtherThread(task); 1193 EXPECT_TRUE(callback.did_run()); 1194 EXPECT_EQ(1, callback.result()); 1195 } 1196 1197 REGISTER_TYPED_TEST_CASE_P(MultiThreadedCookieStoreTest, 1198 ThreadCheckGetCookies, 1199 ThreadCheckGetCookiesWithOptions, 1200 ThreadCheckSetCookieWithOptions, 1201 ThreadCheckDeleteCookie, 1202 ThreadCheckDeleteSessionCookies); 1203 1204 } // namespace net 1205 1206 #endif // NET_COOKIES_COOKIE_STORE_UNITTEST_H_ 1207