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