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