- add sources.
[platform/framework/web/crosswalk.git] / src / net / cookies / cookie_store_unittest.h
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_