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