1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <time.h>
6
7#include <string>
8
9#include "base/basictypes.h"
10#include "base/memory/ref_counted.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/message_loop.h"
13#include "base/metrics/histogram.h"
14#include "base/string_util.h"
15#include "base/stringprintf.h"
16#include "base/threading/platform_thread.h"
17#include "base/time.h"
18#include "googleurl/src/gurl.h"
19#include "net/base/cookie_monster.h"
20#include "net/base/cookie_monster_store_test.h" // For CookieStore Mock
21#include "testing/gtest/include/gtest/gtest.h"
22
23namespace net {
24
25using base::Time;
26using base::TimeDelta;
27
28namespace {
29
30class ParsedCookieTest : public testing::Test { };
31class CookieMonsterTest : public testing::Test { };
32
33// Helper for DeleteAllForHost test; repopulates CM with same layout
34// each time.
35const char* kTopLevelDomainPlus1 = "http://www.harvard.edu";
36const char* kTopLevelDomainPlus2 = "http://www.math.harvard.edu";
37const char* kTopLevelDomainPlus2Secure = "https://www.math.harvard.edu";
38const char* kTopLevelDomainPlus3 =
39    "http://www.bourbaki.math.harvard.edu";
40const char* kOtherDomain = "http://www.mit.edu";
41
42void PopulateCmForDeleteAllForHost(scoped_refptr<CookieMonster> cm) {
43  GURL url_top_level_domain_plus_1(kTopLevelDomainPlus1);
44  GURL url_top_level_domain_plus_2(kTopLevelDomainPlus2);
45  GURL url_top_level_domain_plus_2_secure(kTopLevelDomainPlus2Secure);
46  GURL url_top_level_domain_plus_3(kTopLevelDomainPlus3);
47  GURL url_other(kOtherDomain);
48
49  cm->DeleteAll(true);
50
51  // Static population for probe:
52  //    * Three levels of domain cookie (.b.a, .c.b.a, .d.c.b.a)
53  //    * Three levels of host cookie (w.b.a, w.c.b.a, w.d.c.b.a)
54  //    * http_only cookie (w.c.b.a)
55  //    * Two secure cookies (.c.b.a, w.c.b.a)
56  //    * Two domain path cookies (.c.b.a/dir1, .c.b.a/dir1/dir2)
57  //    * Two host path cookies (w.c.b.a/dir1, w.c.b.a/dir1/dir2)
58
59  // Domain cookies
60  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_1,
61                                       "dom_1", "X", ".harvard.edu", "/",
62                                       base::Time(), false, false));
63  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2,
64                                       "dom_2", "X", ".math.harvard.edu", "/",
65                                       base::Time(), false, false));
66  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_3,
67                                       "dom_3", "X",
68                                       ".bourbaki.math.harvard.edu", "/",
69                                       base::Time(), false, false));
70
71  // Host cookies
72  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_1,
73                                       "host_1", "X", "", "/",
74                                       base::Time(), false, false));
75  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2,
76                                       "host_2", "X", "", "/",
77                                       base::Time(), false, false));
78  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_3,
79                                       "host_3", "X", "", "/",
80                                       base::Time(), false, false));
81
82  // Http_only cookie
83  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2,
84                                       "httpo_check", "X", "", "/",
85                                       base::Time(), false, true));
86
87  // Secure cookies
88  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2_secure,
89                                       "sec_dom", "X", ".math.harvard.edu",
90                                       "/", base::Time(), true, false));
91  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2_secure,
92                                       "sec_host", "X", "", "/",
93                                       base::Time(), true, false));
94
95  // Domain path cookies
96  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2,
97                                       "dom_path_1", "X",
98                                       ".math.harvard.edu", "/dir1",
99                                       base::Time(), false, false));
100  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2,
101                                       "dom_path_2", "X",
102                                       ".math.harvard.edu", "/dir1/dir2",
103                                       base::Time(), false, false));
104
105  // Host path cookies
106  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2,
107                                       "host_path_1", "X",
108                                       "", "/dir1",
109                                       base::Time(), false, false));
110  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2,
111                                       "host_path_2", "X",
112                                       "", "/dir1/dir2",
113                                       base::Time(), false, false));
114
115  EXPECT_EQ(13U, cm->GetAllCookies().size());
116}
117
118}  // namespace
119
120TEST(ParsedCookieTest, TestBasic) {
121  CookieMonster::ParsedCookie pc("a=b");
122  EXPECT_TRUE(pc.IsValid());
123  EXPECT_FALSE(pc.IsSecure());
124  EXPECT_EQ("a", pc.Name());
125  EXPECT_EQ("b", pc.Value());
126}
127
128TEST(ParsedCookieTest, TestQuoted) {
129  // These are some quoting cases which the major browsers all
130  // handle differently.  I've tested Internet Explorer 6, Opera 9.6,
131  // Firefox 3, and Safari Windows 3.2.1.  We originally tried to match
132  // Firefox closely, however we now match Internet Explorer and Safari.
133  const char* values[] = {
134    // Trailing whitespace after a quoted value.  The whitespace after
135    // the quote is stripped in all browsers.
136    "\"zzz \"  ",              "\"zzz \"",
137    // Handling a quoted value with a ';', like FOO="zz;pp"  ;
138    // IE and Safari: "zz;
139    // Firefox and Opera: "zz;pp"
140    "\"zz;pp\" ;",             "\"zz",
141    // Handling a value with multiple quoted parts, like FOO="zzz "   "ppp" ;
142    // IE and Safari: "zzz "   "ppp";
143    // Firefox: "zzz ";
144    // Opera: <rejects cookie>
145    "\"zzz \"   \"ppp\" ",     "\"zzz \"   \"ppp\"",
146    // A quote in a value that didn't start quoted.  like FOO=A"B ;
147    // IE, Safari, and Firefox: A"B;
148    // Opera: <rejects cookie>
149    "A\"B",                    "A\"B",
150  };
151
152  for (size_t i = 0; i < arraysize(values); i += 2) {
153    std::string input(values[i]);
154    std::string expected(values[i + 1]);
155
156    CookieMonster::ParsedCookie pc(
157        "aBc=" + input + " ; path=\"/\"  ; httponly ");
158    EXPECT_TRUE(pc.IsValid());
159    EXPECT_FALSE(pc.IsSecure());
160    EXPECT_TRUE(pc.IsHttpOnly());
161    EXPECT_TRUE(pc.HasPath());
162    EXPECT_EQ("aBc", pc.Name());
163    EXPECT_EQ(expected, pc.Value());
164
165    // If a path was quoted, the path attribute keeps the quotes.  This will
166    // make the cookie effectively useless, but path parameters aren't supposed
167    // to be quoted.  Bug 1261605.
168    EXPECT_EQ("\"/\"", pc.Path());
169  }
170}
171
172TEST(ParsedCookieTest, TestNameless) {
173  CookieMonster::ParsedCookie pc("BLAHHH; path=/; secure;");
174  EXPECT_TRUE(pc.IsValid());
175  EXPECT_TRUE(pc.IsSecure());
176  EXPECT_TRUE(pc.HasPath());
177  EXPECT_EQ("/", pc.Path());
178  EXPECT_EQ("", pc.Name());
179  EXPECT_EQ("BLAHHH", pc.Value());
180}
181
182TEST(ParsedCookieTest, TestAttributeCase) {
183  CookieMonster::ParsedCookie pc("BLAHHH; Path=/; sECuRe; httpONLY");
184  EXPECT_TRUE(pc.IsValid());
185  EXPECT_TRUE(pc.IsSecure());
186  EXPECT_TRUE(pc.IsHttpOnly());
187  EXPECT_TRUE(pc.HasPath());
188  EXPECT_EQ("/", pc.Path());
189  EXPECT_EQ("", pc.Name());
190  EXPECT_EQ("BLAHHH", pc.Value());
191  EXPECT_EQ(3U, pc.NumberOfAttributes());
192}
193
194TEST(ParsedCookieTest, TestDoubleQuotedNameless) {
195  CookieMonster::ParsedCookie pc("\"BLA\\\"HHH\"; path=/; secure;");
196  EXPECT_TRUE(pc.IsValid());
197  EXPECT_TRUE(pc.IsSecure());
198  EXPECT_TRUE(pc.HasPath());
199  EXPECT_EQ("/", pc.Path());
200  EXPECT_EQ("", pc.Name());
201  EXPECT_EQ("\"BLA\\\"HHH\"", pc.Value());
202  EXPECT_EQ(2U, pc.NumberOfAttributes());
203}
204
205TEST(ParsedCookieTest, QuoteOffTheEnd) {
206  CookieMonster::ParsedCookie pc("a=\"B");
207  EXPECT_TRUE(pc.IsValid());
208  EXPECT_EQ("a", pc.Name());
209  EXPECT_EQ("\"B", pc.Value());
210  EXPECT_EQ(0U, pc.NumberOfAttributes());
211}
212
213TEST(ParsedCookieTest, MissingName) {
214  CookieMonster::ParsedCookie pc("=ABC");
215  EXPECT_TRUE(pc.IsValid());
216  EXPECT_EQ("", pc.Name());
217  EXPECT_EQ("ABC", pc.Value());
218  EXPECT_EQ(0U, pc.NumberOfAttributes());
219}
220
221TEST(ParsedCookieTest, MissingValue) {
222  CookieMonster::ParsedCookie pc("ABC=;  path = /wee");
223  EXPECT_TRUE(pc.IsValid());
224  EXPECT_EQ("ABC", pc.Name());
225  EXPECT_EQ("", pc.Value());
226  EXPECT_TRUE(pc.HasPath());
227  EXPECT_EQ("/wee", pc.Path());
228  EXPECT_EQ(1U, pc.NumberOfAttributes());
229}
230
231TEST(ParsedCookieTest, Whitespace) {
232  CookieMonster::ParsedCookie pc("  A  = BC  ;secure;;;   httponly");
233  EXPECT_TRUE(pc.IsValid());
234  EXPECT_EQ("A", pc.Name());
235  EXPECT_EQ("BC", pc.Value());
236  EXPECT_FALSE(pc.HasPath());
237  EXPECT_FALSE(pc.HasDomain());
238  EXPECT_TRUE(pc.IsSecure());
239  EXPECT_TRUE(pc.IsHttpOnly());
240  // We parse anything between ; as attributes, so we end up with two
241  // attributes with an empty string name and value.
242  EXPECT_EQ(4U, pc.NumberOfAttributes());
243}
244TEST(ParsedCookieTest, MultipleEquals) {
245  CookieMonster::ParsedCookie pc("  A=== BC  ;secure;;;   httponly");
246  EXPECT_TRUE(pc.IsValid());
247  EXPECT_EQ("A", pc.Name());
248  EXPECT_EQ("== BC", pc.Value());
249  EXPECT_FALSE(pc.HasPath());
250  EXPECT_FALSE(pc.HasDomain());
251  EXPECT_TRUE(pc.IsSecure());
252  EXPECT_TRUE(pc.IsHttpOnly());
253  EXPECT_EQ(4U, pc.NumberOfAttributes());
254}
255
256TEST(ParsedCookieTest, QuotedTrailingWhitespace) {
257  CookieMonster::ParsedCookie pc("ANCUUID=\"zohNumRKgI0oxyhSsV3Z7D\"  ; "
258                                      "expires=Sun, 18-Apr-2027 21:06:29 GMT ; "
259                                      "path=/  ;  ");
260  EXPECT_TRUE(pc.IsValid());
261  EXPECT_EQ("ANCUUID", pc.Name());
262  // Stripping whitespace after the quotes matches all other major browsers.
263  EXPECT_EQ("\"zohNumRKgI0oxyhSsV3Z7D\"", pc.Value());
264  EXPECT_TRUE(pc.HasExpires());
265  EXPECT_TRUE(pc.HasPath());
266  EXPECT_EQ("/", pc.Path());
267  EXPECT_EQ(2U, pc.NumberOfAttributes());
268}
269
270TEST(ParsedCookieTest, TrailingWhitespace) {
271  CookieMonster::ParsedCookie pc("ANCUUID=zohNumRKgI0oxyhSsV3Z7D  ; "
272                                      "expires=Sun, 18-Apr-2027 21:06:29 GMT ; "
273                                      "path=/  ;  ");
274  EXPECT_TRUE(pc.IsValid());
275  EXPECT_EQ("ANCUUID", pc.Name());
276  EXPECT_EQ("zohNumRKgI0oxyhSsV3Z7D", pc.Value());
277  EXPECT_TRUE(pc.HasExpires());
278  EXPECT_TRUE(pc.HasPath());
279  EXPECT_EQ("/", pc.Path());
280  EXPECT_EQ(2U, pc.NumberOfAttributes());
281}
282
283TEST(ParsedCookieTest, TooManyPairs) {
284  std::string blankpairs;
285  blankpairs.resize(CookieMonster::ParsedCookie::kMaxPairs - 1, ';');
286
287  CookieMonster::ParsedCookie pc1(blankpairs + "secure");
288  EXPECT_TRUE(pc1.IsValid());
289  EXPECT_TRUE(pc1.IsSecure());
290
291  CookieMonster::ParsedCookie pc2(blankpairs + ";secure");
292  EXPECT_TRUE(pc2.IsValid());
293  EXPECT_FALSE(pc2.IsSecure());
294}
295
296// TODO some better test cases for invalid cookies.
297TEST(ParsedCookieTest, InvalidWhitespace) {
298  CookieMonster::ParsedCookie pc("    ");
299  EXPECT_FALSE(pc.IsValid());
300}
301
302TEST(ParsedCookieTest, InvalidTooLong) {
303  std::string maxstr;
304  maxstr.resize(CookieMonster::ParsedCookie::kMaxCookieSize, 'a');
305
306  CookieMonster::ParsedCookie pc1(maxstr);
307  EXPECT_TRUE(pc1.IsValid());
308
309  CookieMonster::ParsedCookie pc2(maxstr + "A");
310  EXPECT_FALSE(pc2.IsValid());
311}
312
313TEST(ParsedCookieTest, InvalidEmpty) {
314  CookieMonster::ParsedCookie pc("");
315  EXPECT_FALSE(pc.IsValid());
316}
317
318TEST(ParsedCookieTest, EmbeddedTerminator) {
319  CookieMonster::ParsedCookie pc1("AAA=BB\0ZYX");
320  CookieMonster::ParsedCookie pc2("AAA=BB\rZYX");
321  CookieMonster::ParsedCookie pc3("AAA=BB\nZYX");
322  EXPECT_TRUE(pc1.IsValid());
323  EXPECT_EQ("AAA", pc1.Name());
324  EXPECT_EQ("BB", pc1.Value());
325  EXPECT_TRUE(pc2.IsValid());
326  EXPECT_EQ("AAA", pc2.Name());
327  EXPECT_EQ("BB", pc2.Value());
328  EXPECT_TRUE(pc3.IsValid());
329  EXPECT_EQ("AAA", pc3.Name());
330  EXPECT_EQ("BB", pc3.Value());
331}
332
333TEST(ParsedCookieTest, ParseTokensAndValues) {
334  EXPECT_EQ("hello",
335            CookieMonster::ParsedCookie::ParseTokenString(
336                "hello\nworld"));
337  EXPECT_EQ("fs!!@",
338            CookieMonster::ParsedCookie::ParseTokenString(
339                "fs!!@;helloworld"));
340  EXPECT_EQ("hello world\tgood",
341            CookieMonster::ParsedCookie::ParseTokenString(
342                "hello world\tgood\rbye"));
343  EXPECT_EQ("A",
344            CookieMonster::ParsedCookie::ParseTokenString(
345                "A=B=C;D=E"));
346  EXPECT_EQ("hello",
347            CookieMonster::ParsedCookie::ParseValueString(
348                "hello\nworld"));
349  EXPECT_EQ("fs!!@",
350            CookieMonster::ParsedCookie::ParseValueString(
351                "fs!!@;helloworld"));
352  EXPECT_EQ("hello world\tgood",
353            CookieMonster::ParsedCookie::ParseValueString(
354                "hello world\tgood\rbye"));
355  EXPECT_EQ("A=B=C",
356            CookieMonster::ParsedCookie::ParseValueString(
357                "A=B=C;D=E"));
358}
359
360static const char kUrlGoogle[] = "http://www.google.izzle";
361static const char kUrlGoogleSpecific[] = "http://www.gmail.google.izzle";
362static const char kUrlGoogleSecure[] = "https://www.google.izzle";
363static const char kUrlFtp[] = "ftp://ftp.google.izzle/";
364static const char kValidCookieLine[] = "A=B; path=/";
365static const char kValidDomainCookieLine[] = "A=B; path=/; domain=google.izzle";
366
367TEST(CookieMonsterTest, DomainTest) {
368  GURL url_google(kUrlGoogle);
369
370  scoped_refptr<MockPersistentCookieStore> store(
371      new MockPersistentCookieStore);
372  scoped_refptr<CookieMonster> cm(new CookieMonster(store, NULL));
373  EXPECT_TRUE(cm->SetCookie(url_google, "A=B"));
374  EXPECT_EQ("A=B", cm->GetCookies(url_google));
375  EXPECT_TRUE(cm->SetCookie(url_google, "C=D; domain=.google.izzle"));
376  EXPECT_EQ("A=B; C=D", cm->GetCookies(url_google));
377
378  // Verify that A=B was set as a host cookie rather than a domain
379  // cookie -- should not be accessible from a sub sub-domain.
380  EXPECT_EQ("C=D", cm->GetCookies(GURL("http://foo.www.google.izzle")));
381
382  // Test and make sure we find domain cookies on the same domain.
383  EXPECT_TRUE(cm->SetCookie(url_google, "E=F; domain=.www.google.izzle"));
384  EXPECT_EQ("A=B; C=D; E=F", cm->GetCookies(url_google));
385
386  // Test setting a domain= that doesn't start w/ a dot, should
387  // treat it as a domain cookie, as if there was a pre-pended dot.
388  EXPECT_TRUE(cm->SetCookie(url_google, "G=H; domain=www.google.izzle"));
389  EXPECT_EQ("A=B; C=D; E=F; G=H", cm->GetCookies(url_google));
390
391  // Test domain enforcement, should fail on a sub-domain or something too deep.
392  EXPECT_FALSE(cm->SetCookie(url_google, "I=J; domain=.izzle"));
393  EXPECT_EQ("", cm->GetCookies(GURL("http://a.izzle")));
394  EXPECT_FALSE(cm->SetCookie(url_google, "K=L; domain=.bla.www.google.izzle"));
395  EXPECT_EQ("C=D; E=F; G=H",
396            cm->GetCookies(GURL("http://bla.www.google.izzle")));
397  EXPECT_EQ("A=B; C=D; E=F; G=H", cm->GetCookies(url_google));
398
399  // Nothing was persisted to the backing store.
400  EXPECT_EQ(0u, store->commands().size());
401}
402
403// FireFox recognizes domains containing trailing periods as valid.
404// IE and Safari do not. Assert the expected policy here.
405TEST(CookieMonsterTest, DomainWithTrailingDotTest) {
406  scoped_refptr<MockPersistentCookieStore> store(
407      new MockPersistentCookieStore);
408  scoped_refptr<CookieMonster> cm(new CookieMonster(store, NULL));
409  GURL url_google("http://www.google.com");
410
411  EXPECT_FALSE(cm->SetCookie(url_google, "a=1; domain=.www.google.com."));
412  EXPECT_FALSE(cm->SetCookie(url_google, "b=2; domain=.www.google.com.."));
413  EXPECT_EQ("", cm->GetCookies(url_google));
414
415  // Nothing was persisted to the backing store.
416  EXPECT_EQ(0u, store->commands().size());
417}
418
419// Test that cookies can bet set on higher level domains.
420// http://b/issue?id=896491
421TEST(CookieMonsterTest, ValidSubdomainTest) {
422  scoped_refptr<MockPersistentCookieStore> store(
423      new MockPersistentCookieStore);
424  scoped_refptr<CookieMonster> cm(new CookieMonster(store, NULL));
425  GURL url_abcd("http://a.b.c.d.com");
426  GURL url_bcd("http://b.c.d.com");
427  GURL url_cd("http://c.d.com");
428  GURL url_d("http://d.com");
429
430  EXPECT_TRUE(cm->SetCookie(url_abcd, "a=1; domain=.a.b.c.d.com"));
431  EXPECT_TRUE(cm->SetCookie(url_abcd, "b=2; domain=.b.c.d.com"));
432  EXPECT_TRUE(cm->SetCookie(url_abcd, "c=3; domain=.c.d.com"));
433  EXPECT_TRUE(cm->SetCookie(url_abcd, "d=4; domain=.d.com"));
434
435  EXPECT_EQ("a=1; b=2; c=3; d=4", cm->GetCookies(url_abcd));
436  EXPECT_EQ("b=2; c=3; d=4", cm->GetCookies(url_bcd));
437  EXPECT_EQ("c=3; d=4", cm->GetCookies(url_cd));
438  EXPECT_EQ("d=4", cm->GetCookies(url_d));
439
440  // Check that the same cookie can exist on different sub-domains.
441  EXPECT_TRUE(cm->SetCookie(url_bcd, "X=bcd; domain=.b.c.d.com"));
442  EXPECT_TRUE(cm->SetCookie(url_bcd, "X=cd; domain=.c.d.com"));
443  EXPECT_EQ("b=2; c=3; d=4; X=bcd; X=cd", cm->GetCookies(url_bcd));
444  EXPECT_EQ("c=3; d=4; X=cd", cm->GetCookies(url_cd));
445
446  // Nothing was persisted to the backing store.
447  EXPECT_EQ(0u, store->commands().size());
448}
449
450// Test that setting a cookie which specifies an invalid domain has
451// no side-effect. An invalid domain in this context is one which does
452// not match the originating domain.
453// http://b/issue?id=896472
454TEST(CookieMonsterTest, InvalidDomainTest) {
455  {
456    scoped_refptr<MockPersistentCookieStore> store(
457        new MockPersistentCookieStore);
458
459    scoped_refptr<CookieMonster> cm(new CookieMonster(store, NULL));
460    GURL url_foobar("http://foo.bar.com");
461
462    // More specific sub-domain than allowed.
463    EXPECT_FALSE(cm->SetCookie(url_foobar, "a=1; domain=.yo.foo.bar.com"));
464
465    EXPECT_FALSE(cm->SetCookie(url_foobar, "b=2; domain=.foo.com"));
466    EXPECT_FALSE(cm->SetCookie(url_foobar, "c=3; domain=.bar.foo.com"));
467
468    // Different TLD, but the rest is a substring.
469    EXPECT_FALSE(cm->SetCookie(url_foobar, "d=4; domain=.foo.bar.com.net"));
470
471    // A substring that isn't really a parent domain.
472    EXPECT_FALSE(cm->SetCookie(url_foobar, "e=5; domain=ar.com"));
473
474    // Completely invalid domains:
475    EXPECT_FALSE(cm->SetCookie(url_foobar, "f=6; domain=."));
476    EXPECT_FALSE(cm->SetCookie(url_foobar, "g=7; domain=/"));
477    EXPECT_FALSE(cm->SetCookie(url_foobar, "h=8; domain=http://foo.bar.com"));
478    EXPECT_FALSE(cm->SetCookie(url_foobar, "i=9; domain=..foo.bar.com"));
479    EXPECT_FALSE(cm->SetCookie(url_foobar, "j=10; domain=..bar.com"));
480
481    // Make sure there isn't something quirky in the domain canonicalization
482    // that supports full URL semantics.
483    EXPECT_FALSE(cm->SetCookie(url_foobar, "k=11; domain=.foo.bar.com?blah"));
484    EXPECT_FALSE(cm->SetCookie(url_foobar, "l=12; domain=.foo.bar.com/blah"));
485    EXPECT_FALSE(cm->SetCookie(url_foobar, "m=13; domain=.foo.bar.com:80"));
486    EXPECT_FALSE(cm->SetCookie(url_foobar, "n=14; domain=.foo.bar.com:"));
487    EXPECT_FALSE(cm->SetCookie(url_foobar, "o=15; domain=.foo.bar.com#sup"));
488
489    EXPECT_EQ("", cm->GetCookies(url_foobar));
490
491    // Nothing was persisted to the backing store.
492    EXPECT_EQ(0u, store->commands().size());
493  }
494
495  {
496    // Make sure the cookie code hasn't gotten its subdomain string handling
497    // reversed, missed a suffix check, etc.  It's important here that the two
498    // hosts below have the same domain + registry.
499    scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
500    GURL url_foocom("http://foo.com.com");
501    EXPECT_FALSE(cm->SetCookie(url_foocom, "a=1; domain=.foo.com.com.com"));
502    EXPECT_EQ("", cm->GetCookies(url_foocom));
503  }
504}
505
506// Test the behavior of omitting dot prefix from domain, should
507// function the same as FireFox.
508// http://b/issue?id=889898
509TEST(CookieMonsterTest, DomainWithoutLeadingDotTest) {
510  {  // The omission of dot results in setting a domain cookie.
511    scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
512    GURL url_hosted("http://manage.hosted.filefront.com");
513    GURL url_filefront("http://www.filefront.com");
514    EXPECT_TRUE(cm->SetCookie(url_hosted, "sawAd=1; domain=filefront.com"));
515    EXPECT_EQ("sawAd=1", cm->GetCookies(url_hosted));
516    EXPECT_EQ("sawAd=1", cm->GetCookies(url_filefront));
517  }
518
519  {  // Even when the domains match exactly, don't consider it host cookie.
520    scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
521    GURL url("http://www.google.com");
522    EXPECT_TRUE(cm->SetCookie(url, "a=1; domain=www.google.com"));
523    EXPECT_EQ("a=1", cm->GetCookies(url));
524    EXPECT_EQ("a=1", cm->GetCookies(GURL("http://sub.www.google.com")));
525    EXPECT_EQ("", cm->GetCookies(GURL("http://something-else.com")));
526  }
527}
528
529// Test that the domain specified in cookie string is treated case-insensitive
530// http://b/issue?id=896475.
531TEST(CookieMonsterTest, CaseInsensitiveDomainTest) {
532  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
533  GURL url_google("http://www.google.com");
534  EXPECT_TRUE(cm->SetCookie(url_google, "a=1; domain=.GOOGLE.COM"));
535  EXPECT_TRUE(cm->SetCookie(url_google, "b=2; domain=.wWw.gOOgLE.coM"));
536  EXPECT_EQ("a=1; b=2", cm->GetCookies(url_google));
537}
538
539TEST(CookieMonsterTest, TestIpAddress) {
540  GURL url_ip("http://1.2.3.4/weee");
541  {
542    scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
543    EXPECT_TRUE(cm->SetCookie(url_ip, kValidCookieLine));
544    EXPECT_EQ("A=B", cm->GetCookies(url_ip));
545  }
546
547  {  // IP addresses should not be able to set domain cookies.
548    scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
549    EXPECT_FALSE(cm->SetCookie(url_ip, "b=2; domain=.1.2.3.4"));
550    EXPECT_FALSE(cm->SetCookie(url_ip, "c=3; domain=.3.4"));
551    EXPECT_EQ("", cm->GetCookies(url_ip));
552    // It should be allowed to set a cookie if domain= matches the IP address
553    // exactly.  This matches IE/Firefox, even though it seems a bit wrong.
554    EXPECT_FALSE(cm->SetCookie(url_ip, "b=2; domain=1.2.3.3"));
555    EXPECT_EQ("", cm->GetCookies(url_ip));
556    EXPECT_TRUE(cm->SetCookie(url_ip, "b=2; domain=1.2.3.4"));
557    EXPECT_EQ("b=2", cm->GetCookies(url_ip));
558  }
559}
560
561// Test host cookies, and setting of cookies on TLD.
562TEST(CookieMonsterTest, TestNonDottedAndTLD) {
563  {
564    scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
565    GURL url("http://com/");
566    // Allow setting on "com", (but only as a host cookie).
567    EXPECT_TRUE(cm->SetCookie(url, "a=1"));
568    EXPECT_FALSE(cm->SetCookie(url, "b=2; domain=.com"));
569    EXPECT_FALSE(cm->SetCookie(url, "c=3; domain=com"));
570    EXPECT_EQ("a=1", cm->GetCookies(url));
571    // Make sure it doesn't show up for a normal .com, it should be a host
572    // not a domain cookie.
573    EXPECT_EQ("", cm->GetCookies(GURL("http://hopefully-no-cookies.com/")));
574    EXPECT_EQ("", cm->GetCookies(GURL("http://.com/")));
575  }
576
577  {  // http://com. should be treated the same as http://com.
578    scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
579    GURL url("http://com./index.html");
580    EXPECT_TRUE(cm->SetCookie(url, "a=1"));
581    EXPECT_EQ("a=1", cm->GetCookies(url));
582    EXPECT_EQ("", cm->GetCookies(GURL("http://hopefully-no-cookies.com./")));
583  }
584
585  {  // Should not be able to set host cookie from a subdomain.
586    scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
587    GURL url("http://a.b");
588    EXPECT_FALSE(cm->SetCookie(url, "a=1; domain=.b"));
589    EXPECT_FALSE(cm->SetCookie(url, "b=2; domain=b"));
590    EXPECT_EQ("", cm->GetCookies(url));
591  }
592
593  {  // Same test as above, but explicitly on a known TLD (com).
594    scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
595    GURL url("http://google.com");
596    EXPECT_FALSE(cm->SetCookie(url, "a=1; domain=.com"));
597    EXPECT_FALSE(cm->SetCookie(url, "b=2; domain=com"));
598    EXPECT_EQ("", cm->GetCookies(url));
599  }
600
601  {  // Make sure can't set cookie on TLD which is dotted.
602    scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
603    GURL url("http://google.co.uk");
604    EXPECT_FALSE(cm->SetCookie(url, "a=1; domain=.co.uk"));
605    EXPECT_FALSE(cm->SetCookie(url, "b=2; domain=.uk"));
606    EXPECT_EQ("", cm->GetCookies(url));
607    EXPECT_EQ("", cm->GetCookies(GURL("http://something-else.co.uk")));
608    EXPECT_EQ("", cm->GetCookies(GURL("http://something-else.uk")));
609  }
610
611  {  // Intranet URLs should only be able to set host cookies.
612    scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
613    GURL url("http://b");
614    EXPECT_TRUE(cm->SetCookie(url, "a=1"));
615    EXPECT_FALSE(cm->SetCookie(url, "b=2; domain=.b"));
616    EXPECT_FALSE(cm->SetCookie(url, "c=3; domain=b"));
617    EXPECT_EQ("a=1", cm->GetCookies(url));
618  }
619}
620
621// Test reading/writing cookies when the domain ends with a period,
622// as in "www.google.com."
623TEST(CookieMonsterTest, TestHostEndsWithDot) {
624  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
625  GURL url("http://www.google.com");
626  GURL url_with_dot("http://www.google.com.");
627  EXPECT_TRUE(cm->SetCookie(url, "a=1"));
628  EXPECT_EQ("a=1", cm->GetCookies(url));
629
630  // Do not share cookie space with the dot version of domain.
631  // Note: this is not what FireFox does, but it _is_ what IE+Safari do.
632  EXPECT_FALSE(cm->SetCookie(url, "b=2; domain=.www.google.com."));
633  EXPECT_EQ("a=1", cm->GetCookies(url));
634
635  EXPECT_TRUE(cm->SetCookie(url_with_dot, "b=2; domain=.google.com."));
636  EXPECT_EQ("b=2", cm->GetCookies(url_with_dot));
637
638  // Make sure there weren't any side effects.
639  EXPECT_EQ(cm->GetCookies(GURL("http://hopefully-no-cookies.com/")), "");
640  EXPECT_EQ("", cm->GetCookies(GURL("http://.com/")));
641}
642
643TEST(CookieMonsterTest, InvalidScheme) {
644  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
645  EXPECT_FALSE(cm->SetCookie(GURL(kUrlFtp), kValidCookieLine));
646}
647
648TEST(CookieMonsterTest, InvalidScheme_Read) {
649  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
650  EXPECT_TRUE(cm->SetCookie(GURL(kUrlGoogle), kValidDomainCookieLine));
651  EXPECT_EQ("", cm->GetCookies(GURL(kUrlFtp)));
652}
653
654TEST(CookieMonsterTest, PathTest) {
655  std::string url("http://www.google.izzle");
656  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
657  EXPECT_TRUE(cm->SetCookie(GURL(url), "A=B; path=/wee"));
658  EXPECT_EQ("A=B", cm->GetCookies(GURL(url + "/wee")));
659  EXPECT_EQ("A=B", cm->GetCookies(GURL(url + "/wee/")));
660  EXPECT_EQ("A=B", cm->GetCookies(GURL(url + "/wee/war")));
661  EXPECT_EQ("A=B", cm->GetCookies(GURL(url + "/wee/war/more/more")));
662  EXPECT_EQ("", cm->GetCookies(GURL(url + "/weehee")));
663  EXPECT_EQ("", cm->GetCookies(GURL(url + "/")));
664
665  // If we add a 0 length path, it should default to /
666  EXPECT_TRUE(cm->SetCookie(GURL(url), "A=C; path="));
667  EXPECT_EQ("A=B; A=C", cm->GetCookies(GURL(url + "/wee")));
668  EXPECT_EQ("A=C", cm->GetCookies(GURL(url + "/")));
669}
670
671TEST(CookieMonsterTest, HttpOnlyTest) {
672  GURL url_google(kUrlGoogle);
673  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
674  CookieOptions options;
675  options.set_include_httponly();
676
677  // Create a httponly cookie.
678  EXPECT_TRUE(cm->SetCookieWithOptions(url_google, "A=B; httponly", options));
679
680  // Check httponly read protection.
681  EXPECT_EQ("", cm->GetCookies(url_google));
682  EXPECT_EQ("A=B", cm->GetCookiesWithOptions(url_google, options));
683
684  // Check httponly overwrite protection.
685  EXPECT_FALSE(cm->SetCookie(url_google, "A=C"));
686  EXPECT_EQ("", cm->GetCookies(url_google));
687  EXPECT_EQ("A=B", cm->GetCookiesWithOptions(url_google, options));
688  EXPECT_TRUE(cm->SetCookieWithOptions(url_google, "A=C", options));
689  EXPECT_EQ("A=C", cm->GetCookies(url_google));
690
691  // Check httponly create protection.
692  EXPECT_FALSE(cm->SetCookie(url_google, "B=A; httponly"));
693  EXPECT_EQ("A=C", cm->GetCookiesWithOptions(url_google, options));
694  EXPECT_TRUE(cm->SetCookieWithOptions(url_google, "B=A; httponly", options));
695  EXPECT_EQ("A=C; B=A", cm->GetCookiesWithOptions(url_google, options));
696  EXPECT_EQ("A=C", cm->GetCookies(url_google));
697}
698
699namespace {
700
701struct CookieDateParsingCase {
702  const char* str;
703  const bool valid;
704  const time_t epoch;
705};
706
707struct DomainIsHostOnlyCase {
708  const char* str;
709  const bool is_host_only;
710};
711
712}  // namespace
713
714TEST(CookieMonsterTest, TestCookieDateParsing) {
715  const CookieDateParsingCase tests[] = {
716    { "Sat, 15-Apr-17 21:01:22 GMT",           true, 1492290082 },
717    { "Thu, 19-Apr-2007 16:00:00 GMT",         true, 1176998400 },
718    { "Wed, 25 Apr 2007 21:02:13 GMT",         true, 1177534933 },
719    { "Thu, 19/Apr\\2007 16:00:00 GMT",        true, 1176998400 },
720    { "Fri, 1 Jan 2010 01:01:50 GMT",          true, 1262307710 },
721    { "Wednesday, 1-Jan-2003 00:00:00 GMT",    true, 1041379200 },
722    { ", 1-Jan-2003 00:00:00 GMT",             true, 1041379200 },
723    { " 1-Jan-2003 00:00:00 GMT",              true, 1041379200 },
724    { "1-Jan-2003 00:00:00 GMT",               true, 1041379200 },
725    { "Wed,18-Apr-07 22:50:12 GMT",            true, 1176936612 },
726    { "WillyWonka  , 18-Apr-07 22:50:12 GMT",  true, 1176936612 },
727    { "WillyWonka  , 18-Apr-07 22:50:12",      true, 1176936612 },
728    { "WillyWonka  ,  18-apr-07   22:50:12",   true, 1176936612 },
729    { "Mon, 18-Apr-1977 22:50:13 GMT",         true, 230251813 },
730    { "Mon, 18-Apr-77 22:50:13 GMT",           true, 230251813 },
731    // If the cookie came in with the expiration quoted (which in terms of
732    // the RFC you shouldn't do), we will get string quoted.  Bug 1261605.
733    { "\"Sat, 15-Apr-17\\\"21:01:22\\\"GMT\"", true, 1492290082 },
734    // Test with full month names and partial names.
735    { "Partyday, 18- April-07 22:50:12",       true, 1176936612 },
736    { "Partyday, 18 - Apri-07 22:50:12",       true, 1176936612 },
737    { "Wednes, 1-Januar-2003 00:00:00 GMT",    true, 1041379200 },
738    // Test that we always take GMT even with other time zones or bogus
739    // values.  The RFC says everything should be GMT, and in the worst case
740    // we are 24 hours off because of zone issues.
741    { "Sat, 15-Apr-17 21:01:22",               true, 1492290082 },
742    { "Sat, 15-Apr-17 21:01:22 GMT-2",         true, 1492290082 },
743    { "Sat, 15-Apr-17 21:01:22 GMT BLAH",      true, 1492290082 },
744    { "Sat, 15-Apr-17 21:01:22 GMT-0400",      true, 1492290082 },
745    { "Sat, 15-Apr-17 21:01:22 GMT-0400 (EDT)",true, 1492290082 },
746    { "Sat, 15-Apr-17 21:01:22 DST",           true, 1492290082 },
747    { "Sat, 15-Apr-17 21:01:22 -0400",         true, 1492290082 },
748    { "Sat, 15-Apr-17 21:01:22 (hello there)", true, 1492290082 },
749    // Test that if we encounter multiple : fields, that we take the first
750    // that correctly parses.
751    { "Sat, 15-Apr-17 21:01:22 11:22:33",      true, 1492290082 },
752    { "Sat, 15-Apr-17 ::00 21:01:22",          true, 1492290082 },
753    { "Sat, 15-Apr-17 boink:z 21:01:22",       true, 1492290082 },
754    // We take the first, which in this case is invalid.
755    { "Sat, 15-Apr-17 91:22:33 21:01:22",      false, 0 },
756    // amazon.com formats their cookie expiration like this.
757    { "Thu Apr 18 22:50:12 2007 GMT",          true, 1176936612 },
758    // Test that hh:mm:ss can occur anywhere.
759    { "22:50:12 Thu Apr 18 2007 GMT",          true, 1176936612 },
760    { "Thu 22:50:12 Apr 18 2007 GMT",          true, 1176936612 },
761    { "Thu Apr 22:50:12 18 2007 GMT",          true, 1176936612 },
762    { "Thu Apr 18 22:50:12 2007 GMT",          true, 1176936612 },
763    { "Thu Apr 18 2007 22:50:12 GMT",          true, 1176936612 },
764    { "Thu Apr 18 2007 GMT 22:50:12",          true, 1176936612 },
765    // Test that the day and year can be anywhere if they are unambigious.
766    { "Sat, 15-Apr-17 21:01:22 GMT",           true, 1492290082 },
767    { "15-Sat, Apr-17 21:01:22 GMT",           true, 1492290082 },
768    { "15-Sat, Apr 21:01:22 GMT 17",           true, 1492290082 },
769    { "15-Sat, Apr 21:01:22 GMT 2017",         true, 1492290082 },
770    { "15 Apr 21:01:22 2017",                  true, 1492290082 },
771    { "15 17 Apr 21:01:22",                    true, 1492290082 },
772    { "Apr 15 17 21:01:22",                    true, 1492290082 },
773    { "Apr 15 21:01:22 17",                    true, 1492290082 },
774    { "2017 April 15 21:01:22",                true, 1492290082 },
775    { "15 April 2017 21:01:22",                true, 1492290082 },
776    // Some invalid dates
777    { "98 April 17 21:01:22",                    false, 0 },
778    { "Thu, 012-Aug-2008 20:49:07 GMT",          false, 0 },
779    { "Thu, 12-Aug-31841 20:49:07 GMT",          false, 0 },
780    { "Thu, 12-Aug-9999999999 20:49:07 GMT",     false, 0 },
781    { "Thu, 999999999999-Aug-2007 20:49:07 GMT", false, 0 },
782    { "Thu, 12-Aug-2007 20:61:99999999999 GMT",  false, 0 },
783    { "IAintNoDateFool",                         false, 0 },
784  };
785
786  Time parsed_time;
787  for (size_t i = 0; i < arraysize(tests); ++i) {
788    parsed_time = CookieMonster::ParseCookieTime(tests[i].str);
789    if (!tests[i].valid) {
790      EXPECT_FALSE(!parsed_time.is_null()) << tests[i].str;
791      continue;
792    }
793    EXPECT_TRUE(!parsed_time.is_null()) << tests[i].str;
794    EXPECT_EQ(tests[i].epoch, parsed_time.ToTimeT()) << tests[i].str;
795  }
796}
797
798TEST(CookieMonsterTest, TestDomainIsHostOnly) {
799  const DomainIsHostOnlyCase tests[] = {
800    { "",               true },
801    { "www.google.com", true },
802    { ".google.com",    false }
803  };
804
805  for (size_t i = 0; i < arraysize(tests); ++i) {
806    EXPECT_EQ(tests[i].is_host_only,
807              CookieMonster::DomainIsHostOnly(tests[i].str));
808  }
809}
810
811TEST(CookieMonsterTest, TestCookieDeletion) {
812  GURL url_google(kUrlGoogle);
813  scoped_refptr<MockPersistentCookieStore> store(
814      new MockPersistentCookieStore);
815  scoped_refptr<CookieMonster> cm(new CookieMonster(store, NULL));
816
817  // Create a session cookie.
818  EXPECT_TRUE(cm->SetCookie(url_google, kValidCookieLine));
819  EXPECT_EQ("A=B", cm->GetCookies(url_google));
820  // Delete it via Max-Age.
821  EXPECT_TRUE(cm->SetCookie(url_google,
822                           std::string(kValidCookieLine) + "; max-age=0"));
823  EXPECT_EQ("", cm->GetCookies(url_google));
824
825  // Create a session cookie.
826  EXPECT_TRUE(cm->SetCookie(url_google, kValidCookieLine));
827  EXPECT_EQ("A=B", cm->GetCookies(url_google));
828  // Delete it via Expires.
829  EXPECT_TRUE(cm->SetCookie(url_google,
830                           std::string(kValidCookieLine) +
831                           "; expires=Mon, 18-Apr-1977 22:50:13 GMT"));
832  EXPECT_EQ("", cm->GetCookies(url_google));
833
834  // Create a persistent cookie.
835  EXPECT_TRUE(cm->SetCookie(url_google,
836                           std::string(kValidCookieLine) +
837                           "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
838  ASSERT_EQ(1u, store->commands().size());
839  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
840
841  EXPECT_EQ("A=B", cm->GetCookies(url_google));
842  // Delete it via Max-Age.
843  EXPECT_TRUE(cm->SetCookie(url_google,
844                           std::string(kValidCookieLine) + "; max-age=0"));
845  ASSERT_EQ(2u, store->commands().size());
846  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
847  EXPECT_EQ("", cm->GetCookies(url_google));
848
849  // Create a persistent cookie.
850  EXPECT_TRUE(cm->SetCookie(url_google,
851                           std::string(kValidCookieLine) +
852                           "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
853  ASSERT_EQ(3u, store->commands().size());
854  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type);
855  EXPECT_EQ("A=B", cm->GetCookies(url_google));
856  // Delete it via Expires.
857  EXPECT_TRUE(cm->SetCookie(url_google,
858                           std::string(kValidCookieLine) +
859                           "; expires=Mon, 18-Apr-1977 22:50:13 GMT"));
860  ASSERT_EQ(4u, store->commands().size());
861  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type);
862  EXPECT_EQ("", cm->GetCookies(url_google));
863
864  // Create a persistent cookie.
865  EXPECT_TRUE(cm->SetCookie(url_google,
866                           std::string(kValidCookieLine) +
867                           "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
868  ASSERT_EQ(5u, store->commands().size());
869  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[4].type);
870  EXPECT_EQ("A=B", cm->GetCookies(url_google));
871  // Delete it via Expires, with a unix epoch of 0.
872  EXPECT_TRUE(cm->SetCookie(url_google,
873                           std::string(kValidCookieLine) +
874                           "; expires=Thu, 1-Jan-1970 00:00:00 GMT"));
875  ASSERT_EQ(6u, store->commands().size());
876  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[5].type);
877  EXPECT_EQ("", cm->GetCookies(url_google));
878}
879
880TEST(CookieMonsterTest, TestCookieDeleteAll) {
881  GURL url_google(kUrlGoogle);
882  scoped_refptr<MockPersistentCookieStore> store(
883      new MockPersistentCookieStore);
884  scoped_refptr<CookieMonster> cm(new CookieMonster(store, NULL));
885  CookieOptions options;
886  options.set_include_httponly();
887
888  EXPECT_TRUE(cm->SetCookie(url_google, kValidCookieLine));
889  EXPECT_EQ("A=B", cm->GetCookies(url_google));
890
891  EXPECT_TRUE(cm->SetCookieWithOptions(url_google, "C=D; httponly", options));
892  EXPECT_EQ("A=B; C=D", cm->GetCookiesWithOptions(url_google, options));
893
894  EXPECT_EQ(2, cm->DeleteAll(false));
895  EXPECT_EQ("", cm->GetCookiesWithOptions(url_google, options));
896
897  EXPECT_EQ(0u, store->commands().size());
898
899  // Create a persistent cookie.
900  EXPECT_TRUE(cm->SetCookie(url_google,
901                            std::string(kValidCookieLine) +
902                            "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
903  ASSERT_EQ(1u, store->commands().size());
904  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
905
906  EXPECT_EQ(1, cm->DeleteAll(true));  // sync_to_store = true.
907  ASSERT_EQ(2u, store->commands().size());
908  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
909
910  EXPECT_EQ("", cm->GetCookiesWithOptions(url_google, options));
911}
912
913TEST(CookieMonsterTest, TestCookieDeleteAllCreatedAfterTimestamp) {
914  GURL url_google(kUrlGoogle);
915  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
916  Time now = Time::Now();
917
918  // Nothing has been added so nothing should be deleted.
919  EXPECT_EQ(0, cm->DeleteAllCreatedAfter(now - TimeDelta::FromDays(99), false));
920
921  // Create 3 cookies with creation date of today, yesterday and the day before.
922  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-0=Now", now));
923  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-1=Yesterday",
924                                           now - TimeDelta::FromDays(1)));
925  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-2=DayBefore",
926                                           now - TimeDelta::FromDays(2)));
927
928  // Try to delete everything from now onwards.
929  EXPECT_EQ(1, cm->DeleteAllCreatedAfter(now, false));
930  // Now delete the one cookie created in the last day.
931  EXPECT_EQ(1, cm->DeleteAllCreatedAfter(now - TimeDelta::FromDays(1), false));
932  // Now effectively delete all cookies just created (1 is remaining).
933  EXPECT_EQ(1, cm->DeleteAllCreatedAfter(now - TimeDelta::FromDays(99), false));
934
935  // Make sure everything is gone.
936  EXPECT_EQ(0, cm->DeleteAllCreatedAfter(Time(), false));
937  // Really make sure everything is gone.
938  EXPECT_EQ(0, cm->DeleteAll(false));
939}
940
941TEST(CookieMonsterTest, TestCookieDeleteAllCreatedBetweenTimestamps) {
942  GURL url_google(kUrlGoogle);
943  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
944  Time now = Time::Now();
945
946  // Nothing has been added so nothing should be deleted.
947  EXPECT_EQ(0, cm->DeleteAllCreatedAfter(now - TimeDelta::FromDays(99), false));
948
949  // Create 3 cookies with creation date of today, yesterday and the day before.
950  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-0=Now", now));
951  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-1=Yesterday",
952                                           now - TimeDelta::FromDays(1)));
953  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-2=DayBefore",
954                                           now - TimeDelta::FromDays(2)));
955  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-3=ThreeDays",
956                                           now - TimeDelta::FromDays(3)));
957  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-7=LastWeek",
958                                           now - TimeDelta::FromDays(7)));
959
960  // Try to delete threedays and the daybefore.
961  EXPECT_EQ(2, cm->DeleteAllCreatedBetween(now - TimeDelta::FromDays(3),
962                                          now - TimeDelta::FromDays(1),
963                                          false));
964
965  // Try to delete yesterday, also make sure that delete_end is not
966  // inclusive.
967  EXPECT_EQ(1, cm->DeleteAllCreatedBetween(now - TimeDelta::FromDays(2),
968                                          now,
969                                          false));
970
971  // Make sure the delete_begin is inclusive.
972  EXPECT_EQ(1, cm->DeleteAllCreatedBetween(now - TimeDelta::FromDays(7),
973                                          now,
974                                          false));
975
976  // Delete the last (now) item.
977  EXPECT_EQ(1, cm->DeleteAllCreatedAfter(Time(), false));
978
979  // Really make sure everything is gone.
980  EXPECT_EQ(0, cm->DeleteAll(false));
981}
982
983TEST(CookieMonsterTest, TestSecure) {
984  GURL url_google(kUrlGoogle);
985  GURL url_google_secure(kUrlGoogleSecure);
986  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
987
988  EXPECT_TRUE(cm->SetCookie(url_google, "A=B"));
989  EXPECT_EQ("A=B", cm->GetCookies(url_google));
990  EXPECT_EQ("A=B", cm->GetCookies(url_google_secure));
991
992  EXPECT_TRUE(cm->SetCookie(url_google_secure, "A=B; secure"));
993  // The secure should overwrite the non-secure.
994  EXPECT_EQ("", cm->GetCookies(url_google));
995  EXPECT_EQ("A=B", cm->GetCookies(url_google_secure));
996
997  EXPECT_TRUE(cm->SetCookie(url_google_secure, "D=E; secure"));
998  EXPECT_EQ("", cm->GetCookies(url_google));
999  EXPECT_EQ("A=B; D=E", cm->GetCookies(url_google_secure));
1000
1001  EXPECT_TRUE(cm->SetCookie(url_google_secure, "A=B"));
1002  // The non-secure should overwrite the secure.
1003  EXPECT_EQ("A=B", cm->GetCookies(url_google));
1004  EXPECT_EQ("D=E; A=B", cm->GetCookies(url_google_secure));
1005}
1006
1007static Time GetFirstCookieAccessDate(CookieMonster* cm) {
1008  const CookieList all_cookies(cm->GetAllCookies());
1009  return all_cookies.front().LastAccessDate();
1010}
1011
1012static const int kLastAccessThresholdMilliseconds = 200;
1013
1014TEST(CookieMonsterTest, TestLastAccess) {
1015  GURL url_google(kUrlGoogle);
1016  scoped_refptr<CookieMonster> cm(
1017      new CookieMonster(NULL, NULL, kLastAccessThresholdMilliseconds));
1018
1019  EXPECT_TRUE(cm->SetCookie(url_google, "A=B"));
1020  const Time last_access_date(GetFirstCookieAccessDate(cm));
1021
1022  // Reading the cookie again immediately shouldn't update the access date,
1023  // since we're inside the threshold.
1024  EXPECT_EQ("A=B", cm->GetCookies(url_google));
1025  EXPECT_TRUE(last_access_date == GetFirstCookieAccessDate(cm));
1026
1027  // Reading after a short wait should update the access date.
1028  base::PlatformThread::Sleep(kLastAccessThresholdMilliseconds + 20);
1029  EXPECT_EQ("A=B", cm->GetCookies(url_google));
1030  EXPECT_FALSE(last_access_date == GetFirstCookieAccessDate(cm));
1031}
1032
1033static int CountInString(const std::string& str, char c) {
1034  return std::count(str.begin(), str.end(), c);
1035}
1036
1037static void TestHostGarbageCollectHelper(
1038    int domain_max_cookies,
1039    int domain_purge_cookies,
1040    CookieMonster::ExpiryAndKeyScheme key_scheme) {
1041  GURL url_google(kUrlGoogle);
1042  const int more_than_enough_cookies =
1043      (domain_max_cookies + domain_purge_cookies) * 2;
1044  // Add a bunch of cookies on a single host, should purge them.
1045  {
1046    scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1047    cm->SetExpiryAndKeyScheme(key_scheme);
1048    for (int i = 0; i < more_than_enough_cookies; ++i) {
1049      std::string cookie = base::StringPrintf("a%03d=b", i);
1050      EXPECT_TRUE(cm->SetCookie(url_google, cookie));
1051      std::string cookies = cm->GetCookies(url_google);
1052      // Make sure we find it in the cookies.
1053      EXPECT_NE(cookies.find(cookie), std::string::npos);
1054      // Count the number of cookies.
1055      EXPECT_LE(CountInString(cookies, '='), domain_max_cookies);
1056    }
1057  }
1058
1059  // Add a bunch of cookies on multiple hosts within a single eTLD.
1060  // Should keep at least kDomainMaxCookies - kDomainPurgeCookies
1061  // between them.  If we are using the effective domain keying system
1062  // (EKS_KEEP_RECENT_AND_PURGE_ETLDP1) we shouldn't go above
1063  // kDomainMaxCookies for both together.  If we're using the domain
1064  // keying system (EKS_DISCARD_RECENT_AND_PURGE_DOMAIN), each
1065  // individual domain shouldn't go above kDomainMaxCookies.
1066  GURL url_google_specific(kUrlGoogleSpecific);
1067  {
1068    scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1069    cm->SetExpiryAndKeyScheme(key_scheme);
1070    for (int i = 0; i < more_than_enough_cookies; ++i) {
1071      std::string cookie_general = base::StringPrintf("a%03d=b", i);
1072      EXPECT_TRUE(cm->SetCookie(url_google, cookie_general));
1073      std::string cookie_specific = base::StringPrintf("c%03d=b", i);
1074      EXPECT_TRUE(cm->SetCookie(url_google_specific, cookie_specific));
1075      std::string cookies_general = cm->GetCookies(url_google);
1076      EXPECT_NE(cookies_general.find(cookie_general), std::string::npos);
1077      std::string cookies_specific = cm->GetCookies(url_google_specific);
1078      EXPECT_NE(cookies_specific.find(cookie_specific), std::string::npos);
1079      if (key_scheme == CookieMonster::EKS_KEEP_RECENT_AND_PURGE_ETLDP1) {
1080        EXPECT_LE((CountInString(cookies_general, '=') +
1081                   CountInString(cookies_specific, '=')),
1082                  domain_max_cookies);
1083      } else {
1084        EXPECT_LE(CountInString(cookies_general, '='), domain_max_cookies);
1085        EXPECT_LE(CountInString(cookies_specific, '='), domain_max_cookies);
1086      }
1087    }
1088    // After all this, there should be at least
1089    // kDomainMaxCookies - kDomainPurgeCookies for both URLs.
1090    std::string cookies_general = cm->GetCookies(url_google);
1091    std::string cookies_specific = cm->GetCookies(url_google_specific);
1092    if (key_scheme == CookieMonster::EKS_KEEP_RECENT_AND_PURGE_ETLDP1) {
1093      int total_cookies = (CountInString(cookies_general, '=') +
1094                           CountInString(cookies_specific, '='));
1095      EXPECT_GE(total_cookies,
1096                domain_max_cookies - domain_purge_cookies);
1097      EXPECT_LE(total_cookies, domain_max_cookies);
1098    } else {
1099      int general_cookies = CountInString(cookies_general, '=');
1100      int specific_cookies = CountInString(cookies_specific, '=');
1101      EXPECT_GE(general_cookies,
1102                domain_max_cookies - domain_purge_cookies);
1103      EXPECT_LE(general_cookies, domain_max_cookies);
1104      EXPECT_GE(specific_cookies,
1105                domain_max_cookies - domain_purge_cookies);
1106      EXPECT_LE(specific_cookies, domain_max_cookies);
1107    }
1108  }
1109}
1110
1111TEST(CookieMonsterTest, TestHostGarbageCollection) {
1112  TestHostGarbageCollectHelper(
1113      CookieMonster::kDomainMaxCookies, CookieMonster::kDomainPurgeCookies,
1114      CookieMonster::EKS_KEEP_RECENT_AND_PURGE_ETLDP1);
1115  TestHostGarbageCollectHelper(
1116      CookieMonster::kDomainMaxCookies, CookieMonster::kDomainPurgeCookies,
1117      CookieMonster::EKS_DISCARD_RECENT_AND_PURGE_DOMAIN);
1118}
1119
1120// Formerly NetUtilTest.CookieTest back when we used wininet's cookie handling.
1121TEST(CookieMonsterTest, NetUtilCookieTest) {
1122  const GURL test_url("http://mojo.jojo.google.izzle/");
1123
1124  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1125
1126  EXPECT_TRUE(cm->SetCookie(test_url, "foo=bar"));
1127  std::string value = cm->GetCookies(test_url);
1128  EXPECT_EQ("foo=bar", value);
1129
1130  // test that we can retrieve all cookies:
1131  EXPECT_TRUE(cm->SetCookie(test_url, "x=1"));
1132  EXPECT_TRUE(cm->SetCookie(test_url, "y=2"));
1133
1134  std::string result = cm->GetCookies(test_url);
1135  EXPECT_FALSE(result.empty());
1136  EXPECT_NE(result.find("x=1"), std::string::npos) << result;
1137  EXPECT_NE(result.find("y=2"), std::string::npos) << result;
1138}
1139
1140static bool FindAndDeleteCookie(CookieMonster* cm,
1141                                const std::string& domain,
1142                                const std::string& name) {
1143  CookieList cookies = cm->GetAllCookies();
1144  for (CookieList::iterator it = cookies.begin();
1145       it != cookies.end(); ++it)
1146    if (it->Domain() == domain && it->Name() == name)
1147      return cm->DeleteCanonicalCookie(*it);
1148  return false;
1149}
1150
1151TEST(CookieMonsterTest, TestDeleteSingleCookie) {
1152  GURL url_google(kUrlGoogle);
1153
1154  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1155
1156  EXPECT_TRUE(cm->SetCookie(url_google, "A=B"));
1157  EXPECT_TRUE(cm->SetCookie(url_google, "C=D"));
1158  EXPECT_TRUE(cm->SetCookie(url_google, "E=F"));
1159  EXPECT_EQ("A=B; C=D; E=F", cm->GetCookies(url_google));
1160
1161  EXPECT_TRUE(FindAndDeleteCookie(cm, url_google.host(), "C"));
1162  EXPECT_EQ("A=B; E=F", cm->GetCookies(url_google));
1163
1164  EXPECT_FALSE(FindAndDeleteCookie(cm, "random.host", "E"));
1165  EXPECT_EQ("A=B; E=F", cm->GetCookies(url_google));
1166}
1167
1168TEST(CookieMonsterTest, SetCookieableSchemes) {
1169  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1170  scoped_refptr<CookieMonster> cm_foo(new CookieMonster(NULL, NULL));
1171
1172  // Only cm_foo should allow foo:// cookies.
1173  const char* kSchemes[] = {"foo"};
1174  cm_foo->SetCookieableSchemes(kSchemes, 1);
1175
1176  GURL foo_url("foo://host/path");
1177  GURL http_url("http://host/path");
1178
1179  EXPECT_TRUE(cm->SetCookie(http_url, "x=1"));
1180  EXPECT_FALSE(cm->SetCookie(foo_url, "x=1"));
1181  EXPECT_TRUE(cm_foo->SetCookie(foo_url, "x=1"));
1182  EXPECT_FALSE(cm_foo->SetCookie(http_url, "x=1"));
1183}
1184
1185TEST(CookieMonsterTest, GetAllCookiesForURL) {
1186  GURL url_google(kUrlGoogle);
1187  GURL url_google_secure(kUrlGoogleSecure);
1188
1189  scoped_refptr<CookieMonster> cm(
1190      new CookieMonster(NULL, NULL, kLastAccessThresholdMilliseconds));
1191
1192  // Create an httponly cookie.
1193  CookieOptions options;
1194  options.set_include_httponly();
1195
1196  EXPECT_TRUE(cm->SetCookieWithOptions(url_google, "A=B; httponly", options));
1197  EXPECT_TRUE(cm->SetCookieWithOptions(url_google,
1198                                       "C=D; domain=.google.izzle",
1199                                       options));
1200  EXPECT_TRUE(cm->SetCookieWithOptions(url_google_secure,
1201                                       "E=F; domain=.google.izzle; secure",
1202                                       options));
1203
1204  const Time last_access_date(GetFirstCookieAccessDate(cm));
1205
1206  base::PlatformThread::Sleep(kLastAccessThresholdMilliseconds + 20);
1207
1208  // Check cookies for url.
1209  CookieList cookies = cm->GetAllCookiesForURL(url_google);
1210  CookieList::iterator it = cookies.begin();
1211
1212  ASSERT_TRUE(it != cookies.end());
1213  EXPECT_EQ("www.google.izzle", it->Domain());
1214  EXPECT_EQ("A", it->Name());
1215
1216  ASSERT_TRUE(++it != cookies.end());
1217  EXPECT_EQ(".google.izzle", it->Domain());
1218  EXPECT_EQ("C", it->Name());
1219
1220  ASSERT_TRUE(++it == cookies.end());
1221
1222  // Check cookies for url excluding http-only cookies.
1223  cookies =
1224      cm->GetAllCookiesForURLWithOptions(url_google, CookieOptions());
1225  it = cookies.begin();
1226
1227  ASSERT_TRUE(it != cookies.end());
1228  EXPECT_EQ(".google.izzle", it->Domain());
1229  EXPECT_EQ("C", it->Name());
1230
1231  ASSERT_TRUE(++it == cookies.end());
1232
1233  // Test secure cookies.
1234  cookies = cm->GetAllCookiesForURL(url_google_secure);
1235  it = cookies.begin();
1236
1237  ASSERT_TRUE(it != cookies.end());
1238  EXPECT_EQ("www.google.izzle", it->Domain());
1239  EXPECT_EQ("A", it->Name());
1240
1241  ASSERT_TRUE(++it != cookies.end());
1242  EXPECT_EQ(".google.izzle", it->Domain());
1243  EXPECT_EQ("C", it->Name());
1244
1245  ASSERT_TRUE(++it != cookies.end());
1246  EXPECT_EQ(".google.izzle", it->Domain());
1247  EXPECT_EQ("E", it->Name());
1248
1249  ASSERT_TRUE(++it == cookies.end());
1250
1251  // Reading after a short wait should not update the access date.
1252  EXPECT_TRUE(last_access_date == GetFirstCookieAccessDate(cm));
1253}
1254
1255TEST(CookieMonsterTest, GetAllCookiesForURLPathMatching) {
1256  GURL url_google(kUrlGoogle);
1257  GURL url_google_foo("http://www.google.izzle/foo");
1258  GURL url_google_bar("http://www.google.izzle/bar");
1259
1260  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1261  CookieOptions options;
1262
1263  EXPECT_TRUE(cm->SetCookieWithOptions(url_google_foo,
1264                                       "A=B; path=/foo;",
1265                                       options));
1266  EXPECT_TRUE(cm->SetCookieWithOptions(url_google_bar,
1267                                       "C=D; path=/bar;",
1268                                       options));
1269  EXPECT_TRUE(cm->SetCookieWithOptions(url_google,
1270                                       "E=F;",
1271                                       options));
1272
1273  CookieList cookies = cm->GetAllCookiesForURL(url_google_foo);
1274  CookieList::iterator it = cookies.begin();
1275
1276  ASSERT_TRUE(it != cookies.end());
1277  EXPECT_EQ("A", it->Name());
1278  EXPECT_EQ("/foo", it->Path());
1279
1280  ASSERT_TRUE(++it != cookies.end());
1281  EXPECT_EQ("E", it->Name());
1282  EXPECT_EQ("/", it->Path());
1283
1284  ASSERT_TRUE(++it == cookies.end());
1285
1286  cookies = cm->GetAllCookiesForURL(url_google_bar);
1287  it = cookies.begin();
1288
1289  ASSERT_TRUE(it != cookies.end());
1290  EXPECT_EQ("C", it->Name());
1291  EXPECT_EQ("/bar", it->Path());
1292
1293  ASSERT_TRUE(++it != cookies.end());
1294  EXPECT_EQ("E", it->Name());
1295  EXPECT_EQ("/", it->Path());
1296
1297  ASSERT_TRUE(++it == cookies.end());
1298}
1299
1300TEST(CookieMonsterTest, DeleteCookieByName) {
1301  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1302  GURL url_google(kUrlGoogle);
1303
1304  EXPECT_TRUE(cm->SetCookie(url_google, "A=A1; path=/"));
1305  EXPECT_TRUE(cm->SetCookie(url_google, "A=A2; path=/foo"));
1306  EXPECT_TRUE(cm->SetCookie(url_google, "A=A3; path=/bar"));
1307  EXPECT_TRUE(cm->SetCookie(url_google, "B=B1; path=/"));
1308  EXPECT_TRUE(cm->SetCookie(url_google, "B=B2; path=/foo"));
1309  EXPECT_TRUE(cm->SetCookie(url_google, "B=B3; path=/bar"));
1310
1311  cm->DeleteCookie(GURL(std::string(kUrlGoogle) + "/foo/bar"), "A");
1312
1313  CookieList cookies = cm->GetAllCookies();
1314  size_t expected_size = 4;
1315  EXPECT_EQ(expected_size, cookies.size());
1316  for (CookieList::iterator it = cookies.begin();
1317       it != cookies.end(); ++it) {
1318    EXPECT_NE("A1", it->Value());
1319    EXPECT_NE("A2", it->Value());
1320  }
1321}
1322
1323// Test that overwriting persistent cookies deletes the old one from the
1324// backing store.
1325TEST(CookieMonsterTest, OverwritePersistentCookie) {
1326  GURL url_google("http://www.google.com/");
1327  GURL url_chromium("http://chromium.org");
1328  scoped_refptr<MockPersistentCookieStore> store(
1329      new MockPersistentCookieStore);
1330  scoped_refptr<CookieMonster> cm(new CookieMonster(store, NULL));
1331
1332  // Insert a cookie "a" for path "/path1"
1333  EXPECT_TRUE(
1334      cm->SetCookie(url_google, "a=val1; path=/path1; "
1335                                "expires=Mon, 18-Apr-22 22:50:13 GMT"));
1336  ASSERT_EQ(1u, store->commands().size());
1337  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
1338
1339  // Insert a cookie "b" for path "/path1"
1340  EXPECT_TRUE(
1341      cm->SetCookie(url_google, "b=val1; path=/path1; "
1342                                "expires=Mon, 18-Apr-22 22:50:14 GMT"));
1343  ASSERT_EQ(2u, store->commands().size());
1344  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[1].type);
1345
1346  // Insert a cookie "b" for path "/path1", that is httponly. This should
1347  // overwrite the non-http-only version.
1348  CookieOptions allow_httponly;
1349  allow_httponly.set_include_httponly();
1350  EXPECT_TRUE(
1351    cm->SetCookieWithOptions(url_google,
1352                             "b=val2; path=/path1; httponly; "
1353                             "expires=Mon, 18-Apr-22 22:50:14 GMT",
1354                             allow_httponly));
1355  ASSERT_EQ(4u, store->commands().size());
1356  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[2].type);
1357  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[3].type);
1358
1359  // Insert a cookie "a" for path "/path1". This should overwrite.
1360  EXPECT_TRUE(cm->SetCookie(url_google,
1361                            "a=val33; path=/path1; "
1362                            "expires=Mon, 18-Apr-22 22:50:14 GMT"));
1363  ASSERT_EQ(6u, store->commands().size());
1364  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[4].type);
1365  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[5].type);
1366
1367  // Insert a cookie "a" for path "/path2". This should NOT overwrite
1368  // cookie "a", since the path is different.
1369  EXPECT_TRUE(cm->SetCookie(url_google,
1370                            "a=val9; path=/path2; "
1371                            "expires=Mon, 18-Apr-22 22:50:14 GMT"));
1372  ASSERT_EQ(7u, store->commands().size());
1373  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[6].type);
1374
1375  // Insert a cookie "a" for path "/path1", but this time for "chromium.org".
1376  // Although the name and path match, the hostnames do not, so shouldn't
1377  // overwrite.
1378  EXPECT_TRUE(cm->SetCookie(url_chromium,
1379                            "a=val99; path=/path1; "
1380                            "expires=Mon, 18-Apr-22 22:50:14 GMT"));
1381  ASSERT_EQ(8u, store->commands().size());
1382  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[7].type);
1383
1384  EXPECT_EQ("a=val33", cm->GetCookies(GURL("http://www.google.com/path1")));
1385  EXPECT_EQ("a=val9", cm->GetCookies(GURL("http://www.google.com/path2")));
1386  EXPECT_EQ("a=val99", cm->GetCookies(GURL("http://chromium.org/path1")));
1387}
1388
1389// Tests importing from a persistent cookie store that contains duplicate
1390// equivalent cookies. This situation should be handled by removing the
1391// duplicate cookie (both from the in-memory cache, and from the backing store).
1392//
1393// This is a regression test for: http://crbug.com/17855.
1394TEST(CookieMonsterTest, DontImportDuplicateCookies) {
1395  GURL url_google("http://www.google.com/");
1396
1397  scoped_refptr<MockPersistentCookieStore> store(
1398      new MockPersistentCookieStore);
1399
1400  // We will fill some initial cookies into the PersistentCookieStore,
1401  // to simulate a database with 4 duplicates.  Note that we need to
1402  // be careful not to have any duplicate creation times at all (as it's a
1403  // violation of a CookieMonster invariant) even if Time::Now() doesn't
1404  // move between calls.
1405  std::vector<CookieMonster::CanonicalCookie*> initial_cookies;
1406
1407  // Insert 4 cookies with name "X" on path "/", with varying creation
1408  // dates. We expect only the most recent one to be preserved following
1409  // the import.
1410
1411  AddCookieToList("www.google.com",
1412                  "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1413                  Time::Now() + TimeDelta::FromDays(3),
1414                  &initial_cookies);
1415
1416  AddCookieToList("www.google.com",
1417                  "X=2; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1418                  Time::Now() + TimeDelta::FromDays(1),
1419                  &initial_cookies);
1420
1421  // ===> This one is the WINNER (biggest creation time).  <====
1422  AddCookieToList("www.google.com",
1423                  "X=3; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1424                  Time::Now() + TimeDelta::FromDays(4),
1425                  &initial_cookies);
1426
1427  AddCookieToList("www.google.com",
1428                  "X=4; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1429                  Time::Now(),
1430                  &initial_cookies);
1431
1432  // Insert 2 cookies with name "X" on path "/2", with varying creation
1433  // dates. We expect only the most recent one to be preserved the import.
1434
1435  // ===> This one is the WINNER (biggest creation time).  <====
1436  AddCookieToList("www.google.com",
1437                  "X=a1; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
1438                  Time::Now() + TimeDelta::FromDays(9),
1439                  &initial_cookies);
1440
1441  AddCookieToList("www.google.com",
1442                  "X=a2; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
1443                  Time::Now() + TimeDelta::FromDays(2),
1444                  &initial_cookies);
1445
1446  // Insert 1 cookie with name "Y" on path "/".
1447  AddCookieToList("www.google.com",
1448                  "Y=a; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1449                  Time::Now() + TimeDelta::FromDays(10),
1450                  &initial_cookies);
1451
1452  // Inject our initial cookies into the mock PersistentCookieStore.
1453  store->SetLoadExpectation(true, initial_cookies);
1454
1455  scoped_refptr<CookieMonster> cm(new CookieMonster(store, NULL));
1456
1457  // Verify that duplicates were not imported for path "/".
1458  // (If this had failed, GetCookies() would have also returned X=1, X=2, X=4).
1459  EXPECT_EQ("X=3; Y=a", cm->GetCookies(GURL("http://www.google.com/")));
1460
1461  // Verify that same-named cookie on a different path ("/x2") didn't get
1462  // messed up.
1463  EXPECT_EQ("X=a1; X=3; Y=a",
1464            cm->GetCookies(GURL("http://www.google.com/2/x")));
1465
1466  // Verify that the PersistentCookieStore was told to kill its 4 duplicates.
1467  ASSERT_EQ(4u, store->commands().size());
1468  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[0].type);
1469  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
1470  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[2].type);
1471  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type);
1472}
1473
1474// Tests importing from a persistent cookie store that contains cookies
1475// with duplicate creation times.  This situation should be handled by
1476// dropping the cookies before insertion/visibility to user.
1477//
1478// This is a regression test for: http://crbug.com/43188.
1479TEST(CookieMonsterTest, DontImportDuplicateCreationTimes) {
1480  GURL url_google("http://www.google.com/");
1481
1482  scoped_refptr<MockPersistentCookieStore> store(
1483      new MockPersistentCookieStore);
1484
1485  Time now(Time::Now());
1486  Time earlier(now - TimeDelta::FromDays(1));
1487
1488  // Insert 8 cookies, four with the current time as creation times, and
1489  // four with the earlier time as creation times.  We should only get
1490  // two cookies remaining, but which two (other than that there should
1491  // be one from each set) will be random.
1492  std::vector<CookieMonster::CanonicalCookie*> initial_cookies;
1493  AddCookieToList("www.google.com", "X=1; path=/", now, &initial_cookies);
1494  AddCookieToList("www.google.com", "X=2; path=/", now, &initial_cookies);
1495  AddCookieToList("www.google.com", "X=3; path=/", now, &initial_cookies);
1496  AddCookieToList("www.google.com", "X=4; path=/", now, &initial_cookies);
1497
1498  AddCookieToList("www.google.com", "Y=1; path=/", earlier, &initial_cookies);
1499  AddCookieToList("www.google.com", "Y=2; path=/", earlier, &initial_cookies);
1500  AddCookieToList("www.google.com", "Y=3; path=/", earlier, &initial_cookies);
1501  AddCookieToList("www.google.com", "Y=4; path=/", earlier, &initial_cookies);
1502
1503  // Inject our initial cookies into the mock PersistentCookieStore.
1504  store->SetLoadExpectation(true, initial_cookies);
1505
1506  scoped_refptr<CookieMonster> cm(new CookieMonster(store, NULL));
1507
1508  CookieList list(cm->GetAllCookies());
1509  EXPECT_EQ(2U, list.size());
1510  // Confirm that we have one of each.
1511  std::string name1(list[0].Name());
1512  std::string name2(list[1].Name());
1513  EXPECT_TRUE(name1 == "X" || name2 == "X");
1514  EXPECT_TRUE(name1 == "Y" || name2 == "Y");
1515  EXPECT_NE(name1, name2);
1516}
1517
1518TEST(CookieMonsterTest, Delegate) {
1519  GURL url_google(kUrlGoogle);
1520
1521  scoped_refptr<MockPersistentCookieStore> store(
1522      new MockPersistentCookieStore);
1523  scoped_refptr<MockCookieMonsterDelegate> delegate(
1524      new MockCookieMonsterDelegate);
1525  scoped_refptr<CookieMonster> cm(new CookieMonster(store, delegate));
1526
1527  EXPECT_TRUE(cm->SetCookie(url_google, "A=B"));
1528  EXPECT_TRUE(cm->SetCookie(url_google, "C=D"));
1529  EXPECT_TRUE(cm->SetCookie(url_google, "E=F"));
1530  EXPECT_EQ("A=B; C=D; E=F", cm->GetCookies(url_google));
1531  ASSERT_EQ(3u, delegate->changes().size());
1532  EXPECT_FALSE(delegate->changes()[0].second);
1533  EXPECT_EQ(url_google.host(), delegate->changes()[0].first.Domain());
1534  EXPECT_EQ("A", delegate->changes()[0].first.Name());
1535  EXPECT_EQ("B", delegate->changes()[0].first.Value());
1536  EXPECT_EQ(url_google.host(), delegate->changes()[1].first.Domain());
1537  EXPECT_FALSE(delegate->changes()[1].second);
1538  EXPECT_EQ("C", delegate->changes()[1].first.Name());
1539  EXPECT_EQ("D", delegate->changes()[1].first.Value());
1540  EXPECT_EQ(url_google.host(), delegate->changes()[2].first.Domain());
1541  EXPECT_FALSE(delegate->changes()[2].second);
1542  EXPECT_EQ("E", delegate->changes()[2].first.Name());
1543  EXPECT_EQ("F", delegate->changes()[2].first.Value());
1544  delegate->reset();
1545
1546  EXPECT_TRUE(FindAndDeleteCookie(cm, url_google.host(), "C"));
1547  EXPECT_EQ("A=B; E=F", cm->GetCookies(url_google));
1548  ASSERT_EQ(1u, delegate->changes().size());
1549  EXPECT_EQ(url_google.host(), delegate->changes()[0].first.Domain());
1550  EXPECT_TRUE(delegate->changes()[0].second);
1551  EXPECT_EQ("C", delegate->changes()[0].first.Name());
1552  EXPECT_EQ("D", delegate->changes()[0].first.Value());
1553  delegate->reset();
1554
1555  EXPECT_FALSE(FindAndDeleteCookie(cm, "random.host", "E"));
1556  EXPECT_EQ("A=B; E=F", cm->GetCookies(url_google));
1557  EXPECT_EQ(0u, delegate->changes().size());
1558
1559  // Insert a cookie "a" for path "/path1"
1560  EXPECT_TRUE(
1561      cm->SetCookie(url_google, "a=val1; path=/path1; "
1562                                "expires=Mon, 18-Apr-22 22:50:13 GMT"));
1563  ASSERT_EQ(1u, store->commands().size());
1564  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
1565  ASSERT_EQ(1u, delegate->changes().size());
1566  EXPECT_FALSE(delegate->changes()[0].second);
1567  EXPECT_EQ(url_google.host(), delegate->changes()[0].first.Domain());
1568  EXPECT_EQ("a", delegate->changes()[0].first.Name());
1569  EXPECT_EQ("val1", delegate->changes()[0].first.Value());
1570  delegate->reset();
1571
1572  // Insert a cookie "a" for path "/path1", that is httponly. This should
1573  // overwrite the non-http-only version.
1574  CookieOptions allow_httponly;
1575  allow_httponly.set_include_httponly();
1576  EXPECT_TRUE(
1577    cm->SetCookieWithOptions(url_google,
1578                             "a=val2; path=/path1; httponly; "
1579                             "expires=Mon, 18-Apr-22 22:50:14 GMT",
1580                             allow_httponly));
1581  ASSERT_EQ(3u, store->commands().size());
1582  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
1583  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type);
1584  ASSERT_EQ(2u, delegate->changes().size());
1585  EXPECT_EQ(url_google.host(), delegate->changes()[0].first.Domain());
1586  EXPECT_TRUE(delegate->changes()[0].second);
1587  EXPECT_EQ("a", delegate->changes()[0].first.Name());
1588  EXPECT_EQ("val1", delegate->changes()[0].first.Value());
1589  EXPECT_EQ(url_google.host(), delegate->changes()[1].first.Domain());
1590  EXPECT_FALSE(delegate->changes()[1].second);
1591  EXPECT_EQ("a", delegate->changes()[1].first.Name());
1592  EXPECT_EQ("val2", delegate->changes()[1].first.Value());
1593  delegate->reset();
1594}
1595
1596TEST(CookieMonsterTest, SetCookieWithDetails) {
1597  GURL url_google(kUrlGoogle);
1598  GURL url_google_foo("http://www.google.izzle/foo");
1599  GURL url_google_bar("http://www.google.izzle/bar");
1600  GURL url_google_secure(kUrlGoogleSecure);
1601
1602  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1603
1604  EXPECT_TRUE(cm->SetCookieWithDetails(
1605      url_google_foo, "A", "B", std::string(), "/foo", base::Time(),
1606      false, false));
1607  EXPECT_TRUE(cm->SetCookieWithDetails(
1608      url_google_bar, "C", "D", "google.izzle", "/bar", base::Time(),
1609      false, true));
1610  EXPECT_TRUE(cm->SetCookieWithDetails(
1611      url_google, "E", "F", std::string(), std::string(), base::Time(),
1612      true, false));
1613
1614  // Test that malformed attributes fail to set the cookie.
1615  EXPECT_FALSE(cm->SetCookieWithDetails(
1616      url_google_foo, " A", "B", std::string(), "/foo", base::Time(),
1617      false, false));
1618  EXPECT_FALSE(cm->SetCookieWithDetails(
1619      url_google_foo, "A;", "B", std::string(), "/foo", base::Time(),
1620      false, false));
1621  EXPECT_FALSE(cm->SetCookieWithDetails(
1622      url_google_foo, "A=", "B", std::string(), "/foo", base::Time(),
1623      false, false));
1624  EXPECT_FALSE(cm->SetCookieWithDetails(
1625      url_google_foo, "A", "B", "google.ozzzzzzle", "foo", base::Time(),
1626      false, false));
1627  EXPECT_FALSE(cm->SetCookieWithDetails(
1628      url_google_foo, "A=", "B", std::string(), "foo", base::Time(),
1629      false, false));
1630
1631  CookieList cookies = cm->GetAllCookiesForURL(url_google_foo);
1632  CookieList::iterator it = cookies.begin();
1633
1634  ASSERT_TRUE(it != cookies.end());
1635  EXPECT_EQ("A", it->Name());
1636  EXPECT_EQ("B", it->Value());
1637  EXPECT_EQ("www.google.izzle", it->Domain());
1638  EXPECT_EQ("/foo", it->Path());
1639  EXPECT_FALSE(it->DoesExpire());
1640  EXPECT_FALSE(it->IsSecure());
1641  EXPECT_FALSE(it->IsHttpOnly());
1642
1643  ASSERT_TRUE(++it == cookies.end());
1644
1645  cookies = cm->GetAllCookiesForURL(url_google_bar);
1646  it = cookies.begin();
1647
1648  ASSERT_TRUE(it != cookies.end());
1649  EXPECT_EQ("C", it->Name());
1650  EXPECT_EQ("D", it->Value());
1651  EXPECT_EQ(".google.izzle", it->Domain());
1652  EXPECT_EQ("/bar", it->Path());
1653  EXPECT_FALSE(it->IsSecure());
1654  EXPECT_TRUE(it->IsHttpOnly());
1655
1656  ASSERT_TRUE(++it == cookies.end());
1657
1658  cookies = cm->GetAllCookiesForURL(url_google_secure);
1659  it = cookies.begin();
1660
1661  ASSERT_TRUE(it != cookies.end());
1662  EXPECT_EQ("E", it->Name());
1663  EXPECT_EQ("F", it->Value());
1664  EXPECT_EQ("/", it->Path());
1665  EXPECT_EQ("www.google.izzle", it->Domain());
1666  EXPECT_TRUE(it->IsSecure());
1667  EXPECT_FALSE(it->IsHttpOnly());
1668
1669  ASSERT_TRUE(++it == cookies.end());
1670}
1671
1672TEST(CookieMonsterTest, DeleteAllForHost) {
1673  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1674
1675  // Test probes:
1676  //    * Non-secure URL, mid-level (http://w.c.b.a)
1677  //    * Secure URL, mid-level (https://w.c.b.a)
1678  //    * URL with path, mid-level (https:/w.c.b.a/dir1/xx)
1679  // All three tests should nuke only the midlevel host cookie,
1680  // the http_only cookie, the host secure cookie, and the two host
1681  // path cookies.  http_only, secure, and paths are ignored by
1682  // this call, and domain cookies arent touched.
1683  PopulateCmForDeleteAllForHost(cm);
1684  EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1685            cm->GetCookies(GURL(kTopLevelDomainPlus3)));
1686  EXPECT_EQ("dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X",
1687            cm->GetCookies(GURL(kTopLevelDomainPlus2Secure)));
1688  EXPECT_EQ("dom_1=X; host_1=X", cm->GetCookies(GURL(kTopLevelDomainPlus1)));
1689  EXPECT_EQ("dom_path_2=X; host_path_2=X; dom_path_1=X; host_path_1=X; "
1690            "dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X",
1691            cm->GetCookies(GURL(kTopLevelDomainPlus2Secure +
1692                                std::string("/dir1/dir2/xxx"))));
1693
1694  EXPECT_EQ(5, cm->DeleteAllForHost(GURL(kTopLevelDomainPlus2)));
1695  EXPECT_EQ(8U, cm->GetAllCookies().size());
1696
1697  EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1698            cm->GetCookies(GURL(kTopLevelDomainPlus3)));
1699  EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1700            cm->GetCookies(GURL(kTopLevelDomainPlus2Secure)));
1701  EXPECT_EQ("dom_1=X; host_1=X", cm->GetCookies(GURL(kTopLevelDomainPlus1)));
1702  EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1703            cm->GetCookies(GURL(kTopLevelDomainPlus2Secure +
1704                                std::string("/dir1/dir2/xxx"))));
1705
1706  PopulateCmForDeleteAllForHost(cm);
1707  EXPECT_EQ(5, cm->DeleteAllForHost(GURL(kTopLevelDomainPlus2Secure)));
1708  EXPECT_EQ(8U, cm->GetAllCookies().size());
1709
1710  EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1711            cm->GetCookies(GURL(kTopLevelDomainPlus3)));
1712  EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1713            cm->GetCookies(GURL(kTopLevelDomainPlus2Secure)));
1714  EXPECT_EQ("dom_1=X; host_1=X", cm->GetCookies(GURL(kTopLevelDomainPlus1)));
1715  EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1716            cm->GetCookies(GURL(kTopLevelDomainPlus2Secure +
1717                                std::string("/dir1/dir2/xxx"))));
1718
1719  PopulateCmForDeleteAllForHost(cm);
1720  EXPECT_EQ(5, cm->DeleteAllForHost(GURL(kTopLevelDomainPlus2Secure +
1721                                         std::string("/dir1/xxx"))));
1722  EXPECT_EQ(8U, cm->GetAllCookies().size());
1723
1724  EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1725            cm->GetCookies(GURL(kTopLevelDomainPlus3)));
1726  EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1727            cm->GetCookies(GURL(kTopLevelDomainPlus2Secure)));
1728  EXPECT_EQ("dom_1=X; host_1=X", cm->GetCookies(GURL(kTopLevelDomainPlus1)));
1729  EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1730            cm->GetCookies(GURL(kTopLevelDomainPlus2Secure +
1731                                std::string("/dir1/dir2/xxx"))));
1732
1733}
1734
1735TEST(CookieMonsterTest, UniqueCreationTime) {
1736  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1737  GURL url_google(kUrlGoogle);
1738  CookieOptions options;
1739
1740  // Add in three cookies through every public interface to the
1741  // CookieMonster and confirm that none of them have duplicate
1742  // creation times.
1743
1744  // SetCookieWithCreationTime and SetCookieWithCreationTimeAndOptions
1745  // are not included as they aren't going to be public for very much
1746  // longer.
1747
1748  // SetCookie, SetCookies, SetCookiesWithOptions,
1749  // SetCookieWithOptions, SetCookieWithDetails
1750
1751  cm->SetCookie(url_google, "SetCookie1=A");
1752  cm->SetCookie(url_google, "SetCookie2=A");
1753  cm->SetCookie(url_google, "SetCookie3=A");
1754
1755  {
1756    std::vector<std::string> cookie_lines;
1757    cookie_lines.push_back("setCookies1=A");
1758    cookie_lines.push_back("setCookies2=A");
1759    cookie_lines.push_back("setCookies4=A");
1760    cm->SetCookies(url_google, cookie_lines);
1761  }
1762
1763  {
1764    std::vector<std::string> cookie_lines;
1765    cookie_lines.push_back("setCookiesWithOptions1=A");
1766    cookie_lines.push_back("setCookiesWithOptions2=A");
1767    cookie_lines.push_back("setCookiesWithOptions3=A");
1768
1769    cm->SetCookiesWithOptions(url_google, cookie_lines, options);
1770  }
1771
1772  cm->SetCookieWithOptions(url_google, "setCookieWithOptions1=A", options);
1773  cm->SetCookieWithOptions(url_google, "setCookieWithOptions2=A", options);
1774  cm->SetCookieWithOptions(url_google, "setCookieWithOptions3=A", options);
1775
1776  cm->SetCookieWithDetails(url_google, "setCookieWithDetails1", "A",
1777                           ".google.com", "/", Time(), false, false);
1778  cm->SetCookieWithDetails(url_google, "setCookieWithDetails2", "A",
1779                           ".google.com", "/", Time(), false, false);
1780  cm->SetCookieWithDetails(url_google, "setCookieWithDetails3", "A",
1781                           ".google.com", "/", Time(), false, false);
1782
1783  // Now we check
1784  CookieList cookie_list(cm->GetAllCookies());
1785  typedef std::map<int64, CookieMonster::CanonicalCookie> TimeCookieMap;
1786  TimeCookieMap check_map;
1787  for (CookieList::const_iterator it = cookie_list.begin();
1788       it != cookie_list.end(); it++) {
1789    const int64 creation_date = it->CreationDate().ToInternalValue();
1790    TimeCookieMap::const_iterator
1791        existing_cookie_it(check_map.find(creation_date));
1792    EXPECT_TRUE(existing_cookie_it == check_map.end())
1793        << "Cookie " << it->Name() << " has same creation date ("
1794        << it->CreationDate().ToInternalValue()
1795        << ") as previously entered cookie "
1796        << existing_cookie_it->second.Name();
1797
1798    if (existing_cookie_it == check_map.end()) {
1799      check_map.insert(TimeCookieMap::value_type(
1800          it->CreationDate().ToInternalValue(), *it));
1801    }
1802  }
1803}
1804
1805// Mainly a test of GetEffectiveDomain, or more specifically, of the
1806// expected behavior of GetEffectiveDomain within the CookieMonster.
1807TEST(CookieMonsterTest, GetKey) {
1808  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1809
1810  // This test is really only interesting if GetKey() actually does something.
1811  if (cm->expiry_and_key_scheme_ ==
1812      CookieMonster::EKS_KEEP_RECENT_AND_PURGE_ETLDP1) {
1813    EXPECT_EQ("google.com", cm->GetKey("www.google.com"));
1814    EXPECT_EQ("google.izzie", cm->GetKey("www.google.izzie"));
1815    EXPECT_EQ("google.izzie", cm->GetKey(".google.izzie"));
1816    EXPECT_EQ("bbc.co.uk", cm->GetKey("bbc.co.uk"));
1817    EXPECT_EQ("bbc.co.uk", cm->GetKey("a.b.c.d.bbc.co.uk"));
1818    EXPECT_EQ("apple.com", cm->GetKey("a.b.c.d.apple.com"));
1819    EXPECT_EQ("apple.izzie", cm->GetKey("a.b.c.d.apple.izzie"));
1820
1821    // Cases where the effective domain is null, so we use the host
1822    // as the key.
1823    EXPECT_EQ("co.uk", cm->GetKey("co.uk"));
1824    const std::string extension_name("iehocdgbbocmkdidlbnnfbmbinnahbae");
1825    EXPECT_EQ(extension_name, cm->GetKey(extension_name));
1826    EXPECT_EQ("com", cm->GetKey("com"));
1827    EXPECT_EQ("hostalias", cm->GetKey("hostalias"));
1828    EXPECT_EQ("localhost", cm->GetKey("localhost"));
1829  }
1830}
1831
1832// Test that cookies transfer from/to the backing store correctly.
1833TEST(CookieMonsterTest, BackingStoreCommunication) {
1834  // Store details for cookies transforming through the backing store interface.
1835
1836  base::Time current(base::Time::Now());
1837  scoped_refptr<MockSimplePersistentCookieStore> store(
1838      new MockSimplePersistentCookieStore);
1839  base::Time new_access_time;
1840  base::Time expires(base::Time::Now() + base::TimeDelta::FromSeconds(100));
1841
1842  struct CookiesInputInfo {
1843    std::string gurl;
1844    std::string name;
1845    std::string value;
1846    std::string domain;
1847    std::string path;
1848    base::Time expires;
1849    bool secure;
1850    bool http_only;
1851  };
1852  const CookiesInputInfo input_info[] = {
1853    {"http://a.b.google.com", "a", "1", "", "/path/to/cookie", expires,
1854     false, false},
1855    {"https://www.google.com", "b", "2", ".google.com", "/path/from/cookie",
1856     expires + TimeDelta::FromSeconds(10), true, true},
1857    {"https://google.com", "c", "3", "", "/another/path/to/cookie",
1858     base::Time::Now() + base::TimeDelta::FromSeconds(100),
1859     true, false}
1860  };
1861  const int INPUT_DELETE = 1;
1862
1863  // Create new cookies and flush them to the store.
1864  {
1865    scoped_refptr<CookieMonster> cmout(new CookieMonster(store, NULL));
1866    for (const CookiesInputInfo* p = input_info;
1867         p < &input_info[ARRAYSIZE_UNSAFE(input_info)]; p++) {
1868      EXPECT_TRUE(cmout->SetCookieWithDetails(GURL(p->gurl), p->name, p->value,
1869                                              p->domain, p->path, p->expires,
1870                                              p->secure, p->http_only));
1871    }
1872    cmout->DeleteCookie(GURL(std::string(input_info[INPUT_DELETE].gurl) +
1873                             input_info[INPUT_DELETE].path),
1874                        input_info[INPUT_DELETE].name);
1875  }
1876
1877  // Create a new cookie monster and make sure that everything is correct
1878  {
1879    scoped_refptr<CookieMonster> cmin(new CookieMonster(store, NULL));
1880    CookieList cookies(cmin->GetAllCookies());
1881    ASSERT_EQ(2u, cookies.size());
1882    // Ordering is path length, then creation time.  So second cookie
1883    // will come first, and we need to swap them.
1884    std::swap(cookies[0], cookies[1]);
1885    for (int output_index = 0; output_index < 2; output_index++) {
1886      int input_index = output_index * 2;
1887      const CookiesInputInfo* input = &input_info[input_index];
1888      const CookieMonster::CanonicalCookie* output = &cookies[output_index];
1889
1890      EXPECT_EQ(input->name, output->Name());
1891      EXPECT_EQ(input->value, output->Value());
1892      EXPECT_EQ(GURL(input->gurl).host(), output->Domain());
1893      EXPECT_EQ(input->path, output->Path());
1894      EXPECT_LE(current.ToInternalValue(),
1895                output->CreationDate().ToInternalValue());
1896      EXPECT_EQ(input->secure, output->IsSecure());
1897      EXPECT_EQ(input->http_only, output->IsHttpOnly());
1898      EXPECT_TRUE(output->IsPersistent());
1899      EXPECT_EQ(input->expires.ToInternalValue(),
1900                output->ExpiryDate().ToInternalValue());
1901    }
1902  }
1903}
1904
1905TEST(CookieMonsterTest, CookieOrdering) {
1906  // Put a random set of cookies into a monster and make sure
1907  // they're returned in the right order.
1908  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1909  EXPECT_TRUE(cm->SetCookie(GURL("http://d.c.b.a.google.com/aa/x.html"),
1910                            "c=1"));
1911  EXPECT_TRUE(cm->SetCookie(GURL("http://b.a.google.com/aa/bb/cc/x.html"),
1912                            "d=1; domain=b.a.google.com"));
1913  EXPECT_TRUE(cm->SetCookie(GURL("http://b.a.google.com/aa/bb/cc/x.html"),
1914                            "a=4; domain=b.a.google.com"));
1915  EXPECT_TRUE(cm->SetCookie(GURL("http://c.b.a.google.com/aa/bb/cc/x.html"),
1916                            "e=1; domain=c.b.a.google.com"));
1917  EXPECT_TRUE(cm->SetCookie(GURL("http://d.c.b.a.google.com/aa/bb/x.html"),
1918                            "b=1"));
1919  EXPECT_TRUE(cm->SetCookie(GURL("http://news.bbc.co.uk/midpath/x.html"),
1920                            "g=10"));
1921  EXPECT_EQ("d=1; a=4; e=1; b=1; c=1",
1922            cm->GetCookiesWithOptions(
1923                GURL("http://d.c.b.a.google.com/aa/bb/cc/dd"),
1924                CookieOptions()));
1925  {
1926    unsigned int i = 0;
1927    CookieList cookies(cm->GetAllCookiesForURL(
1928        GURL("http://d.c.b.a.google.com/aa/bb/cc/dd")));
1929    ASSERT_EQ(5u, cookies.size());
1930    EXPECT_EQ("d", cookies[i++].Name());
1931    EXPECT_EQ("a", cookies[i++].Name());
1932    EXPECT_EQ("e", cookies[i++].Name());
1933    EXPECT_EQ("b", cookies[i++].Name());
1934    EXPECT_EQ("c", cookies[i++].Name());
1935  }
1936
1937  {
1938    unsigned int i = 0;
1939    CookieList cookies(cm->GetAllCookies());
1940    ASSERT_EQ(6u, cookies.size());
1941    EXPECT_EQ("d", cookies[i++].Name());
1942    EXPECT_EQ("a", cookies[i++].Name());
1943    EXPECT_EQ("e", cookies[i++].Name());
1944    EXPECT_EQ("g", cookies[i++].Name());
1945    EXPECT_EQ("b", cookies[i++].Name());
1946    EXPECT_EQ("c", cookies[i++].Name());
1947  }
1948}
1949
1950
1951// Function for creating a CM with a number of cookies in it,
1952// no store (and hence no ability to affect access time).
1953static CookieMonster* CreateMonsterForGC(int num_cookies) {
1954  CookieMonster* cm(new CookieMonster(NULL, NULL));
1955  for (int i = 0; i < num_cookies; i++)
1956    cm->SetCookie(GURL(StringPrintf("http://h%05d.izzle", i)), "a=1");
1957  return cm;
1958}
1959
1960// This test and CookieMonstertest.TestGCTimes (in cookie_monster_perftest.cc)
1961// are somewhat complementary twins.  This test is probing for whether
1962// garbage collection always happens when it should (i.e. that we actually
1963// get rid of cookies when we should).  The perftest is probing for
1964// whether garbage collection happens when it shouldn't.  See comments
1965// before that test for more details.
1966TEST(CookieMonsterTest, GarbageCollectionTriggers) {
1967  // First we check to make sure that a whole lot of recent cookies
1968  // doesn't get rid of anything after garbage collection is checked for.
1969  {
1970    scoped_refptr<CookieMonster> cm(
1971        CreateMonsterForGC(CookieMonster::kMaxCookies * 2));
1972    EXPECT_EQ(CookieMonster::kMaxCookies * 2, cm->GetAllCookies().size());
1973    cm->SetCookie(GURL("http://newdomain.com"), "b=2");
1974    EXPECT_EQ(CookieMonster::kMaxCookies * 2 + 1, cm->GetAllCookies().size());
1975  }
1976
1977  // Now we explore a series of relationships between cookie last access
1978  // time and size of store to make sure we only get rid of cookies when
1979  // we really should.
1980  const struct TestCase {
1981    int num_cookies;
1982    int num_old_cookies;
1983    int expected_initial_cookies;
1984    // Indexed by ExpiryAndKeyScheme
1985    int expected_cookies_after_set[CookieMonster::EKS_LAST_ENTRY];
1986  } test_cases[] = {
1987    {
1988      // A whole lot of recent cookies; gc shouldn't happen.
1989      CookieMonster::kMaxCookies * 2,
1990      0,
1991      CookieMonster::kMaxCookies * 2,
1992      { CookieMonster::kMaxCookies * 2 + 1,
1993        CookieMonster::kMaxCookies - CookieMonster::kPurgeCookies }
1994    }, {
1995      // Some old cookies, but still overflowing max.
1996      CookieMonster::kMaxCookies * 2,
1997      CookieMonster::kMaxCookies / 2,
1998      CookieMonster::kMaxCookies * 2,
1999      {CookieMonster::kMaxCookies * 2 - CookieMonster::kMaxCookies / 2 + 1,
2000       CookieMonster::kMaxCookies - CookieMonster::kPurgeCookies}
2001    }, {
2002      // Old cookies enough to bring us right down to our purge line.
2003      CookieMonster::kMaxCookies * 2,
2004      CookieMonster::kMaxCookies + CookieMonster::kPurgeCookies + 1,
2005      CookieMonster::kMaxCookies * 2,
2006      {CookieMonster::kMaxCookies - CookieMonster::kPurgeCookies,
2007       CookieMonster::kMaxCookies - CookieMonster::kPurgeCookies}
2008    }, {
2009      // Old cookies enough to bring below our purge line (which we
2010      // shouldn't do).
2011      CookieMonster::kMaxCookies * 2,
2012      CookieMonster::kMaxCookies * 3 / 2,
2013      CookieMonster::kMaxCookies * 2,
2014      {CookieMonster::kMaxCookies - CookieMonster::kPurgeCookies,
2015       CookieMonster::kMaxCookies - CookieMonster::kPurgeCookies}
2016    }
2017  };
2018  const CookieMonster::ExpiryAndKeyScheme schemes[] = {
2019    CookieMonster::EKS_KEEP_RECENT_AND_PURGE_ETLDP1,
2020    CookieMonster::EKS_DISCARD_RECENT_AND_PURGE_DOMAIN,
2021  };
2022
2023  for (int ci = 0; ci < static_cast<int>(ARRAYSIZE_UNSAFE(test_cases)); ++ci) {
2024    // Test both old and new key and expiry schemes.
2025    for (int recent_scheme = 0;
2026         recent_scheme < static_cast<int>(ARRAYSIZE_UNSAFE(schemes));
2027         recent_scheme++) {
2028      const TestCase *test_case = &test_cases[ci];
2029      scoped_refptr<CookieMonster> cm(
2030          CreateMonsterFromStoreForGC(
2031              test_case->num_cookies, test_case->num_old_cookies,
2032              CookieMonster::kSafeFromGlobalPurgeDays * 2));
2033      cm->SetExpiryAndKeyScheme(schemes[recent_scheme]);
2034      EXPECT_EQ(test_case->expected_initial_cookies,
2035                static_cast<int>(cm->GetAllCookies().size()))
2036          << "For test case " << ci;
2037      // Will trigger GC
2038      cm->SetCookie(GURL("http://newdomain.com"), "b=2");
2039      EXPECT_EQ(test_case->expected_cookies_after_set[recent_scheme],
2040                static_cast<int>((cm->GetAllCookies().size())))
2041          << "For test case (" << ci << ", " << recent_scheme << ")";
2042    }
2043  }
2044}
2045
2046// This test checks that setting a cookie forcing it to be a session only
2047// cookie works as expected.
2048TEST(CookieMonsterTest, ForceSessionOnly) {
2049  GURL url_google(kUrlGoogle);
2050  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2051  CookieOptions options;
2052
2053  // Set a persistent cookie, but force it to be a session cookie.
2054  options.set_force_session();
2055  ASSERT_TRUE(cm->SetCookieWithOptions(url_google,
2056      std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT",
2057      options));
2058
2059  // Get the canonical cookie.
2060  CookieList cookie_list = cm->GetAllCookies();
2061  ASSERT_EQ(1U, cookie_list.size());
2062  ASSERT_FALSE(cookie_list[0].IsPersistent());
2063
2064  // Use a past expiry date to delete the cookie, but force it to session only.
2065  ASSERT_TRUE(cm->SetCookieWithOptions(url_google,
2066      std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-1977 22:50:13 GMT",
2067      options));
2068
2069  // Check that the cookie was deleted.
2070  cookie_list = cm->GetAllCookies();
2071  ASSERT_EQ(0U, cookie_list.size());
2072}
2073
2074// This test checks that keep expired cookies flag is working.
2075TEST(CookieMonsterTest, KeepExpiredCookies) {
2076  GURL url_google(kUrlGoogle);
2077  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2078  cm->SetKeepExpiredCookies();
2079  CookieOptions options;
2080
2081  // Set a persistent cookie.
2082  ASSERT_TRUE(cm->SetCookieWithOptions(url_google,
2083      std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT",
2084      options));
2085
2086  // Get the canonical cookie.
2087  CookieList cookie_list = cm->GetAllCookies();
2088  ASSERT_EQ(1U, cookie_list.size());
2089
2090  // Use a past expiry date to delete the cookie.
2091  ASSERT_TRUE(cm->SetCookieWithOptions(url_google,
2092      std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-1977 22:50:13 GMT",
2093      options));
2094
2095  // Check that the cookie with the past expiry date is still there.
2096  // GetAllCookies() also triggers garbage collection.
2097  cookie_list = cm->GetAllCookies();
2098  ASSERT_EQ(1U, cookie_list.size());
2099  ASSERT_TRUE(cookie_list[0].IsExpired(Time::Now()));
2100}
2101
2102namespace {
2103
2104// Mock PersistentCookieStore that keeps track of the number of Flush() calls.
2105class FlushablePersistentStore : public CookieMonster::PersistentCookieStore {
2106 public:
2107  FlushablePersistentStore() : flush_count_(0) {}
2108
2109  bool Load(std::vector<CookieMonster::CanonicalCookie*>*) {
2110    return false;
2111  }
2112
2113  void AddCookie(const CookieMonster::CanonicalCookie&) {}
2114  void UpdateCookieAccessTime(const CookieMonster::CanonicalCookie&) {}
2115  void DeleteCookie(const CookieMonster::CanonicalCookie&) {}
2116  void SetClearLocalStateOnExit(bool clear_local_state) {}
2117
2118  void Flush(Task* completion_callback) {
2119    ++flush_count_;
2120    if (completion_callback) {
2121      completion_callback->Run();
2122      delete completion_callback;
2123    }
2124  }
2125
2126  int flush_count() {
2127    return flush_count_;
2128  }
2129
2130 private:
2131  volatile int flush_count_;
2132};
2133
2134// Counts the number of times Callback() has been run.
2135class CallbackCounter : public base::RefCountedThreadSafe<CallbackCounter> {
2136 public:
2137  CallbackCounter() : callback_count_(0) {}
2138
2139  void Callback() {
2140    ++callback_count_;
2141  }
2142
2143  int callback_count() {
2144    return callback_count_;
2145  }
2146
2147 private:
2148  friend class base::RefCountedThreadSafe<CallbackCounter>;
2149  volatile int callback_count_;
2150};
2151
2152}  // namespace
2153
2154// Test that FlushStore() is forwarded to the store and callbacks are posted.
2155TEST(CookieMonsterTest, FlushStore) {
2156  scoped_refptr<CallbackCounter> counter(new CallbackCounter());
2157  scoped_refptr<FlushablePersistentStore> store(new FlushablePersistentStore());
2158  scoped_refptr<CookieMonster> cm(new CookieMonster(store, NULL));
2159
2160  ASSERT_EQ(0, store->flush_count());
2161  ASSERT_EQ(0, counter->callback_count());
2162
2163  // Before initialization, FlushStore() should just run the callback.
2164  cm->FlushStore(NewRunnableMethod(counter.get(), &CallbackCounter::Callback));
2165  MessageLoop::current()->RunAllPending();
2166
2167  ASSERT_EQ(0, store->flush_count());
2168  ASSERT_EQ(1, counter->callback_count());
2169
2170  // NULL callback is safe.
2171  cm->FlushStore(NULL);
2172  MessageLoop::current()->RunAllPending();
2173
2174  ASSERT_EQ(0, store->flush_count());
2175  ASSERT_EQ(1, counter->callback_count());
2176
2177  // After initialization, FlushStore() should delegate to the store.
2178  cm->GetAllCookies();  // Force init.
2179  cm->FlushStore(NewRunnableMethod(counter.get(), &CallbackCounter::Callback));
2180  MessageLoop::current()->RunAllPending();
2181
2182  ASSERT_EQ(1, store->flush_count());
2183  ASSERT_EQ(2, counter->callback_count());
2184
2185  // NULL callback is still safe.
2186  cm->FlushStore(NULL);
2187  MessageLoop::current()->RunAllPending();
2188
2189  ASSERT_EQ(2, store->flush_count());
2190  ASSERT_EQ(2, counter->callback_count());
2191
2192  // If there's no backing store, FlushStore() is always a safe no-op.
2193  cm = new CookieMonster(NULL, NULL);
2194  cm->GetAllCookies();  // Force init.
2195  cm->FlushStore(NULL);
2196  MessageLoop::current()->RunAllPending();
2197
2198  ASSERT_EQ(2, counter->callback_count());
2199
2200  cm->FlushStore(NewRunnableMethod(counter.get(), &CallbackCounter::Callback));
2201  MessageLoop::current()->RunAllPending();
2202
2203  ASSERT_EQ(3, counter->callback_count());
2204}
2205
2206TEST(CookieMonsterTest, GetCookieSourceFromURL) {
2207  EXPECT_EQ("http://example.com/",
2208            CookieMonster::CanonicalCookie::GetCookieSourceFromURL(
2209                GURL("http://example.com")));
2210  EXPECT_EQ("http://example.com/",
2211            CookieMonster::CanonicalCookie::GetCookieSourceFromURL(
2212                GURL("http://example.com/")));
2213  EXPECT_EQ("http://example.com/",
2214            CookieMonster::CanonicalCookie::GetCookieSourceFromURL(
2215                GURL("http://example.com/test")));
2216  EXPECT_EQ("file:///tmp/test.html",
2217            CookieMonster::CanonicalCookie::GetCookieSourceFromURL(
2218                GURL("file:///tmp/test.html")));
2219  EXPECT_EQ("http://example.com/",
2220            CookieMonster::CanonicalCookie::GetCookieSourceFromURL(
2221                GURL("http://example.com:1234/")));
2222  EXPECT_EQ("http://example.com/",
2223            CookieMonster::CanonicalCookie::GetCookieSourceFromURL(
2224                GURL("https://example.com/")));
2225  EXPECT_EQ("http://example.com/",
2226            CookieMonster::CanonicalCookie::GetCookieSourceFromURL(
2227                GURL("http://user:pwd@example.com/")));
2228  EXPECT_EQ("http://example.com/",
2229            CookieMonster::CanonicalCookie::GetCookieSourceFromURL(
2230                GURL("http://example.com/test?foo")));
2231  EXPECT_EQ("http://example.com/",
2232            CookieMonster::CanonicalCookie::GetCookieSourceFromURL(
2233                GURL("http://example.com/test#foo")));
2234}
2235
2236TEST(CookieMonsterTest, HistogramCheck) {
2237  scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2238  // Should match call in InitializeHistograms, but doesn't really matter
2239  // since the histogram should have been initialized by the CM construction
2240  // above.
2241  base::Histogram* expired_histogram =
2242      base::Histogram::FactoryGet(
2243          "Cookie.ExpirationDurationMinutes", 1, 10 * 365 * 24 * 60, 50,
2244          base::Histogram::kUmaTargetedHistogramFlag);
2245
2246  base::Histogram::SampleSet histogram_set_1;
2247  expired_histogram->SnapshotSample(&histogram_set_1);
2248  ASSERT_TRUE(cm->SetCookieWithDetails(
2249      GURL("http://fake.a.url"), "a", "b", "a.url", "/",
2250      base::Time::Now() + base::TimeDelta::FromMinutes(59),
2251      false, false));
2252
2253  base::Histogram::SampleSet histogram_set_2;
2254  expired_histogram->SnapshotSample(&histogram_set_2);
2255  EXPECT_EQ(histogram_set_1.TotalCount() + 1,
2256            histogram_set_2.TotalCount());
2257
2258  // kValidCookieLine creates a session cookie.
2259  GURL url_google(kUrlGoogle);
2260  ASSERT_TRUE(cm->SetCookie(url_google, kValidCookieLine));
2261  expired_histogram->SnapshotSample(&histogram_set_1);
2262  EXPECT_EQ(histogram_set_2.TotalCount(),
2263            histogram_set_1.TotalCount());
2264}
2265
2266}  // namespace
2267