OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "net/base/cookie_store_unittest.h" | |
6 | |
7 #include <time.h> | |
8 #include <string> | |
9 | |
10 #include "base/basictypes.h" | |
11 #include "base/bind.h" | |
12 #include "base/memory/ref_counted.h" | |
13 #include "base/memory/scoped_ptr.h" | |
14 #include "base/message_loop.h" | |
15 #include "base/metrics/histogram.h" | |
16 #include "base/stringprintf.h" | |
17 #include "base/string_tokenizer.h" | |
18 #include "base/threading/thread.h" | |
19 #include "base/time.h" | |
20 #include "googleurl/src/gurl.h" | |
21 #include "net/base/cookie_monster.h" | |
22 #include "net/base/cookie_monster_store_test.h" // For CookieStore mock | |
23 #include "net/base/cookie_util.h" | |
24 #include "testing/gmock/include/gmock/gmock.h" | |
25 #include "testing/gtest/include/gtest/gtest.h" | |
26 | |
27 namespace net { | |
28 | |
29 using base::Time; | |
30 using base::TimeDelta; | |
31 | |
32 namespace { | |
33 | |
34 // TODO(erikwright): Replace the pre-existing MockPersistentCookieStore (and | |
35 // brethren) with this one, and remove the 'New' prefix. | |
36 class NewMockPersistentCookieStore | |
37 : public CookieMonster::PersistentCookieStore { | |
38 public: | |
39 MOCK_METHOD1(Load, void(const LoadedCallback& loaded_callback)); | |
40 MOCK_METHOD2(LoadCookiesForKey, void(const std::string& key, | |
41 const LoadedCallback& loaded_callback)); | |
42 MOCK_METHOD1(AddCookie, void(const CookieMonster::CanonicalCookie& cc)); | |
43 MOCK_METHOD1(UpdateCookieAccessTime, | |
44 void(const CookieMonster::CanonicalCookie& cc)); | |
45 MOCK_METHOD1(DeleteCookie, void(const CookieMonster::CanonicalCookie& cc)); | |
46 MOCK_METHOD1(SetClearLocalStateOnExit, void(bool clear_local_state)); | |
47 MOCK_METHOD1(Flush, void(const base::Closure& callback)); | |
48 }; | |
49 | |
50 const char* kTopLevelDomainPlus1 = "http://www.harvard.edu"; | |
51 const char* kTopLevelDomainPlus2 = "http://www.math.harvard.edu"; | |
52 const char* kTopLevelDomainPlus2Secure = "https://www.math.harvard.edu"; | |
53 const char* kTopLevelDomainPlus3 = | |
54 "http://www.bourbaki.math.harvard.edu"; | |
55 const char* kOtherDomain = "http://www.mit.edu"; | |
56 const char kUrlGoogleSpecific[] = "http://www.gmail.google.izzle"; | |
57 | |
58 class GetCookieListCallback : public CookieCallback { | |
59 public: | |
60 GetCookieListCallback() {} | |
61 explicit GetCookieListCallback(Thread* run_in_thread) | |
62 : CookieCallback(run_in_thread) {} | |
63 | |
64 void Run(const CookieList& cookies) { | |
65 cookies_ = cookies; | |
66 CallbackEpilogue(); | |
67 } | |
68 | |
69 const CookieList& cookies() { return cookies_; } | |
70 | |
71 private: | |
72 CookieList cookies_; | |
73 }; | |
74 | |
75 class ParsedCookieTest : public testing::Test { }; | |
76 | |
77 } // namespace | |
78 | |
79 TEST(ParsedCookieTest, TestBasic) { | |
80 CookieMonster::ParsedCookie pc("a=b"); | |
81 EXPECT_TRUE(pc.IsValid()); | |
82 EXPECT_FALSE(pc.IsSecure()); | |
83 EXPECT_EQ("a", pc.Name()); | |
84 EXPECT_EQ("b", pc.Value()); | |
85 } | |
86 | |
87 TEST(ParsedCookieTest, TestQuoted) { | |
88 // These are some quoting cases which the major browsers all | |
89 // handle differently. I've tested Internet Explorer 6, Opera 9.6, | |
90 // Firefox 3, and Safari Windows 3.2.1. We originally tried to match | |
91 // Firefox closely, however we now match Internet Explorer and Safari. | |
92 const char* values[] = { | |
93 // Trailing whitespace after a quoted value. The whitespace after | |
94 // the quote is stripped in all browsers. | |
95 "\"zzz \" ", "\"zzz \"", | |
96 // Handling a quoted value with a ';', like FOO="zz;pp" ; | |
97 // IE and Safari: "zz; | |
98 // Firefox and Opera: "zz;pp" | |
99 "\"zz;pp\" ;", "\"zz", | |
100 // Handling a value with multiple quoted parts, like FOO="zzz " "ppp" ; | |
101 // IE and Safari: "zzz " "ppp"; | |
102 // Firefox: "zzz "; | |
103 // Opera: <rejects cookie> | |
104 "\"zzz \" \"ppp\" ", "\"zzz \" \"ppp\"", | |
105 // A quote in a value that didn't start quoted. like FOO=A"B ; | |
106 // IE, Safari, and Firefox: A"B; | |
107 // Opera: <rejects cookie> | |
108 "A\"B", "A\"B", | |
109 }; | |
110 | |
111 for (size_t i = 0; i < arraysize(values); i += 2) { | |
112 std::string input(values[i]); | |
113 std::string expected(values[i + 1]); | |
114 | |
115 CookieMonster::ParsedCookie pc( | |
116 "aBc=" + input + " ; path=\"/\" ; httponly "); | |
117 EXPECT_TRUE(pc.IsValid()); | |
118 EXPECT_FALSE(pc.IsSecure()); | |
119 EXPECT_TRUE(pc.IsHttpOnly()); | |
120 EXPECT_TRUE(pc.HasPath()); | |
121 EXPECT_EQ("aBc", pc.Name()); | |
122 EXPECT_EQ(expected, pc.Value()); | |
123 | |
124 // If a path was quoted, the path attribute keeps the quotes. This will | |
125 // make the cookie effectively useless, but path parameters aren't supposed | |
126 // to be quoted. Bug 1261605. | |
127 EXPECT_EQ("\"/\"", pc.Path()); | |
128 } | |
129 } | |
130 | |
131 TEST(ParsedCookieTest, TestNameless) { | |
132 CookieMonster::ParsedCookie pc("BLAHHH; path=/; secure;"); | |
133 EXPECT_TRUE(pc.IsValid()); | |
134 EXPECT_TRUE(pc.IsSecure()); | |
135 EXPECT_TRUE(pc.HasPath()); | |
136 EXPECT_EQ("/", pc.Path()); | |
137 EXPECT_EQ("", pc.Name()); | |
138 EXPECT_EQ("BLAHHH", pc.Value()); | |
139 } | |
140 | |
141 TEST(ParsedCookieTest, TestAttributeCase) { | |
142 CookieMonster::ParsedCookie pc("BLAHHH; Path=/; sECuRe; httpONLY"); | |
143 EXPECT_TRUE(pc.IsValid()); | |
144 EXPECT_TRUE(pc.IsSecure()); | |
145 EXPECT_TRUE(pc.IsHttpOnly()); | |
146 EXPECT_TRUE(pc.HasPath()); | |
147 EXPECT_EQ("/", pc.Path()); | |
148 EXPECT_EQ("", pc.Name()); | |
149 EXPECT_EQ("BLAHHH", pc.Value()); | |
150 EXPECT_EQ(3U, pc.NumberOfAttributes()); | |
151 } | |
152 | |
153 TEST(ParsedCookieTest, TestDoubleQuotedNameless) { | |
154 CookieMonster::ParsedCookie pc("\"BLA\\\"HHH\"; path=/; secure;"); | |
155 EXPECT_TRUE(pc.IsValid()); | |
156 EXPECT_TRUE(pc.IsSecure()); | |
157 EXPECT_TRUE(pc.HasPath()); | |
158 EXPECT_EQ("/", pc.Path()); | |
159 EXPECT_EQ("", pc.Name()); | |
160 EXPECT_EQ("\"BLA\\\"HHH\"", pc.Value()); | |
161 EXPECT_EQ(2U, pc.NumberOfAttributes()); | |
162 } | |
163 | |
164 TEST(ParsedCookieTest, QuoteOffTheEnd) { | |
165 CookieMonster::ParsedCookie pc("a=\"B"); | |
166 EXPECT_TRUE(pc.IsValid()); | |
167 EXPECT_EQ("a", pc.Name()); | |
168 EXPECT_EQ("\"B", pc.Value()); | |
169 EXPECT_EQ(0U, pc.NumberOfAttributes()); | |
170 } | |
171 | |
172 TEST(ParsedCookieTest, MissingName) { | |
173 CookieMonster::ParsedCookie pc("=ABC"); | |
174 EXPECT_TRUE(pc.IsValid()); | |
175 EXPECT_EQ("", pc.Name()); | |
176 EXPECT_EQ("ABC", pc.Value()); | |
177 EXPECT_EQ(0U, pc.NumberOfAttributes()); | |
178 } | |
179 | |
180 TEST(ParsedCookieTest, MissingValue) { | |
181 CookieMonster::ParsedCookie pc("ABC=; path = /wee"); | |
182 EXPECT_TRUE(pc.IsValid()); | |
183 EXPECT_EQ("ABC", pc.Name()); | |
184 EXPECT_EQ("", pc.Value()); | |
185 EXPECT_TRUE(pc.HasPath()); | |
186 EXPECT_EQ("/wee", pc.Path()); | |
187 EXPECT_EQ(1U, pc.NumberOfAttributes()); | |
188 } | |
189 | |
190 TEST(ParsedCookieTest, Whitespace) { | |
191 CookieMonster::ParsedCookie pc(" A = BC ;secure;;; httponly"); | |
192 EXPECT_TRUE(pc.IsValid()); | |
193 EXPECT_EQ("A", pc.Name()); | |
194 EXPECT_EQ("BC", pc.Value()); | |
195 EXPECT_FALSE(pc.HasPath()); | |
196 EXPECT_FALSE(pc.HasDomain()); | |
197 EXPECT_TRUE(pc.IsSecure()); | |
198 EXPECT_TRUE(pc.IsHttpOnly()); | |
199 // We parse anything between ; as attributes, so we end up with two | |
200 // attributes with an empty string name and value. | |
201 EXPECT_EQ(4U, pc.NumberOfAttributes()); | |
202 } | |
203 TEST(ParsedCookieTest, MultipleEquals) { | |
204 CookieMonster::ParsedCookie pc(" A=== BC ;secure;;; httponly"); | |
205 EXPECT_TRUE(pc.IsValid()); | |
206 EXPECT_EQ("A", pc.Name()); | |
207 EXPECT_EQ("== BC", pc.Value()); | |
208 EXPECT_FALSE(pc.HasPath()); | |
209 EXPECT_FALSE(pc.HasDomain()); | |
210 EXPECT_TRUE(pc.IsSecure()); | |
211 EXPECT_TRUE(pc.IsHttpOnly()); | |
212 EXPECT_EQ(4U, pc.NumberOfAttributes()); | |
213 } | |
214 | |
215 TEST(ParsedCookieTest, MACKey) { | |
216 CookieMonster::ParsedCookie pc("foo=bar; MAC-Key=3900ac9anw9incvw9f"); | |
217 EXPECT_TRUE(pc.IsValid()); | |
218 EXPECT_EQ("foo", pc.Name()); | |
219 EXPECT_EQ("bar", pc.Value()); | |
220 EXPECT_EQ("3900ac9anw9incvw9f", pc.MACKey()); | |
221 EXPECT_EQ(1U, pc.NumberOfAttributes()); | |
222 } | |
223 | |
224 TEST(ParsedCookieTest, MACAlgorithm) { | |
225 CookieMonster::ParsedCookie pc("foo=bar; MAC-Algorithm=hmac-sha-1"); | |
226 EXPECT_TRUE(pc.IsValid()); | |
227 EXPECT_EQ("foo", pc.Name()); | |
228 EXPECT_EQ("bar", pc.Value()); | |
229 EXPECT_EQ("hmac-sha-1", pc.MACAlgorithm()); | |
230 EXPECT_EQ(1U, pc.NumberOfAttributes()); | |
231 } | |
232 | |
233 TEST(ParsedCookieTest, MACKeyAndMACAlgorithm) { | |
234 CookieMonster::ParsedCookie pc( | |
235 "foo=bar; MAC-Key=voiae-09fj0302nfqf; MAC-Algorithm=hmac-sha-256"); | |
236 EXPECT_TRUE(pc.IsValid()); | |
237 EXPECT_EQ("foo", pc.Name()); | |
238 EXPECT_EQ("bar", pc.Value()); | |
239 EXPECT_EQ("voiae-09fj0302nfqf", pc.MACKey()); | |
240 EXPECT_EQ("hmac-sha-256", pc.MACAlgorithm()); | |
241 EXPECT_EQ(2U, pc.NumberOfAttributes()); | |
242 } | |
243 | |
244 TEST(ParsedCookieTest, QuotedTrailingWhitespace) { | |
245 CookieMonster::ParsedCookie pc("ANCUUID=\"zohNumRKgI0oxyhSsV3Z7D\" ; " | |
246 "expires=Sun, 18-Apr-2027 21:06:29 GMT ; " | |
247 "path=/ ; "); | |
248 EXPECT_TRUE(pc.IsValid()); | |
249 EXPECT_EQ("ANCUUID", pc.Name()); | |
250 // Stripping whitespace after the quotes matches all other major browsers. | |
251 EXPECT_EQ("\"zohNumRKgI0oxyhSsV3Z7D\"", pc.Value()); | |
252 EXPECT_TRUE(pc.HasExpires()); | |
253 EXPECT_TRUE(pc.HasPath()); | |
254 EXPECT_EQ("/", pc.Path()); | |
255 EXPECT_EQ(2U, pc.NumberOfAttributes()); | |
256 } | |
257 | |
258 TEST(ParsedCookieTest, TrailingWhitespace) { | |
259 CookieMonster::ParsedCookie pc("ANCUUID=zohNumRKgI0oxyhSsV3Z7D ; " | |
260 "expires=Sun, 18-Apr-2027 21:06:29 GMT ; " | |
261 "path=/ ; "); | |
262 EXPECT_TRUE(pc.IsValid()); | |
263 EXPECT_EQ("ANCUUID", pc.Name()); | |
264 EXPECT_EQ("zohNumRKgI0oxyhSsV3Z7D", pc.Value()); | |
265 EXPECT_TRUE(pc.HasExpires()); | |
266 EXPECT_TRUE(pc.HasPath()); | |
267 EXPECT_EQ("/", pc.Path()); | |
268 EXPECT_EQ(2U, pc.NumberOfAttributes()); | |
269 } | |
270 | |
271 TEST(ParsedCookieTest, TooManyPairs) { | |
272 std::string blankpairs; | |
273 blankpairs.resize(CookieMonster::ParsedCookie::kMaxPairs - 1, ';'); | |
274 | |
275 CookieMonster::ParsedCookie pc1(blankpairs + "secure"); | |
276 EXPECT_TRUE(pc1.IsValid()); | |
277 EXPECT_TRUE(pc1.IsSecure()); | |
278 | |
279 CookieMonster::ParsedCookie pc2(blankpairs + ";secure"); | |
280 EXPECT_TRUE(pc2.IsValid()); | |
281 EXPECT_FALSE(pc2.IsSecure()); | |
282 } | |
283 | |
284 // TODO(erikwright): some better test cases for invalid cookies. | |
285 TEST(ParsedCookieTest, InvalidWhitespace) { | |
286 CookieMonster::ParsedCookie pc(" "); | |
287 EXPECT_FALSE(pc.IsValid()); | |
288 } | |
289 | |
290 TEST(ParsedCookieTest, InvalidTooLong) { | |
291 std::string maxstr; | |
292 maxstr.resize(CookieMonster::ParsedCookie::kMaxCookieSize, 'a'); | |
293 | |
294 CookieMonster::ParsedCookie pc1(maxstr); | |
295 EXPECT_TRUE(pc1.IsValid()); | |
296 | |
297 CookieMonster::ParsedCookie pc2(maxstr + "A"); | |
298 EXPECT_FALSE(pc2.IsValid()); | |
299 } | |
300 | |
301 TEST(ParsedCookieTest, InvalidEmpty) { | |
302 CookieMonster::ParsedCookie pc(""); | |
303 EXPECT_FALSE(pc.IsValid()); | |
304 } | |
305 | |
306 TEST(ParsedCookieTest, EmbeddedTerminator) { | |
307 CookieMonster::ParsedCookie pc1("AAA=BB\0ZYX"); | |
308 CookieMonster::ParsedCookie pc2("AAA=BB\rZYX"); | |
309 CookieMonster::ParsedCookie pc3("AAA=BB\nZYX"); | |
310 EXPECT_TRUE(pc1.IsValid()); | |
311 EXPECT_EQ("AAA", pc1.Name()); | |
312 EXPECT_EQ("BB", pc1.Value()); | |
313 EXPECT_TRUE(pc2.IsValid()); | |
314 EXPECT_EQ("AAA", pc2.Name()); | |
315 EXPECT_EQ("BB", pc2.Value()); | |
316 EXPECT_TRUE(pc3.IsValid()); | |
317 EXPECT_EQ("AAA", pc3.Name()); | |
318 EXPECT_EQ("BB", pc3.Value()); | |
319 } | |
320 | |
321 TEST(ParsedCookieTest, ParseTokensAndValues) { | |
322 EXPECT_EQ("hello", | |
323 CookieMonster::ParsedCookie::ParseTokenString( | |
324 "hello\nworld")); | |
325 EXPECT_EQ("fs!!@", | |
326 CookieMonster::ParsedCookie::ParseTokenString( | |
327 "fs!!@;helloworld")); | |
328 EXPECT_EQ("hello world\tgood", | |
329 CookieMonster::ParsedCookie::ParseTokenString( | |
330 "hello world\tgood\rbye")); | |
331 EXPECT_EQ("A", | |
332 CookieMonster::ParsedCookie::ParseTokenString( | |
333 "A=B=C;D=E")); | |
334 EXPECT_EQ("hello", | |
335 CookieMonster::ParsedCookie::ParseValueString( | |
336 "hello\nworld")); | |
337 EXPECT_EQ("fs!!@", | |
338 CookieMonster::ParsedCookie::ParseValueString( | |
339 "fs!!@;helloworld")); | |
340 EXPECT_EQ("hello world\tgood", | |
341 CookieMonster::ParsedCookie::ParseValueString( | |
342 "hello world\tgood\rbye")); | |
343 EXPECT_EQ("A=B=C", | |
344 CookieMonster::ParsedCookie::ParseValueString( | |
345 "A=B=C;D=E")); | |
346 } | |
347 | |
348 namespace { | |
349 | |
350 struct CookieMonsterTestTraits { | |
351 static scoped_refptr<CookieStore> Create() { | |
352 return new CookieMonster(NULL, NULL); | |
353 } | |
354 | |
355 static const bool is_cookie_monster = true; | |
356 static const bool supports_http_only = true; | |
357 static const bool supports_cookies_with_info = true; | |
358 static const bool supports_non_dotted_domains = true; | |
359 static const bool supports_trailing_dots = true; | |
360 static const bool filters_schemes = true; | |
361 static const bool has_path_prefix_bug = false; | |
362 static const int creation_time_granularity_in_ms = 0; | |
363 }; | |
364 | |
365 INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster, | |
366 CookieStoreTest, | |
367 CookieMonsterTestTraits); | |
368 | |
369 INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster, | |
370 MultiThreadedCookieStoreTest, | |
371 CookieMonsterTestTraits); | |
372 | |
373 class CookieMonsterTest : public CookieStoreTest<CookieMonsterTestTraits> { | |
374 protected: | |
375 | |
376 CookieList GetAllCookies(CookieMonster* cm) { | |
377 DCHECK(cm); | |
378 GetCookieListCallback callback; | |
379 cm->GetAllCookiesAsync( | |
380 base::Bind(&GetCookieListCallback::Run, | |
381 base::Unretained(&callback))); | |
382 RunFor(kTimeout); | |
383 EXPECT_TRUE(callback.did_run()); | |
384 return callback.cookies(); | |
385 } | |
386 | |
387 CookieList GetAllCookiesForURL(CookieMonster* cm, | |
388 const GURL& url) { | |
389 DCHECK(cm); | |
390 GetCookieListCallback callback; | |
391 cm->GetAllCookiesForURLAsync( | |
392 url, base::Bind(&GetCookieListCallback::Run, | |
393 base::Unretained(&callback))); | |
394 RunFor(kTimeout); | |
395 EXPECT_TRUE(callback.did_run()); | |
396 return callback.cookies(); | |
397 } | |
398 | |
399 CookieList GetAllCookiesForURLWithOptions(CookieMonster* cm, | |
400 const GURL& url, | |
401 const CookieOptions& options) { | |
402 DCHECK(cm); | |
403 GetCookieListCallback callback; | |
404 cm->GetAllCookiesForURLWithOptionsAsync( | |
405 url, options, base::Bind(&GetCookieListCallback::Run, | |
406 base::Unretained(&callback))); | |
407 RunFor(kTimeout); | |
408 EXPECT_TRUE(callback.did_run()); | |
409 return callback.cookies(); | |
410 } | |
411 | |
412 bool SetCookieWithDetails(CookieMonster* cm, | |
413 const GURL& url, | |
414 const std::string& name, | |
415 const std::string& value, | |
416 const std::string& domain, | |
417 const std::string& path, | |
418 const base::Time& expiration_time, | |
419 bool secure, bool http_only) { | |
420 DCHECK(cm); | |
421 SetCookieCallback callback; | |
422 cm->SetCookieWithDetailsAsync( | |
423 url, name, value, domain, path, expiration_time, secure, http_only, | |
424 base::Bind(&SetCookieCallback::Run, base::Unretained(&callback))); | |
425 RunFor(kTimeout); | |
426 EXPECT_TRUE(callback.did_run()); | |
427 return callback.result(); | |
428 } | |
429 | |
430 int DeleteAll(CookieMonster*cm) { | |
431 DCHECK(cm); | |
432 DeleteCallback callback; | |
433 cm->DeleteAllAsync( | |
434 base::Bind(&DeleteCallback::Run, base::Unretained(&callback))); | |
435 RunFor(kTimeout); | |
436 EXPECT_TRUE(callback.did_run()); | |
437 return callback.num_deleted(); | |
438 } | |
439 | |
440 int DeleteAllCreatedBetween(CookieMonster*cm, | |
441 const base::Time& delete_begin, | |
442 const base::Time& delete_end) { | |
443 DCHECK(cm); | |
444 DeleteCallback callback; | |
445 cm->DeleteAllCreatedBetweenAsync( | |
446 delete_begin, delete_end, | |
447 base::Bind(&DeleteCallback::Run, base::Unretained(&callback))); | |
448 RunFor(kTimeout); | |
449 EXPECT_TRUE(callback.did_run()); | |
450 return callback.num_deleted(); | |
451 } | |
452 | |
453 int DeleteAllForHost(CookieMonster*cm, | |
454 const GURL& url) { | |
455 DCHECK(cm); | |
456 DeleteCallback callback; | |
457 cm->DeleteAllForHostAsync( | |
458 url, base::Bind(&DeleteCallback::Run, base::Unretained(&callback))); | |
459 RunFor(kTimeout); | |
460 EXPECT_TRUE(callback.did_run()); | |
461 return callback.num_deleted(); | |
462 } | |
463 | |
464 bool DeleteCanonicalCookie(CookieMonster*cm, | |
465 const CookieMonster::CanonicalCookie& cookie) { | |
466 DCHECK(cm); | |
467 SetCookieCallback callback; | |
468 cm->DeleteCanonicalCookieAsync( | |
469 cookie, | |
470 base::Bind(&SetCookieCallback::Run, base::Unretained(&callback))); | |
471 RunFor(kTimeout); | |
472 EXPECT_TRUE(callback.did_run()); | |
473 return callback.result(); | |
474 } | |
475 | |
476 // Helper for DeleteAllForHost test; repopulates CM with same layout | |
477 // each time. | |
478 void PopulateCmForDeleteAllForHost(scoped_refptr<CookieMonster> cm) { | |
479 GURL url_top_level_domain_plus_1(kTopLevelDomainPlus1); | |
480 GURL url_top_level_domain_plus_2(kTopLevelDomainPlus2); | |
481 GURL url_top_level_domain_plus_2_secure(kTopLevelDomainPlus2Secure); | |
482 GURL url_top_level_domain_plus_3(kTopLevelDomainPlus3); | |
483 GURL url_other(kOtherDomain); | |
484 | |
485 DeleteAll(cm); | |
486 | |
487 // Static population for probe: | |
488 // * Three levels of domain cookie (.b.a, .c.b.a, .d.c.b.a) | |
489 // * Three levels of host cookie (w.b.a, w.c.b.a, w.d.c.b.a) | |
490 // * http_only cookie (w.c.b.a) | |
491 // * Two secure cookies (.c.b.a, w.c.b.a) | |
492 // * Two domain path cookies (.c.b.a/dir1, .c.b.a/dir1/dir2) | |
493 // * Two host path cookies (w.c.b.a/dir1, w.c.b.a/dir1/dir2) | |
494 | |
495 // Domain cookies | |
496 EXPECT_TRUE(this->SetCookieWithDetails(cm, url_top_level_domain_plus_1, | |
497 "dom_1", "X", ".harvard.edu", "/", | |
498 base::Time(), false, false)); | |
499 EXPECT_TRUE(this->SetCookieWithDetails(cm, url_top_level_domain_plus_2, | |
500 "dom_2", "X", ".math.harvard.edu", | |
501 "/", base::Time(), false, false)); | |
502 EXPECT_TRUE(this->SetCookieWithDetails(cm, url_top_level_domain_plus_3, | |
503 "dom_3", "X", | |
504 ".bourbaki.math.harvard.edu", "/", | |
505 base::Time(), false, false)); | |
506 | |
507 // Host cookies | |
508 EXPECT_TRUE(this->SetCookieWithDetails(cm, url_top_level_domain_plus_1, | |
509 "host_1", "X", "", "/", | |
510 base::Time(), false, false)); | |
511 EXPECT_TRUE(this->SetCookieWithDetails(cm, url_top_level_domain_plus_2, | |
512 "host_2", "X", "", "/", | |
513 base::Time(), false, false)); | |
514 EXPECT_TRUE(this->SetCookieWithDetails(cm, url_top_level_domain_plus_3, | |
515 "host_3", "X", "", "/", | |
516 base::Time(), false, false)); | |
517 | |
518 // Http_only cookie | |
519 EXPECT_TRUE(this->SetCookieWithDetails(cm, url_top_level_domain_plus_2, | |
520 "httpo_check", "X", "", "/", | |
521 base::Time(), false, true)); | |
522 | |
523 // Secure cookies | |
524 EXPECT_TRUE(this->SetCookieWithDetails(cm, | |
525 url_top_level_domain_plus_2_secure, | |
526 "sec_dom", "X", ".math.harvard.edu", | |
527 "/", base::Time(), true, false)); | |
528 EXPECT_TRUE(this->SetCookieWithDetails(cm, | |
529 url_top_level_domain_plus_2_secure, | |
530 "sec_host", "X", "", "/", | |
531 base::Time(), true, false)); | |
532 | |
533 // Domain path cookies | |
534 EXPECT_TRUE(this->SetCookieWithDetails(cm, url_top_level_domain_plus_2, | |
535 "dom_path_1", "X", | |
536 ".math.harvard.edu", "/dir1", | |
537 base::Time(), false, false)); | |
538 EXPECT_TRUE(this->SetCookieWithDetails(cm, url_top_level_domain_plus_2, | |
539 "dom_path_2", "X", | |
540 ".math.harvard.edu", "/dir1/dir2", | |
541 base::Time(), false, false)); | |
542 | |
543 // Host path cookies | |
544 EXPECT_TRUE(this->SetCookieWithDetails(cm, url_top_level_domain_plus_2, | |
545 "host_path_1", "X", | |
546 "", "/dir1", | |
547 base::Time(), false, false)); | |
548 EXPECT_TRUE(this->SetCookieWithDetails(cm, url_top_level_domain_plus_2, | |
549 "host_path_2", "X", | |
550 "", "/dir1/dir2", | |
551 base::Time(), false, false)); | |
552 | |
553 EXPECT_EQ(13U, this->GetAllCookies(cm).size()); | |
554 } | |
555 | |
556 Time GetFirstCookieAccessDate(CookieMonster* cm) { | |
557 const CookieList all_cookies(this->GetAllCookies(cm)); | |
558 return all_cookies.front().LastAccessDate(); | |
559 } | |
560 | |
561 bool FindAndDeleteCookie(CookieMonster* cm, | |
562 const std::string& domain, | |
563 const std::string& name) { | |
564 CookieList cookies = this->GetAllCookies(cm); | |
565 for (CookieList::iterator it = cookies.begin(); | |
566 it != cookies.end(); ++it) | |
567 if (it->Domain() == domain && it->Name() == name) | |
568 return this->DeleteCanonicalCookie(cm, *it); | |
569 return false; | |
570 } | |
571 | |
572 int CountInString(const std::string& str, char c) { | |
573 return std::count(str.begin(), str.end(), c); | |
574 } | |
575 | |
576 void TestHostGarbageCollectHelper( | |
577 int domain_max_cookies, | |
578 int domain_purge_cookies) { | |
579 const int more_than_enough_cookies = | |
580 (domain_max_cookies + domain_purge_cookies) * 2; | |
581 // Add a bunch of cookies on a single host, should purge them. | |
582 { | |
583 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
584 for (int i = 0; i < more_than_enough_cookies; ++i) { | |
585 std::string cookie = base::StringPrintf("a%03d=b", i); | |
586 EXPECT_TRUE(SetCookie(cm, url_google_, cookie)); | |
587 std::string cookies = this->GetCookies(cm, url_google_); | |
588 // Make sure we find it in the cookies. | |
589 EXPECT_NE(cookies.find(cookie), std::string::npos); | |
590 // Count the number of cookies. | |
591 EXPECT_LE(CountInString(cookies, '='), domain_max_cookies); | |
592 } | |
593 } | |
594 | |
595 // Add a bunch of cookies on multiple hosts within a single eTLD. | |
596 // Should keep at least kDomainMaxCookies - kDomainPurgeCookies | |
597 // between them. We shouldn't go above kDomainMaxCookies for both together. | |
598 GURL url_google_specific(kUrlGoogleSpecific); | |
599 { | |
600 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
601 for (int i = 0; i < more_than_enough_cookies; ++i) { | |
602 std::string cookie_general = base::StringPrintf("a%03d=b", i); | |
603 EXPECT_TRUE(SetCookie(cm, url_google_, cookie_general)); | |
604 std::string cookie_specific = base::StringPrintf("c%03d=b", i); | |
605 EXPECT_TRUE(SetCookie(cm, url_google_specific, cookie_specific)); | |
606 std::string cookies_general = this->GetCookies(cm, url_google_); | |
607 EXPECT_NE(cookies_general.find(cookie_general), std::string::npos); | |
608 std::string cookies_specific = | |
609 this->GetCookies(cm, url_google_specific); | |
610 EXPECT_NE(cookies_specific.find(cookie_specific), std::string::npos); | |
611 EXPECT_LE((CountInString(cookies_general, '=') + | |
612 CountInString(cookies_specific, '=')), | |
613 domain_max_cookies); | |
614 } | |
615 // After all this, there should be at least | |
616 // kDomainMaxCookies - kDomainPurgeCookies for both URLs. | |
617 std::string cookies_general = this->GetCookies(cm, url_google_); | |
618 std::string cookies_specific = this->GetCookies(cm, url_google_specific); | |
619 int total_cookies = (CountInString(cookies_general, '=') + | |
620 CountInString(cookies_specific, '=')); | |
621 EXPECT_GE(total_cookies, | |
622 domain_max_cookies - domain_purge_cookies); | |
623 EXPECT_LE(total_cookies, domain_max_cookies); | |
624 } | |
625 } | |
626 | |
627 // Function for creating a CM with a number of cookies in it, | |
628 // no store (and hence no ability to affect access time). | |
629 CookieMonster* CreateMonsterForGC(int num_cookies) { | |
630 CookieMonster* cm(new CookieMonster(NULL, NULL)); | |
631 for (int i = 0; i < num_cookies; i++) { | |
632 SetCookie(cm, GURL(StringPrintf("http://h%05d.izzle", i)), "a=1"); | |
633 } | |
634 return cm; | |
635 } | |
636 }; | |
637 | |
638 // TODO(erikwright): Replace the other callbacks and synchronous helper methods | |
639 // in this test suite with these Mocks. | |
640 template<typename T, typename C> class MockCookieCallback { | |
641 public: | |
642 C AsCallback() { | |
643 return base::Bind(&T::Invoke, base::Unretained(static_cast<T*>(this))); | |
644 } | |
645 }; | |
646 | |
647 class MockGetCookiesCallback | |
648 : public MockCookieCallback<MockGetCookiesCallback, | |
649 CookieStore::GetCookiesCallback> { | |
650 public: | |
651 MOCK_METHOD1(Invoke, void(const std::string& cookies)); | |
652 }; | |
653 | |
654 class MockGetCookieInfoCallback | |
655 : public MockCookieCallback<MockGetCookieInfoCallback, | |
656 CookieStore::GetCookieInfoCallback> { | |
657 public: | |
658 MOCK_METHOD2(Invoke, | |
659 void(const std::string& cookies, | |
660 const std::vector<CookieStore::CookieInfo>& cookie_infos)); | |
661 }; | |
662 | |
663 class MockSetCookiesCallback | |
664 : public MockCookieCallback<MockSetCookiesCallback, | |
665 CookieStore::SetCookiesCallback> { | |
666 public: | |
667 MOCK_METHOD1(Invoke, void(bool success)); | |
668 }; | |
669 | |
670 class MockClosure | |
671 : public MockCookieCallback<MockClosure, base::Closure> { | |
672 public: | |
673 MOCK_METHOD0(Invoke, void(void)); | |
674 }; | |
675 | |
676 class MockGetCookieListCallback | |
677 : public MockCookieCallback<MockGetCookieListCallback, | |
678 CookieMonster::GetCookieListCallback> { | |
679 public: | |
680 MOCK_METHOD1(Invoke, void(const CookieList& cookies)); | |
681 }; | |
682 | |
683 class MockDeleteCallback | |
684 : public MockCookieCallback<MockDeleteCallback, | |
685 CookieMonster::DeleteCallback> { | |
686 public: | |
687 MOCK_METHOD1(Invoke, void(int num_deleted)); | |
688 }; | |
689 | |
690 class MockDeleteCookieCallback | |
691 : public MockCookieCallback<MockDeleteCookieCallback, | |
692 CookieMonster::DeleteCookieCallback> { | |
693 public: | |
694 MOCK_METHOD1(Invoke, void(bool success)); | |
695 }; | |
696 | |
697 ACTION(QuitCurrentMessageLoop) { | |
698 MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure()); | |
699 } | |
700 | |
701 // TODO(erikwright): When the synchronous helpers 'GetCookies' etc. are removed, | |
702 // rename these, removing the 'Action' suffix. | |
703 ACTION_P4(DeleteCookieAction, cookie_monster, url, name, callback) { | |
704 cookie_monster->DeleteCookieAsync(url, name, callback->AsCallback()); | |
705 } | |
706 ACTION_P3(GetCookiesAction, cookie_monster, url, callback) { | |
707 cookie_monster->GetCookiesWithOptionsAsync( | |
708 url, CookieOptions(), callback->AsCallback()); | |
709 } | |
710 ACTION_P3(GetCookiesWithInfoAction, cookie_monster, url, callback) { | |
711 cookie_monster->GetCookiesWithInfoAsync( | |
712 url, CookieOptions(), callback->AsCallback()); | |
713 } | |
714 ACTION_P4(SetCookieAction, cookie_monster, url, cookie_line, callback) { | |
715 cookie_monster->SetCookieWithOptionsAsync( | |
716 url, cookie_line, CookieOptions(), callback->AsCallback()); | |
717 } | |
718 ACTION_P4(DeleteAllCreatedBetweenAction, | |
719 cookie_monster, delete_begin, delete_end, callback) { | |
720 cookie_monster->DeleteAllCreatedBetweenAsync( | |
721 delete_begin, delete_end, callback->AsCallback()); | |
722 } | |
723 ACTION_P10(SetCookieWithDetailsAction, | |
724 cookie_monster, url, name, value, domain, path, expiration_time, | |
725 secure, http_only, callback) { | |
726 cookie_monster->SetCookieWithDetailsAsync( | |
727 url, name, value, domain, path, expiration_time, secure, http_only, | |
728 callback->AsCallback()); | |
729 } | |
730 | |
731 ACTION_P2(GetAllCookiesAction, cookie_monster, callback) { | |
732 cookie_monster->GetAllCookiesAsync(callback->AsCallback()); | |
733 } | |
734 | |
735 ACTION_P3(DeleteAllForHostAction, cookie_monster, url, callback) { | |
736 cookie_monster->DeleteAllForHostAsync(url, callback->AsCallback()); | |
737 } | |
738 | |
739 ACTION_P3(DeleteCanonicalCookieAction, cookie_monster, cookie, callback) { | |
740 cookie_monster->DeleteCanonicalCookieAsync(cookie, callback->AsCallback()); | |
741 } | |
742 | |
743 ACTION_P2(DeleteAllAction, cookie_monster, callback) { | |
744 cookie_monster->DeleteAllAsync(callback->AsCallback()); | |
745 } | |
746 | |
747 ACTION_P3(GetAllCookiesForUrlWithOptionsAction, cookie_monster, url, callback) { | |
748 cookie_monster->GetAllCookiesForURLWithOptionsAsync( | |
749 url, CookieOptions(), callback->AsCallback()); | |
750 } | |
751 | |
752 ACTION_P3(GetAllCookiesForUrlAction, cookie_monster, url, callback) { | |
753 cookie_monster->GetAllCookiesForURLAsync(url, callback->AsCallback()); | |
754 } | |
755 | |
756 ACTION_P(PushCallbackAction, callback_vector) { | |
757 callback_vector->push(arg1); | |
758 } | |
759 | |
760 } // namespace | |
761 | |
762 // This test suite verifies the task deferral behaviour of the CookieMonster. | |
763 // Specifically, for each asynchronous method, verify that: | |
764 // 1. invoking it on an uninitialized cookie store causes the store to begin | |
765 // chain-loading its backing data or loading data for a specific domain key | |
766 // (eTLD+1). | |
767 // 2. The initial invocation does not complete until the loading completes. | |
768 // 3. Invocations after the loading has completed complete immediately. | |
769 class DeferredCookieTaskTest : public CookieMonsterTest { | |
770 protected: | |
771 DeferredCookieTaskTest() { | |
772 persistent_store_ = new NewMockPersistentCookieStore(); | |
773 cookie_monster_ = new CookieMonster(persistent_store_.get(), NULL); | |
774 } | |
775 | |
776 // Defines a cookie to be returned from PersistentCookieStore::Load | |
777 void DeclareLoadedCookie(const std::string& key, | |
778 const std::string& cookie_line, | |
779 const base::Time& creation_time) { | |
780 AddCookieToList(key, cookie_line, creation_time, &loaded_cookies_); | |
781 } | |
782 | |
783 // Runs the message loop, waiting until PersistentCookieStore::Load is called. | |
784 // Call CompleteLoadingAndWait to cause the load to complete. | |
785 void WaitForLoadCall() { | |
786 RunFor(kTimeout); | |
787 | |
788 // Verify that PeristentStore::Load was called. | |
789 testing::Mock::VerifyAndClear(persistent_store_.get()); | |
790 } | |
791 | |
792 // Invokes the PersistentCookieStore::LoadCookiesForKey completion callbacks | |
793 // and PersistentCookieStore::Load completion callback and waits | |
794 // until the message loop is quit. | |
795 void CompleteLoadingAndWait() { | |
796 while (!loaded_for_key_callbacks_.empty()) { | |
797 loaded_for_key_callbacks_.front().Run(loaded_cookies_); | |
798 loaded_cookies_.clear(); | |
799 loaded_for_key_callbacks_.pop(); | |
800 } | |
801 | |
802 loaded_callback_.Run(loaded_cookies_); | |
803 RunFor(kTimeout); | |
804 } | |
805 | |
806 // Performs the provided action, expecting it to cause a call to | |
807 // PersistentCookieStore::Load. Call WaitForLoadCall to verify the load call | |
808 // is received. | |
809 void BeginWith(testing::Action<void(void)> action) { | |
810 EXPECT_CALL(*this, Begin()).WillOnce(action); | |
811 ExpectLoadCall(); | |
812 Begin(); | |
813 } | |
814 | |
815 void BeginWithForDomainKey(std::string key, | |
816 testing::Action<void(void)> action) { | |
817 EXPECT_CALL(*this, Begin()).WillOnce(action); | |
818 ExpectLoadCall(); | |
819 ExpectLoadForKeyCall(key, false); | |
820 Begin(); | |
821 } | |
822 | |
823 // Declares an expectation that PersistentCookieStore::Load will be called, | |
824 // saving the provided callback and sending a quit to the message loop. | |
825 void ExpectLoadCall() { | |
826 EXPECT_CALL(*persistent_store_, Load(testing::_)).WillOnce(testing::DoAll( | |
827 testing::SaveArg<0>(&loaded_callback_), | |
828 QuitCurrentMessageLoop())); | |
829 } | |
830 | |
831 // Declares an expectation that PersistentCookieStore::LoadCookiesForKey | |
832 // will be called, saving the provided callback and sending a quit to the | |
833 // message loop. | |
834 void ExpectLoadForKeyCall(std::string key, bool quit_queue) { | |
835 if (quit_queue) | |
836 EXPECT_CALL(*persistent_store_, LoadCookiesForKey(key, testing::_)). | |
837 WillOnce(testing::DoAll( | |
838 PushCallbackAction(&loaded_for_key_callbacks_), | |
839 QuitCurrentMessageLoop())); | |
840 else | |
841 EXPECT_CALL(*persistent_store_, LoadCookiesForKey(key, testing::_)). | |
842 WillOnce(PushCallbackAction(&loaded_for_key_callbacks_)); | |
843 } | |
844 | |
845 // Invokes the initial action. | |
846 MOCK_METHOD0(Begin, void(void)); | |
847 | |
848 // Returns the CookieMonster instance under test. | |
849 CookieMonster& cookie_monster() { return *cookie_monster_; } | |
850 | |
851 private: | |
852 // Declares that mock expectations in this test suite are strictly ordered. | |
853 testing::InSequence in_sequence_; | |
854 // Holds cookies to be returned from PersistentCookieStore::Load or | |
855 // PersistentCookieStore::LoadCookiesForKey. | |
856 std::vector<CookieMonster::CanonicalCookie*> loaded_cookies_; | |
857 // Stores the callback passed from the CookieMonster to the | |
858 // PersistentCookieStore::Load | |
859 CookieMonster::PersistentCookieStore::LoadedCallback loaded_callback_; | |
860 // Stores the callback passed from the CookieMonster to the | |
861 // PersistentCookieStore::LoadCookiesForKey | |
862 std::queue<CookieMonster::PersistentCookieStore::LoadedCallback> | |
863 loaded_for_key_callbacks_; | |
864 | |
865 // Stores the CookieMonster under test. | |
866 scoped_refptr<CookieMonster> cookie_monster_; | |
867 // Stores the mock PersistentCookieStore. | |
868 scoped_refptr<NewMockPersistentCookieStore> persistent_store_; | |
869 }; | |
870 | |
871 TEST_F(DeferredCookieTaskTest, DeferredGetCookies) { | |
872 DeclareLoadedCookie("www.google.izzle", | |
873 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
874 Time::Now() + TimeDelta::FromDays(3)); | |
875 | |
876 MockGetCookiesCallback get_cookies_callback; | |
877 | |
878 BeginWithForDomainKey("google.izzle", GetCookiesAction( | |
879 &cookie_monster(), url_google_, &get_cookies_callback)); | |
880 | |
881 WaitForLoadCall(); | |
882 | |
883 EXPECT_CALL(get_cookies_callback, Invoke("X=1")).WillOnce( | |
884 GetCookiesAction(&cookie_monster(), url_google_, &get_cookies_callback)); | |
885 EXPECT_CALL(get_cookies_callback, Invoke("X=1")).WillOnce( | |
886 QuitCurrentMessageLoop()); | |
887 | |
888 CompleteLoadingAndWait(); | |
889 } | |
890 | |
891 TEST_F(DeferredCookieTaskTest, DeferredGetCookiesWithInfo) { | |
892 DeclareLoadedCookie("www.google.izzle", | |
893 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
894 Time::Now() + TimeDelta::FromDays(3)); | |
895 | |
896 MockGetCookieInfoCallback get_cookie_info_callback; | |
897 | |
898 BeginWithForDomainKey("google.izzle", GetCookiesWithInfoAction( | |
899 &cookie_monster(), url_google_, &get_cookie_info_callback)); | |
900 | |
901 WaitForLoadCall(); | |
902 | |
903 EXPECT_CALL(get_cookie_info_callback, Invoke("X=1", testing::_)).WillOnce( | |
904 GetCookiesWithInfoAction( | |
905 &cookie_monster(), url_google_, &get_cookie_info_callback)); | |
906 EXPECT_CALL(get_cookie_info_callback, Invoke("X=1", testing::_)).WillOnce( | |
907 QuitCurrentMessageLoop()); | |
908 | |
909 CompleteLoadingAndWait(); | |
910 } | |
911 | |
912 TEST_F(DeferredCookieTaskTest, DeferredSetCookie) { | |
913 MockSetCookiesCallback set_cookies_callback; | |
914 | |
915 BeginWithForDomainKey("google.izzle", SetCookieAction( | |
916 &cookie_monster(), url_google_, "A=B", &set_cookies_callback)); | |
917 | |
918 WaitForLoadCall(); | |
919 | |
920 EXPECT_CALL(set_cookies_callback, Invoke(true)).WillOnce( | |
921 SetCookieAction( | |
922 &cookie_monster(), url_google_, "X=Y", &set_cookies_callback)); | |
923 EXPECT_CALL(set_cookies_callback, Invoke(true)).WillOnce( | |
924 QuitCurrentMessageLoop()); | |
925 | |
926 CompleteLoadingAndWait(); | |
927 } | |
928 | |
929 TEST_F(DeferredCookieTaskTest, DeferredDeleteCookie) { | |
930 MockClosure delete_cookie_callback; | |
931 | |
932 BeginWithForDomainKey("google.izzle", DeleteCookieAction( | |
933 &cookie_monster(), url_google_, "A", &delete_cookie_callback)); | |
934 | |
935 WaitForLoadCall(); | |
936 | |
937 EXPECT_CALL(delete_cookie_callback, Invoke()).WillOnce( | |
938 DeleteCookieAction( | |
939 &cookie_monster(), url_google_, "X", &delete_cookie_callback)); | |
940 EXPECT_CALL(delete_cookie_callback, Invoke()).WillOnce( | |
941 QuitCurrentMessageLoop()); | |
942 | |
943 CompleteLoadingAndWait(); | |
944 } | |
945 | |
946 TEST_F(DeferredCookieTaskTest, DeferredSetCookieWithDetails) { | |
947 MockSetCookiesCallback set_cookies_callback; | |
948 | |
949 BeginWithForDomainKey("google.izzle", SetCookieWithDetailsAction( | |
950 &cookie_monster(), url_google_foo_, "A", "B", std::string(), "/foo", | |
951 base::Time(), false, false, &set_cookies_callback)); | |
952 | |
953 WaitForLoadCall(); | |
954 | |
955 EXPECT_CALL(set_cookies_callback, Invoke(true)).WillOnce( | |
956 SetCookieWithDetailsAction( | |
957 &cookie_monster(), url_google_foo_, "A", "B", std::string(), "/foo", | |
958 base::Time(), false, false, &set_cookies_callback)); | |
959 EXPECT_CALL(set_cookies_callback, Invoke(true)).WillOnce( | |
960 QuitCurrentMessageLoop()); | |
961 | |
962 CompleteLoadingAndWait(); | |
963 } | |
964 | |
965 TEST_F(DeferredCookieTaskTest, DeferredGetAllCookies) { | |
966 DeclareLoadedCookie("www.google.izzle", | |
967 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
968 Time::Now() + TimeDelta::FromDays(3)); | |
969 | |
970 MockGetCookieListCallback get_cookie_list_callback; | |
971 | |
972 BeginWith(GetAllCookiesAction( | |
973 &cookie_monster(), &get_cookie_list_callback)); | |
974 | |
975 WaitForLoadCall(); | |
976 | |
977 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce( | |
978 GetAllCookiesAction(&cookie_monster(), &get_cookie_list_callback)); | |
979 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce( | |
980 QuitCurrentMessageLoop()); | |
981 | |
982 CompleteLoadingAndWait(); | |
983 } | |
984 | |
985 TEST_F(DeferredCookieTaskTest, DeferredGetAllForUrlCookies) { | |
986 DeclareLoadedCookie("www.google.izzle", | |
987 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
988 Time::Now() + TimeDelta::FromDays(3)); | |
989 | |
990 MockGetCookieListCallback get_cookie_list_callback; | |
991 | |
992 BeginWithForDomainKey("google.izzle", GetAllCookiesForUrlAction( | |
993 &cookie_monster(), url_google_, &get_cookie_list_callback)); | |
994 | |
995 WaitForLoadCall(); | |
996 | |
997 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce( | |
998 GetAllCookiesForUrlAction( | |
999 &cookie_monster(), url_google_, &get_cookie_list_callback)); | |
1000 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce( | |
1001 QuitCurrentMessageLoop()); | |
1002 | |
1003 CompleteLoadingAndWait(); | |
1004 } | |
1005 | |
1006 TEST_F(DeferredCookieTaskTest, DeferredGetAllForUrlWithOptionsCookies) { | |
1007 DeclareLoadedCookie("www.google.izzle", | |
1008 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
1009 Time::Now() + TimeDelta::FromDays(3)); | |
1010 | |
1011 MockGetCookieListCallback get_cookie_list_callback; | |
1012 | |
1013 BeginWithForDomainKey("google.izzle", GetAllCookiesForUrlWithOptionsAction( | |
1014 &cookie_monster(), url_google_, &get_cookie_list_callback)); | |
1015 | |
1016 WaitForLoadCall(); | |
1017 | |
1018 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce( | |
1019 GetAllCookiesForUrlWithOptionsAction( | |
1020 &cookie_monster(), url_google_, &get_cookie_list_callback)); | |
1021 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce( | |
1022 QuitCurrentMessageLoop()); | |
1023 | |
1024 CompleteLoadingAndWait(); | |
1025 } | |
1026 | |
1027 TEST_F(DeferredCookieTaskTest, DeferredDeleteAllCookies) { | |
1028 MockDeleteCallback delete_callback; | |
1029 | |
1030 BeginWith(DeleteAllAction( | |
1031 &cookie_monster(), &delete_callback)); | |
1032 | |
1033 WaitForLoadCall(); | |
1034 | |
1035 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce( | |
1036 DeleteAllAction(&cookie_monster(), &delete_callback)); | |
1037 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce( | |
1038 QuitCurrentMessageLoop()); | |
1039 | |
1040 CompleteLoadingAndWait(); | |
1041 } | |
1042 | |
1043 TEST_F(DeferredCookieTaskTest, DeferredDeleteAllCreatedBetweenCookies) { | |
1044 MockDeleteCallback delete_callback; | |
1045 | |
1046 BeginWith(DeleteAllCreatedBetweenAction( | |
1047 &cookie_monster(), base::Time(), base::Time::Now(), &delete_callback)); | |
1048 | |
1049 WaitForLoadCall(); | |
1050 | |
1051 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce( | |
1052 DeleteAllCreatedBetweenAction( | |
1053 &cookie_monster(), base::Time(), base::Time::Now(), | |
1054 &delete_callback)); | |
1055 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce( | |
1056 QuitCurrentMessageLoop()); | |
1057 | |
1058 CompleteLoadingAndWait(); | |
1059 } | |
1060 | |
1061 TEST_F(DeferredCookieTaskTest, DeferredDeleteAllForHostCookies) { | |
1062 MockDeleteCallback delete_callback; | |
1063 | |
1064 BeginWithForDomainKey("google.izzle", DeleteAllForHostAction( | |
1065 &cookie_monster(), url_google_, &delete_callback)); | |
1066 | |
1067 WaitForLoadCall(); | |
1068 | |
1069 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce( | |
1070 DeleteAllForHostAction( | |
1071 &cookie_monster(), url_google_, &delete_callback)); | |
1072 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce( | |
1073 QuitCurrentMessageLoop()); | |
1074 | |
1075 CompleteLoadingAndWait(); | |
1076 } | |
1077 | |
1078 TEST_F(DeferredCookieTaskTest, DeferredDeleteCanonicalCookie) { | |
1079 std::vector<CookieMonster::CanonicalCookie*> cookies; | |
1080 CookieMonster::CanonicalCookie cookie = BuildCanonicalCookie( | |
1081 "www.google.com", "X=1; path=/", base::Time::Now()); | |
1082 | |
1083 MockDeleteCookieCallback delete_cookie_callback; | |
1084 | |
1085 BeginWith(DeleteCanonicalCookieAction( | |
1086 &cookie_monster(), cookie, &delete_cookie_callback)); | |
1087 | |
1088 WaitForLoadCall(); | |
1089 | |
1090 EXPECT_CALL(delete_cookie_callback, Invoke(false)).WillOnce( | |
1091 DeleteCanonicalCookieAction( | |
1092 &cookie_monster(), cookie, &delete_cookie_callback)); | |
1093 EXPECT_CALL(delete_cookie_callback, Invoke(false)).WillOnce( | |
1094 QuitCurrentMessageLoop()); | |
1095 | |
1096 CompleteLoadingAndWait(); | |
1097 } | |
1098 | |
1099 // Verify that a series of queued tasks are executed in order upon loading of | |
1100 // the backing store and that new tasks received while the queued tasks are | |
1101 // being dispatched go to the end of the queue. | |
1102 TEST_F(DeferredCookieTaskTest, DeferredTaskOrder) { | |
1103 DeclareLoadedCookie("www.google.izzle", | |
1104 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
1105 Time::Now() + TimeDelta::FromDays(3)); | |
1106 | |
1107 MockGetCookiesCallback get_cookies_callback; | |
1108 MockSetCookiesCallback set_cookies_callback; | |
1109 MockClosure delete_cookie_callback; | |
1110 MockGetCookieInfoCallback get_cookie_info_callback; | |
1111 | |
1112 EXPECT_CALL(*this, Begin()).WillOnce(testing::DoAll( | |
1113 GetCookiesAction( | |
1114 &cookie_monster(), url_google_, &get_cookies_callback), | |
1115 SetCookieAction( | |
1116 &cookie_monster(), url_google_, "A=B", &set_cookies_callback), | |
1117 DeleteCookieAction( | |
1118 &cookie_monster(), url_google_, "A", &delete_cookie_callback))); | |
1119 ExpectLoadCall(); | |
1120 ExpectLoadForKeyCall("google.izzle", false); | |
1121 Begin(); | |
1122 | |
1123 WaitForLoadCall(); | |
1124 EXPECT_CALL(get_cookies_callback, Invoke("X=1")).WillOnce( | |
1125 GetCookiesWithInfoAction( | |
1126 &cookie_monster(), url_google_, &get_cookie_info_callback)); | |
1127 EXPECT_CALL(get_cookie_info_callback, Invoke("X=1", testing::_)).WillOnce( | |
1128 QuitCurrentMessageLoop()); | |
1129 EXPECT_CALL(set_cookies_callback, Invoke(true)); | |
1130 EXPECT_CALL(delete_cookie_callback, Invoke()); | |
1131 | |
1132 CompleteLoadingAndWait(); | |
1133 } | |
1134 | |
1135 TEST_F(CookieMonsterTest, TestCookieDateParsing) { | |
1136 const struct { | |
1137 const char* str; | |
1138 const bool valid; | |
1139 const time_t epoch; | |
1140 } tests[] = { | |
1141 { "Sat, 15-Apr-17 21:01:22 GMT", true, 1492290082 }, | |
1142 { "Thu, 19-Apr-2007 16:00:00 GMT", true, 1176998400 }, | |
1143 { "Wed, 25 Apr 2007 21:02:13 GMT", true, 1177534933 }, | |
1144 { "Thu, 19/Apr\\2007 16:00:00 GMT", true, 1176998400 }, | |
1145 { "Fri, 1 Jan 2010 01:01:50 GMT", true, 1262307710 }, | |
1146 { "Wednesday, 1-Jan-2003 00:00:00 GMT", true, 1041379200 }, | |
1147 { ", 1-Jan-2003 00:00:00 GMT", true, 1041379200 }, | |
1148 { " 1-Jan-2003 00:00:00 GMT", true, 1041379200 }, | |
1149 { "1-Jan-2003 00:00:00 GMT", true, 1041379200 }, | |
1150 { "Wed,18-Apr-07 22:50:12 GMT", true, 1176936612 }, | |
1151 { "WillyWonka , 18-Apr-07 22:50:12 GMT", true, 1176936612 }, | |
1152 { "WillyWonka , 18-Apr-07 22:50:12", true, 1176936612 }, | |
1153 { "WillyWonka , 18-apr-07 22:50:12", true, 1176936612 }, | |
1154 { "Mon, 18-Apr-1977 22:50:13 GMT", true, 230251813 }, | |
1155 { "Mon, 18-Apr-77 22:50:13 GMT", true, 230251813 }, | |
1156 // If the cookie came in with the expiration quoted (which in terms of | |
1157 // the RFC you shouldn't do), we will get string quoted. Bug 1261605. | |
1158 { "\"Sat, 15-Apr-17\\\"21:01:22\\\"GMT\"", true, 1492290082 }, | |
1159 // Test with full month names and partial names. | |
1160 { "Partyday, 18- April-07 22:50:12", true, 1176936612 }, | |
1161 { "Partyday, 18 - Apri-07 22:50:12", true, 1176936612 }, | |
1162 { "Wednes, 1-Januar-2003 00:00:00 GMT", true, 1041379200 }, | |
1163 // Test that we always take GMT even with other time zones or bogus | |
1164 // values. The RFC says everything should be GMT, and in the worst case | |
1165 // we are 24 hours off because of zone issues. | |
1166 { "Sat, 15-Apr-17 21:01:22", true, 1492290082 }, | |
1167 { "Sat, 15-Apr-17 21:01:22 GMT-2", true, 1492290082 }, | |
1168 { "Sat, 15-Apr-17 21:01:22 GMT BLAH", true, 1492290082 }, | |
1169 { "Sat, 15-Apr-17 21:01:22 GMT-0400", true, 1492290082 }, | |
1170 { "Sat, 15-Apr-17 21:01:22 GMT-0400 (EDT)",true, 1492290082 }, | |
1171 { "Sat, 15-Apr-17 21:01:22 DST", true, 1492290082 }, | |
1172 { "Sat, 15-Apr-17 21:01:22 -0400", true, 1492290082 }, | |
1173 { "Sat, 15-Apr-17 21:01:22 (hello there)", true, 1492290082 }, | |
1174 // Test that if we encounter multiple : fields, that we take the first | |
1175 // that correctly parses. | |
1176 { "Sat, 15-Apr-17 21:01:22 11:22:33", true, 1492290082 }, | |
1177 { "Sat, 15-Apr-17 ::00 21:01:22", true, 1492290082 }, | |
1178 { "Sat, 15-Apr-17 boink:z 21:01:22", true, 1492290082 }, | |
1179 // We take the first, which in this case is invalid. | |
1180 { "Sat, 15-Apr-17 91:22:33 21:01:22", false, 0 }, | |
1181 // amazon.com formats their cookie expiration like this. | |
1182 { "Thu Apr 18 22:50:12 2007 GMT", true, 1176936612 }, | |
1183 // Test that hh:mm:ss can occur anywhere. | |
1184 { "22:50:12 Thu Apr 18 2007 GMT", true, 1176936612 }, | |
1185 { "Thu 22:50:12 Apr 18 2007 GMT", true, 1176936612 }, | |
1186 { "Thu Apr 22:50:12 18 2007 GMT", true, 1176936612 }, | |
1187 { "Thu Apr 18 22:50:12 2007 GMT", true, 1176936612 }, | |
1188 { "Thu Apr 18 2007 22:50:12 GMT", true, 1176936612 }, | |
1189 { "Thu Apr 18 2007 GMT 22:50:12", true, 1176936612 }, | |
1190 // Test that the day and year can be anywhere if they are unambigious. | |
1191 { "Sat, 15-Apr-17 21:01:22 GMT", true, 1492290082 }, | |
1192 { "15-Sat, Apr-17 21:01:22 GMT", true, 1492290082 }, | |
1193 { "15-Sat, Apr 21:01:22 GMT 17", true, 1492290082 }, | |
1194 { "15-Sat, Apr 21:01:22 GMT 2017", true, 1492290082 }, | |
1195 { "15 Apr 21:01:22 2017", true, 1492290082 }, | |
1196 { "15 17 Apr 21:01:22", true, 1492290082 }, | |
1197 { "Apr 15 17 21:01:22", true, 1492290082 }, | |
1198 { "Apr 15 21:01:22 17", true, 1492290082 }, | |
1199 { "2017 April 15 21:01:22", true, 1492290082 }, | |
1200 { "15 April 2017 21:01:22", true, 1492290082 }, | |
1201 // Some invalid dates | |
1202 { "98 April 17 21:01:22", false, 0 }, | |
1203 { "Thu, 012-Aug-2008 20:49:07 GMT", false, 0 }, | |
1204 { "Thu, 12-Aug-31841 20:49:07 GMT", false, 0 }, | |
1205 { "Thu, 12-Aug-9999999999 20:49:07 GMT", false, 0 }, | |
1206 { "Thu, 999999999999-Aug-2007 20:49:07 GMT", false, 0 }, | |
1207 { "Thu, 12-Aug-2007 20:61:99999999999 GMT", false, 0 }, | |
1208 { "IAintNoDateFool", false, 0 }, | |
1209 }; | |
1210 | |
1211 Time parsed_time; | |
1212 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { | |
1213 parsed_time = CookieMonster::ParseCookieTime(tests[i].str); | |
1214 if (!tests[i].valid) { | |
1215 EXPECT_FALSE(!parsed_time.is_null()) << tests[i].str; | |
1216 continue; | |
1217 } | |
1218 EXPECT_TRUE(!parsed_time.is_null()) << tests[i].str; | |
1219 EXPECT_EQ(tests[i].epoch, parsed_time.ToTimeT()) << tests[i].str; | |
1220 } | |
1221 } | |
1222 | |
1223 TEST_F(CookieMonsterTest, TestCookieDeleteAll) { | |
1224 scoped_refptr<MockPersistentCookieStore> store( | |
1225 new MockPersistentCookieStore); | |
1226 scoped_refptr<CookieMonster> cm(new CookieMonster(store, NULL)); | |
1227 CookieOptions options; | |
1228 options.set_include_httponly(); | |
1229 | |
1230 EXPECT_TRUE(SetCookie(cm, url_google_, kValidCookieLine)); | |
1231 EXPECT_EQ("A=B", GetCookies(cm, url_google_)); | |
1232 | |
1233 EXPECT_TRUE(SetCookieWithOptions(cm, url_google_, "C=D; httponly", options)); | |
1234 EXPECT_EQ("A=B; C=D", GetCookiesWithOptions(cm, url_google_, options)); | |
1235 | |
1236 EXPECT_EQ(2, DeleteAll(cm)); | |
1237 EXPECT_EQ("", GetCookiesWithOptions(cm, url_google_, options)); | |
1238 | |
1239 EXPECT_EQ(0u, store->commands().size()); | |
1240 | |
1241 // Create a persistent cookie. | |
1242 EXPECT_TRUE(SetCookie(cm, url_google_, | |
1243 std::string(kValidCookieLine) + | |
1244 "; expires=Mon, 18-Apr-22 22:50:13 GMT")); | |
1245 ASSERT_EQ(1u, store->commands().size()); | |
1246 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type); | |
1247 | |
1248 EXPECT_EQ(1, DeleteAll(cm)); // sync_to_store = true. | |
1249 ASSERT_EQ(2u, store->commands().size()); | |
1250 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type); | |
1251 | |
1252 EXPECT_EQ("", GetCookiesWithOptions(cm, url_google_, options)); | |
1253 } | |
1254 | |
1255 TEST_F(CookieMonsterTest, TestCookieDeleteAllCreatedBetweenTimestamps) { | |
1256 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
1257 Time now = Time::Now(); | |
1258 | |
1259 // Nothing has been added so nothing should be deleted. | |
1260 EXPECT_EQ(0, DeleteAllCreatedBetween(cm, now - TimeDelta::FromDays(99), | |
1261 Time())); | |
1262 | |
1263 // Create 3 cookies with creation date of today, yesterday and the day before. | |
1264 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-0=Now", now)); | |
1265 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-1=Yesterday", | |
1266 now - TimeDelta::FromDays(1))); | |
1267 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-2=DayBefore", | |
1268 now - TimeDelta::FromDays(2))); | |
1269 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-3=ThreeDays", | |
1270 now - TimeDelta::FromDays(3))); | |
1271 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-7=LastWeek", | |
1272 now - TimeDelta::FromDays(7))); | |
1273 | |
1274 // Try to delete threedays and the daybefore. | |
1275 EXPECT_EQ(2, DeleteAllCreatedBetween(cm, now - TimeDelta::FromDays(3), | |
1276 now - TimeDelta::FromDays(1))); | |
1277 | |
1278 // Try to delete yesterday, also make sure that delete_end is not | |
1279 // inclusive. | |
1280 EXPECT_EQ(1, DeleteAllCreatedBetween(cm, now - TimeDelta::FromDays(2), | |
1281 now)); | |
1282 | |
1283 // Make sure the delete_begin is inclusive. | |
1284 EXPECT_EQ(1, DeleteAllCreatedBetween(cm, now - TimeDelta::FromDays(7), | |
1285 now)); | |
1286 | |
1287 // Delete the last (now) item. | |
1288 EXPECT_EQ(1, DeleteAllCreatedBetween(cm, Time(), Time())); | |
1289 | |
1290 // Really make sure everything is gone. | |
1291 EXPECT_EQ(0, DeleteAll(cm)); | |
1292 } | |
1293 | |
1294 static const int kAccessDelayMs = kLastAccessThresholdMilliseconds + 20; | |
1295 | |
1296 TEST_F(CookieMonsterTest, TestLastAccess) { | |
1297 scoped_refptr<CookieMonster> cm( | |
1298 new CookieMonster(NULL, NULL, kLastAccessThresholdMilliseconds)); | |
1299 | |
1300 EXPECT_TRUE(SetCookie(cm, url_google_, "A=B")); | |
1301 const Time last_access_date(GetFirstCookieAccessDate(cm)); | |
1302 | |
1303 // Reading the cookie again immediately shouldn't update the access date, | |
1304 // since we're inside the threshold. | |
1305 EXPECT_EQ("A=B", GetCookies(cm, url_google_)); | |
1306 EXPECT_TRUE(last_access_date == GetFirstCookieAccessDate(cm)); | |
1307 | |
1308 // Reading after a short wait should update the access date. | |
1309 base::PlatformThread::Sleep( | |
1310 base::TimeDelta::FromMilliseconds(kAccessDelayMs)); | |
1311 EXPECT_EQ("A=B", GetCookies(cm, url_google_)); | |
1312 EXPECT_FALSE(last_access_date == GetFirstCookieAccessDate(cm)); | |
1313 } | |
1314 | |
1315 TEST_F(CookieMonsterTest, TestHostGarbageCollection) { | |
1316 TestHostGarbageCollectHelper( | |
1317 CookieMonster::kDomainMaxCookies, CookieMonster::kDomainPurgeCookies); | |
1318 } | |
1319 | |
1320 TEST_F(CookieMonsterTest, TestDeleteSingleCookie) { | |
1321 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
1322 | |
1323 EXPECT_TRUE(SetCookie(cm, url_google_, "A=B")); | |
1324 EXPECT_TRUE(SetCookie(cm, url_google_, "C=D")); | |
1325 EXPECT_TRUE(SetCookie(cm, url_google_, "E=F")); | |
1326 EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm, url_google_)); | |
1327 | |
1328 EXPECT_TRUE(FindAndDeleteCookie(cm, url_google_.host(), "C")); | |
1329 EXPECT_EQ("A=B; E=F", GetCookies(cm, url_google_)); | |
1330 | |
1331 EXPECT_FALSE(FindAndDeleteCookie(cm, "random.host", "E")); | |
1332 EXPECT_EQ("A=B; E=F", GetCookies(cm, url_google_)); | |
1333 } | |
1334 | |
1335 TEST_F(CookieMonsterTest, SetCookieableSchemes) { | |
1336 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
1337 scoped_refptr<CookieMonster> cm_foo(new CookieMonster(NULL, NULL)); | |
1338 | |
1339 // Only cm_foo should allow foo:// cookies. | |
1340 const char* kSchemes[] = {"foo"}; | |
1341 cm_foo->SetCookieableSchemes(kSchemes, 1); | |
1342 | |
1343 GURL foo_url("foo://host/path"); | |
1344 GURL http_url("http://host/path"); | |
1345 | |
1346 EXPECT_TRUE(SetCookie(cm, http_url, "x=1")); | |
1347 EXPECT_FALSE(SetCookie(cm, foo_url, "x=1")); | |
1348 EXPECT_TRUE(SetCookie(cm_foo, foo_url, "x=1")); | |
1349 EXPECT_FALSE(SetCookie(cm_foo, http_url, "x=1")); | |
1350 } | |
1351 | |
1352 TEST_F(CookieMonsterTest, GetAllCookiesForURL) { | |
1353 scoped_refptr<CookieMonster> cm( | |
1354 new CookieMonster(NULL, NULL, kLastAccessThresholdMilliseconds)); | |
1355 | |
1356 // Create an httponly cookie. | |
1357 CookieOptions options; | |
1358 options.set_include_httponly(); | |
1359 | |
1360 EXPECT_TRUE(SetCookieWithOptions(cm, url_google_, "A=B; httponly", options)); | |
1361 EXPECT_TRUE(SetCookieWithOptions(cm, url_google_, | |
1362 "C=D; domain=.google.izzle", | |
1363 options)); | |
1364 EXPECT_TRUE(SetCookieWithOptions(cm, url_google_secure_, | |
1365 "E=F; domain=.google.izzle; secure", | |
1366 options)); | |
1367 | |
1368 const Time last_access_date(GetFirstCookieAccessDate(cm)); | |
1369 | |
1370 base::PlatformThread::Sleep( | |
1371 base::TimeDelta::FromMilliseconds(kAccessDelayMs)); | |
1372 | |
1373 // Check cookies for url. | |
1374 CookieList cookies = GetAllCookiesForURL(cm, url_google_); | |
1375 CookieList::iterator it = cookies.begin(); | |
1376 | |
1377 ASSERT_TRUE(it != cookies.end()); | |
1378 EXPECT_EQ("www.google.izzle", it->Domain()); | |
1379 EXPECT_EQ("A", it->Name()); | |
1380 | |
1381 ASSERT_TRUE(++it != cookies.end()); | |
1382 EXPECT_EQ(".google.izzle", it->Domain()); | |
1383 EXPECT_EQ("C", it->Name()); | |
1384 | |
1385 ASSERT_TRUE(++it == cookies.end()); | |
1386 | |
1387 // Check cookies for url excluding http-only cookies. | |
1388 cookies = | |
1389 GetAllCookiesForURLWithOptions(cm, url_google_, CookieOptions()); | |
1390 it = cookies.begin(); | |
1391 | |
1392 ASSERT_TRUE(it != cookies.end()); | |
1393 EXPECT_EQ(".google.izzle", it->Domain()); | |
1394 EXPECT_EQ("C", it->Name()); | |
1395 | |
1396 ASSERT_TRUE(++it == cookies.end()); | |
1397 | |
1398 // Test secure cookies. | |
1399 cookies = GetAllCookiesForURL(cm, url_google_secure_); | |
1400 it = cookies.begin(); | |
1401 | |
1402 ASSERT_TRUE(it != cookies.end()); | |
1403 EXPECT_EQ("www.google.izzle", it->Domain()); | |
1404 EXPECT_EQ("A", it->Name()); | |
1405 | |
1406 ASSERT_TRUE(++it != cookies.end()); | |
1407 EXPECT_EQ(".google.izzle", it->Domain()); | |
1408 EXPECT_EQ("C", it->Name()); | |
1409 | |
1410 ASSERT_TRUE(++it != cookies.end()); | |
1411 EXPECT_EQ(".google.izzle", it->Domain()); | |
1412 EXPECT_EQ("E", it->Name()); | |
1413 | |
1414 ASSERT_TRUE(++it == cookies.end()); | |
1415 | |
1416 // Reading after a short wait should not update the access date. | |
1417 EXPECT_TRUE(last_access_date == GetFirstCookieAccessDate(cm)); | |
1418 } | |
1419 | |
1420 TEST_F(CookieMonsterTest, GetAllCookiesForURLPathMatching) { | |
1421 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
1422 CookieOptions options; | |
1423 | |
1424 EXPECT_TRUE(SetCookieWithOptions(cm, url_google_foo_, | |
1425 "A=B; path=/foo;", options)); | |
1426 EXPECT_TRUE(SetCookieWithOptions(cm, url_google_bar_, | |
1427 "C=D; path=/bar;", options)); | |
1428 EXPECT_TRUE(SetCookieWithOptions(cm, url_google_, | |
1429 "E=F;", options)); | |
1430 | |
1431 CookieList cookies = GetAllCookiesForURL(cm, url_google_foo_); | |
1432 CookieList::iterator it = cookies.begin(); | |
1433 | |
1434 ASSERT_TRUE(it != cookies.end()); | |
1435 EXPECT_EQ("A", it->Name()); | |
1436 EXPECT_EQ("/foo", it->Path()); | |
1437 | |
1438 ASSERT_TRUE(++it != cookies.end()); | |
1439 EXPECT_EQ("E", it->Name()); | |
1440 EXPECT_EQ("/", it->Path()); | |
1441 | |
1442 ASSERT_TRUE(++it == cookies.end()); | |
1443 | |
1444 cookies = GetAllCookiesForURL(cm, url_google_bar_); | |
1445 it = cookies.begin(); | |
1446 | |
1447 ASSERT_TRUE(it != cookies.end()); | |
1448 EXPECT_EQ("C", it->Name()); | |
1449 EXPECT_EQ("/bar", it->Path()); | |
1450 | |
1451 ASSERT_TRUE(++it != cookies.end()); | |
1452 EXPECT_EQ("E", it->Name()); | |
1453 EXPECT_EQ("/", it->Path()); | |
1454 | |
1455 ASSERT_TRUE(++it == cookies.end()); | |
1456 } | |
1457 | |
1458 TEST_F(CookieMonsterTest, DeleteCookieByName) { | |
1459 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
1460 | |
1461 EXPECT_TRUE(SetCookie(cm, url_google_, "A=A1; path=/")); | |
1462 EXPECT_TRUE(SetCookie(cm, url_google_, "A=A2; path=/foo")); | |
1463 EXPECT_TRUE(SetCookie(cm, url_google_, "A=A3; path=/bar")); | |
1464 EXPECT_TRUE(SetCookie(cm, url_google_, "B=B1; path=/")); | |
1465 EXPECT_TRUE(SetCookie(cm, url_google_, "B=B2; path=/foo")); | |
1466 EXPECT_TRUE(SetCookie(cm, url_google_, "B=B3; path=/bar")); | |
1467 | |
1468 DeleteCookie(cm, GURL(std::string(kUrlGoogle) + "/foo/bar"), "A"); | |
1469 | |
1470 CookieList cookies = GetAllCookies(cm); | |
1471 size_t expected_size = 4; | |
1472 EXPECT_EQ(expected_size, cookies.size()); | |
1473 for (CookieList::iterator it = cookies.begin(); | |
1474 it != cookies.end(); ++it) { | |
1475 EXPECT_NE("A1", it->Value()); | |
1476 EXPECT_NE("A2", it->Value()); | |
1477 } | |
1478 } | |
1479 | |
1480 TEST_F(CookieMonsterTest, InitializeFromCookieMonster) { | |
1481 scoped_refptr<CookieMonster> cm_1(new CookieMonster(NULL, NULL)); | |
1482 CookieOptions options; | |
1483 | |
1484 EXPECT_TRUE(SetCookieWithOptions(cm_1.get(), url_google_foo_, | |
1485 "A1=B; path=/foo;", | |
1486 options)); | |
1487 EXPECT_TRUE(SetCookieWithOptions(cm_1.get(), url_google_bar_, | |
1488 "A2=D; path=/bar;", | |
1489 options)); | |
1490 EXPECT_TRUE(SetCookieWithOptions(cm_1.get(), url_google_, | |
1491 "A3=F;", | |
1492 options)); | |
1493 | |
1494 CookieList cookies_1 = GetAllCookies(cm_1); | |
1495 scoped_refptr<CookieMonster> cm_2(new CookieMonster(NULL, NULL)); | |
1496 ASSERT_TRUE(cm_2->InitializeFrom(cookies_1)); | |
1497 CookieList cookies_2 = GetAllCookies(cm_2); | |
1498 | |
1499 size_t expected_size = 3; | |
1500 EXPECT_EQ(expected_size, cookies_2.size()); | |
1501 | |
1502 CookieList::iterator it = cookies_2.begin(); | |
1503 | |
1504 ASSERT_TRUE(it != cookies_2.end()); | |
1505 EXPECT_EQ("A1", it->Name()); | |
1506 EXPECT_EQ("/foo", it->Path()); | |
1507 | |
1508 ASSERT_TRUE(++it != cookies_2.end()); | |
1509 EXPECT_EQ("A2", it->Name()); | |
1510 EXPECT_EQ("/bar", it->Path()); | |
1511 | |
1512 ASSERT_TRUE(++it != cookies_2.end()); | |
1513 EXPECT_EQ("A3", it->Name()); | |
1514 EXPECT_EQ("/", it->Path()); | |
1515 } | |
1516 | |
1517 // Tests importing from a persistent cookie store that contains duplicate | |
1518 // equivalent cookies. This situation should be handled by removing the | |
1519 // duplicate cookie (both from the in-memory cache, and from the backing store). | |
1520 // | |
1521 // This is a regression test for: http://crbug.com/17855. | |
1522 TEST_F(CookieMonsterTest, DontImportDuplicateCookies) { | |
1523 scoped_refptr<MockPersistentCookieStore> store( | |
1524 new MockPersistentCookieStore); | |
1525 | |
1526 // We will fill some initial cookies into the PersistentCookieStore, | |
1527 // to simulate a database with 4 duplicates. Note that we need to | |
1528 // be careful not to have any duplicate creation times at all (as it's a | |
1529 // violation of a CookieMonster invariant) even if Time::Now() doesn't | |
1530 // move between calls. | |
1531 std::vector<CookieMonster::CanonicalCookie*> initial_cookies; | |
1532 | |
1533 // Insert 4 cookies with name "X" on path "/", with varying creation | |
1534 // dates. We expect only the most recent one to be preserved following | |
1535 // the import. | |
1536 | |
1537 AddCookieToList("www.google.com", | |
1538 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
1539 Time::Now() + TimeDelta::FromDays(3), | |
1540 &initial_cookies); | |
1541 | |
1542 AddCookieToList("www.google.com", | |
1543 "X=2; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
1544 Time::Now() + TimeDelta::FromDays(1), | |
1545 &initial_cookies); | |
1546 | |
1547 // ===> This one is the WINNER (biggest creation time). <==== | |
1548 AddCookieToList("www.google.com", | |
1549 "X=3; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
1550 Time::Now() + TimeDelta::FromDays(4), | |
1551 &initial_cookies); | |
1552 | |
1553 AddCookieToList("www.google.com", | |
1554 "X=4; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
1555 Time::Now(), | |
1556 &initial_cookies); | |
1557 | |
1558 // Insert 2 cookies with name "X" on path "/2", with varying creation | |
1559 // dates. We expect only the most recent one to be preserved the import. | |
1560 | |
1561 // ===> This one is the WINNER (biggest creation time). <==== | |
1562 AddCookieToList("www.google.com", | |
1563 "X=a1; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
1564 Time::Now() + TimeDelta::FromDays(9), | |
1565 &initial_cookies); | |
1566 | |
1567 AddCookieToList("www.google.com", | |
1568 "X=a2; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
1569 Time::Now() + TimeDelta::FromDays(2), | |
1570 &initial_cookies); | |
1571 | |
1572 // Insert 1 cookie with name "Y" on path "/". | |
1573 AddCookieToList("www.google.com", | |
1574 "Y=a; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", | |
1575 Time::Now() + TimeDelta::FromDays(10), | |
1576 &initial_cookies); | |
1577 | |
1578 // Inject our initial cookies into the mock PersistentCookieStore. | |
1579 store->SetLoadExpectation(true, initial_cookies); | |
1580 | |
1581 scoped_refptr<CookieMonster> cm(new CookieMonster(store, NULL)); | |
1582 | |
1583 // Verify that duplicates were not imported for path "/". | |
1584 // (If this had failed, GetCookies() would have also returned X=1, X=2, X=4). | |
1585 EXPECT_EQ("X=3; Y=a", GetCookies(cm, GURL("http://www.google.com/"))); | |
1586 | |
1587 // Verify that same-named cookie on a different path ("/x2") didn't get | |
1588 // messed up. | |
1589 EXPECT_EQ("X=a1; X=3; Y=a", | |
1590 GetCookies(cm, GURL("http://www.google.com/2/x"))); | |
1591 | |
1592 // Verify that the PersistentCookieStore was told to kill its 4 duplicates. | |
1593 ASSERT_EQ(4u, store->commands().size()); | |
1594 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[0].type); | |
1595 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type); | |
1596 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[2].type); | |
1597 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type); | |
1598 } | |
1599 | |
1600 // Tests importing from a persistent cookie store that contains cookies | |
1601 // with duplicate creation times. This situation should be handled by | |
1602 // dropping the cookies before insertion/visibility to user. | |
1603 // | |
1604 // This is a regression test for: http://crbug.com/43188. | |
1605 TEST_F(CookieMonsterTest, DontImportDuplicateCreationTimes) { | |
1606 scoped_refptr<MockPersistentCookieStore> store( | |
1607 new MockPersistentCookieStore); | |
1608 | |
1609 Time now(Time::Now()); | |
1610 Time earlier(now - TimeDelta::FromDays(1)); | |
1611 | |
1612 // Insert 8 cookies, four with the current time as creation times, and | |
1613 // four with the earlier time as creation times. We should only get | |
1614 // two cookies remaining, but which two (other than that there should | |
1615 // be one from each set) will be random. | |
1616 std::vector<CookieMonster::CanonicalCookie*> initial_cookies; | |
1617 AddCookieToList("www.google.com", "X=1; path=/", now, &initial_cookies); | |
1618 AddCookieToList("www.google.com", "X=2; path=/", now, &initial_cookies); | |
1619 AddCookieToList("www.google.com", "X=3; path=/", now, &initial_cookies); | |
1620 AddCookieToList("www.google.com", "X=4; path=/", now, &initial_cookies); | |
1621 | |
1622 AddCookieToList("www.google.com", "Y=1; path=/", earlier, &initial_cookies); | |
1623 AddCookieToList("www.google.com", "Y=2; path=/", earlier, &initial_cookies); | |
1624 AddCookieToList("www.google.com", "Y=3; path=/", earlier, &initial_cookies); | |
1625 AddCookieToList("www.google.com", "Y=4; path=/", earlier, &initial_cookies); | |
1626 | |
1627 // Inject our initial cookies into the mock PersistentCookieStore. | |
1628 store->SetLoadExpectation(true, initial_cookies); | |
1629 | |
1630 scoped_refptr<CookieMonster> cm(new CookieMonster(store, NULL)); | |
1631 | |
1632 CookieList list(GetAllCookies(cm)); | |
1633 EXPECT_EQ(2U, list.size()); | |
1634 // Confirm that we have one of each. | |
1635 std::string name1(list[0].Name()); | |
1636 std::string name2(list[1].Name()); | |
1637 EXPECT_TRUE(name1 == "X" || name2 == "X"); | |
1638 EXPECT_TRUE(name1 == "Y" || name2 == "Y"); | |
1639 EXPECT_NE(name1, name2); | |
1640 } | |
1641 | |
1642 TEST_F(CookieMonsterTest, Delegate) { | |
1643 scoped_refptr<MockPersistentCookieStore> store( | |
1644 new MockPersistentCookieStore); | |
1645 scoped_refptr<MockCookieMonsterDelegate> delegate( | |
1646 new MockCookieMonsterDelegate); | |
1647 scoped_refptr<CookieMonster> cm(new CookieMonster(store, delegate)); | |
1648 | |
1649 EXPECT_TRUE(SetCookie(cm, url_google_, "A=B")); | |
1650 EXPECT_TRUE(SetCookie(cm, url_google_, "C=D")); | |
1651 EXPECT_TRUE(SetCookie(cm, url_google_, "E=F")); | |
1652 EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm, url_google_)); | |
1653 ASSERT_EQ(3u, delegate->changes().size()); | |
1654 EXPECT_FALSE(delegate->changes()[0].second); | |
1655 EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain()); | |
1656 EXPECT_EQ("A", delegate->changes()[0].first.Name()); | |
1657 EXPECT_EQ("B", delegate->changes()[0].first.Value()); | |
1658 EXPECT_EQ(url_google_.host(), delegate->changes()[1].first.Domain()); | |
1659 EXPECT_FALSE(delegate->changes()[1].second); | |
1660 EXPECT_EQ("C", delegate->changes()[1].first.Name()); | |
1661 EXPECT_EQ("D", delegate->changes()[1].first.Value()); | |
1662 EXPECT_EQ(url_google_.host(), delegate->changes()[2].first.Domain()); | |
1663 EXPECT_FALSE(delegate->changes()[2].second); | |
1664 EXPECT_EQ("E", delegate->changes()[2].first.Name()); | |
1665 EXPECT_EQ("F", delegate->changes()[2].first.Value()); | |
1666 delegate->reset(); | |
1667 | |
1668 EXPECT_TRUE(FindAndDeleteCookie(cm, url_google_.host(), "C")); | |
1669 EXPECT_EQ("A=B; E=F", GetCookies(cm, url_google_)); | |
1670 ASSERT_EQ(1u, delegate->changes().size()); | |
1671 EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain()); | |
1672 EXPECT_TRUE(delegate->changes()[0].second); | |
1673 EXPECT_EQ("C", delegate->changes()[0].first.Name()); | |
1674 EXPECT_EQ("D", delegate->changes()[0].first.Value()); | |
1675 delegate->reset(); | |
1676 | |
1677 EXPECT_FALSE(FindAndDeleteCookie(cm, "random.host", "E")); | |
1678 EXPECT_EQ("A=B; E=F", GetCookies(cm, url_google_)); | |
1679 EXPECT_EQ(0u, delegate->changes().size()); | |
1680 | |
1681 // Insert a cookie "a" for path "/path1" | |
1682 EXPECT_TRUE( | |
1683 SetCookie(cm, url_google_, "a=val1; path=/path1; " | |
1684 "expires=Mon, 18-Apr-22 22:50:13 GMT")); | |
1685 ASSERT_EQ(1u, store->commands().size()); | |
1686 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type); | |
1687 ASSERT_EQ(1u, delegate->changes().size()); | |
1688 EXPECT_FALSE(delegate->changes()[0].second); | |
1689 EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain()); | |
1690 EXPECT_EQ("a", delegate->changes()[0].first.Name()); | |
1691 EXPECT_EQ("val1", delegate->changes()[0].first.Value()); | |
1692 delegate->reset(); | |
1693 | |
1694 // Insert a cookie "a" for path "/path1", that is httponly. This should | |
1695 // overwrite the non-http-only version. | |
1696 CookieOptions allow_httponly; | |
1697 allow_httponly.set_include_httponly(); | |
1698 EXPECT_TRUE( | |
1699 SetCookieWithOptions(cm, url_google_, | |
1700 "a=val2; path=/path1; httponly; " | |
1701 "expires=Mon, 18-Apr-22 22:50:14 GMT", | |
1702 allow_httponly)); | |
1703 ASSERT_EQ(3u, store->commands().size()); | |
1704 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type); | |
1705 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type); | |
1706 ASSERT_EQ(2u, delegate->changes().size()); | |
1707 EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain()); | |
1708 EXPECT_TRUE(delegate->changes()[0].second); | |
1709 EXPECT_EQ("a", delegate->changes()[0].first.Name()); | |
1710 EXPECT_EQ("val1", delegate->changes()[0].first.Value()); | |
1711 EXPECT_EQ(url_google_.host(), delegate->changes()[1].first.Domain()); | |
1712 EXPECT_FALSE(delegate->changes()[1].second); | |
1713 EXPECT_EQ("a", delegate->changes()[1].first.Name()); | |
1714 EXPECT_EQ("val2", delegate->changes()[1].first.Value()); | |
1715 delegate->reset(); | |
1716 } | |
1717 | |
1718 TEST_F(CookieMonsterTest, SetCookieWithDetails) { | |
1719 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
1720 | |
1721 EXPECT_TRUE(SetCookieWithDetails( | |
1722 cm, url_google_foo_, "A", "B", std::string(), "/foo", base::Time(), | |
1723 false, false)); | |
1724 EXPECT_TRUE(SetCookieWithDetails( | |
1725 cm, url_google_bar_, "C", "D", "google.izzle", "/bar", base::Time(), | |
1726 false, true)); | |
1727 EXPECT_TRUE(SetCookieWithDetails( | |
1728 cm, url_google_, "E", "F", std::string(), std::string(), base::Time(), | |
1729 true, false)); | |
1730 | |
1731 // Test that malformed attributes fail to set the cookie. | |
1732 EXPECT_FALSE(SetCookieWithDetails( | |
1733 cm, url_google_foo_, " A", "B", std::string(), "/foo", base::Time(), | |
1734 false, false)); | |
1735 EXPECT_FALSE(SetCookieWithDetails( | |
1736 cm, url_google_foo_, "A;", "B", std::string(), "/foo", base::Time(), | |
1737 false, false)); | |
1738 EXPECT_FALSE(SetCookieWithDetails( | |
1739 cm, url_google_foo_, "A=", "B", std::string(), "/foo", base::Time(), | |
1740 false, false)); | |
1741 EXPECT_FALSE(SetCookieWithDetails( | |
1742 cm, url_google_foo_, "A", "B", "google.ozzzzzzle", "foo", base::Time(), | |
1743 false, false)); | |
1744 EXPECT_FALSE(SetCookieWithDetails( | |
1745 cm, url_google_foo_, "A=", "B", std::string(), "foo", base::Time(), | |
1746 false, false)); | |
1747 | |
1748 CookieList cookies = GetAllCookiesForURL(cm, url_google_foo_); | |
1749 CookieList::iterator it = cookies.begin(); | |
1750 | |
1751 ASSERT_TRUE(it != cookies.end()); | |
1752 EXPECT_EQ("A", it->Name()); | |
1753 EXPECT_EQ("B", it->Value()); | |
1754 EXPECT_EQ("www.google.izzle", it->Domain()); | |
1755 EXPECT_EQ("/foo", it->Path()); | |
1756 EXPECT_FALSE(it->DoesExpire()); | |
1757 EXPECT_FALSE(it->IsSecure()); | |
1758 EXPECT_FALSE(it->IsHttpOnly()); | |
1759 | |
1760 ASSERT_TRUE(++it == cookies.end()); | |
1761 | |
1762 cookies = GetAllCookiesForURL(cm, url_google_bar_); | |
1763 it = cookies.begin(); | |
1764 | |
1765 ASSERT_TRUE(it != cookies.end()); | |
1766 EXPECT_EQ("C", it->Name()); | |
1767 EXPECT_EQ("D", it->Value()); | |
1768 EXPECT_EQ(".google.izzle", it->Domain()); | |
1769 EXPECT_EQ("/bar", it->Path()); | |
1770 EXPECT_FALSE(it->IsSecure()); | |
1771 EXPECT_TRUE(it->IsHttpOnly()); | |
1772 | |
1773 ASSERT_TRUE(++it == cookies.end()); | |
1774 | |
1775 cookies = GetAllCookiesForURL(cm, url_google_secure_); | |
1776 it = cookies.begin(); | |
1777 | |
1778 ASSERT_TRUE(it != cookies.end()); | |
1779 EXPECT_EQ("E", it->Name()); | |
1780 EXPECT_EQ("F", it->Value()); | |
1781 EXPECT_EQ("/", it->Path()); | |
1782 EXPECT_EQ("www.google.izzle", it->Domain()); | |
1783 EXPECT_TRUE(it->IsSecure()); | |
1784 EXPECT_FALSE(it->IsHttpOnly()); | |
1785 | |
1786 ASSERT_TRUE(++it == cookies.end()); | |
1787 } | |
1788 | |
1789 TEST_F(CookieMonsterTest, DeleteAllForHost) { | |
1790 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
1791 | |
1792 // Test probes: | |
1793 // * Non-secure URL, mid-level (http://w.c.b.a) | |
1794 // * Secure URL, mid-level (https://w.c.b.a) | |
1795 // * URL with path, mid-level (https:/w.c.b.a/dir1/xx) | |
1796 // All three tests should nuke only the midlevel host cookie, | |
1797 // the http_only cookie, the host secure cookie, and the two host | |
1798 // path cookies. http_only, secure, and paths are ignored by | |
1799 // this call, and domain cookies arent touched. | |
1800 PopulateCmForDeleteAllForHost(cm); | |
1801 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X", | |
1802 GetCookies(cm, GURL(kTopLevelDomainPlus3))); | |
1803 EXPECT_EQ("dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X", | |
1804 GetCookies(cm, GURL(kTopLevelDomainPlus2Secure))); | |
1805 EXPECT_EQ("dom_1=X; host_1=X", GetCookies(cm, GURL(kTopLevelDomainPlus1))); | |
1806 EXPECT_EQ("dom_path_2=X; host_path_2=X; dom_path_1=X; host_path_1=X; " | |
1807 "dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X", | |
1808 GetCookies(cm, GURL(kTopLevelDomainPlus2Secure + | |
1809 std::string("/dir1/dir2/xxx")))); | |
1810 | |
1811 EXPECT_EQ(5, DeleteAllForHost(cm, GURL(kTopLevelDomainPlus2))); | |
1812 EXPECT_EQ(8U, GetAllCookies(cm).size()); | |
1813 | |
1814 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X", | |
1815 GetCookies(cm, GURL(kTopLevelDomainPlus3))); | |
1816 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X", | |
1817 GetCookies(cm, GURL(kTopLevelDomainPlus2Secure))); | |
1818 EXPECT_EQ("dom_1=X; host_1=X", GetCookies(cm, GURL(kTopLevelDomainPlus1))); | |
1819 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X", | |
1820 GetCookies(cm, GURL(kTopLevelDomainPlus2Secure + | |
1821 std::string("/dir1/dir2/xxx")))); | |
1822 | |
1823 PopulateCmForDeleteAllForHost(cm); | |
1824 EXPECT_EQ(5, DeleteAllForHost(cm, GURL(kTopLevelDomainPlus2Secure))); | |
1825 EXPECT_EQ(8U, GetAllCookies(cm).size()); | |
1826 | |
1827 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X", | |
1828 GetCookies(cm, GURL(kTopLevelDomainPlus3))); | |
1829 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X", | |
1830 GetCookies(cm, GURL(kTopLevelDomainPlus2Secure))); | |
1831 EXPECT_EQ("dom_1=X; host_1=X", GetCookies(cm, GURL(kTopLevelDomainPlus1))); | |
1832 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X", | |
1833 GetCookies(cm, GURL(kTopLevelDomainPlus2Secure + | |
1834 std::string("/dir1/dir2/xxx")))); | |
1835 | |
1836 PopulateCmForDeleteAllForHost(cm); | |
1837 EXPECT_EQ(5, DeleteAllForHost(cm, GURL(kTopLevelDomainPlus2Secure + | |
1838 std::string("/dir1/xxx")))); | |
1839 EXPECT_EQ(8U, GetAllCookies(cm).size()); | |
1840 | |
1841 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X", | |
1842 GetCookies(cm, GURL(kTopLevelDomainPlus3))); | |
1843 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X", | |
1844 GetCookies(cm, GURL(kTopLevelDomainPlus2Secure))); | |
1845 EXPECT_EQ("dom_1=X; host_1=X", GetCookies(cm, GURL(kTopLevelDomainPlus1))); | |
1846 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X", | |
1847 GetCookies(cm, GURL(kTopLevelDomainPlus2Secure + | |
1848 std::string("/dir1/dir2/xxx")))); | |
1849 } | |
1850 | |
1851 TEST_F(CookieMonsterTest, UniqueCreationTime) { | |
1852 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
1853 CookieOptions options; | |
1854 | |
1855 // Add in three cookies through every public interface to the | |
1856 // CookieMonster and confirm that none of them have duplicate | |
1857 // creation times. | |
1858 | |
1859 // SetCookieWithCreationTime and SetCookieWithCreationTimeAndOptions | |
1860 // are not included as they aren't going to be public for very much | |
1861 // longer. | |
1862 | |
1863 // SetCookie, SetCookieWithOptions, SetCookieWithDetails | |
1864 | |
1865 SetCookie(cm, url_google_, "SetCookie1=A"); | |
1866 SetCookie(cm, url_google_, "SetCookie2=A"); | |
1867 SetCookie(cm, url_google_, "SetCookie3=A"); | |
1868 | |
1869 SetCookieWithOptions(cm, url_google_, "setCookieWithOptions1=A", options); | |
1870 SetCookieWithOptions(cm, url_google_, "setCookieWithOptions2=A", options); | |
1871 SetCookieWithOptions(cm, url_google_, "setCookieWithOptions3=A", options); | |
1872 | |
1873 SetCookieWithDetails(cm, url_google_, "setCookieWithDetails1", "A", | |
1874 ".google.com", "/", Time(), false, false); | |
1875 SetCookieWithDetails(cm, url_google_, "setCookieWithDetails2", "A", | |
1876 ".google.com", "/", Time(), false, false); | |
1877 SetCookieWithDetails(cm, url_google_, "setCookieWithDetails3", "A", | |
1878 ".google.com", "/", Time(), false, false); | |
1879 | |
1880 // Now we check | |
1881 CookieList cookie_list(GetAllCookies(cm)); | |
1882 typedef std::map<int64, CookieMonster::CanonicalCookie> TimeCookieMap; | |
1883 TimeCookieMap check_map; | |
1884 for (CookieList::const_iterator it = cookie_list.begin(); | |
1885 it != cookie_list.end(); it++) { | |
1886 const int64 creation_date = it->CreationDate().ToInternalValue(); | |
1887 TimeCookieMap::const_iterator | |
1888 existing_cookie_it(check_map.find(creation_date)); | |
1889 EXPECT_TRUE(existing_cookie_it == check_map.end()) | |
1890 << "Cookie " << it->Name() << " has same creation date (" | |
1891 << it->CreationDate().ToInternalValue() | |
1892 << ") as previously entered cookie " | |
1893 << existing_cookie_it->second.Name(); | |
1894 | |
1895 if (existing_cookie_it == check_map.end()) { | |
1896 check_map.insert(TimeCookieMap::value_type( | |
1897 it->CreationDate().ToInternalValue(), *it)); | |
1898 } | |
1899 } | |
1900 } | |
1901 | |
1902 // Mainly a test of GetEffectiveDomain, or more specifically, of the | |
1903 // expected behavior of GetEffectiveDomain within the CookieMonster. | |
1904 TEST_F(CookieMonsterTest, GetKey) { | |
1905 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
1906 | |
1907 // This test is really only interesting if GetKey() actually does something. | |
1908 EXPECT_EQ("google.com", cm->GetKey("www.google.com")); | |
1909 EXPECT_EQ("google.izzie", cm->GetKey("www.google.izzie")); | |
1910 EXPECT_EQ("google.izzie", cm->GetKey(".google.izzie")); | |
1911 EXPECT_EQ("bbc.co.uk", cm->GetKey("bbc.co.uk")); | |
1912 EXPECT_EQ("bbc.co.uk", cm->GetKey("a.b.c.d.bbc.co.uk")); | |
1913 EXPECT_EQ("apple.com", cm->GetKey("a.b.c.d.apple.com")); | |
1914 EXPECT_EQ("apple.izzie", cm->GetKey("a.b.c.d.apple.izzie")); | |
1915 | |
1916 // Cases where the effective domain is null, so we use the host | |
1917 // as the key. | |
1918 EXPECT_EQ("co.uk", cm->GetKey("co.uk")); | |
1919 const std::string extension_name("iehocdgbbocmkdidlbnnfbmbinnahbae"); | |
1920 EXPECT_EQ(extension_name, cm->GetKey(extension_name)); | |
1921 EXPECT_EQ("com", cm->GetKey("com")); | |
1922 EXPECT_EQ("hostalias", cm->GetKey("hostalias")); | |
1923 EXPECT_EQ("localhost", cm->GetKey("localhost")); | |
1924 } | |
1925 | |
1926 // Test that cookies transfer from/to the backing store correctly. | |
1927 TEST_F(CookieMonsterTest, BackingStoreCommunication) { | |
1928 // Store details for cookies transforming through the backing store interface. | |
1929 | |
1930 base::Time current(base::Time::Now()); | |
1931 scoped_refptr<MockSimplePersistentCookieStore> store( | |
1932 new MockSimplePersistentCookieStore); | |
1933 base::Time new_access_time; | |
1934 base::Time expires(base::Time::Now() + base::TimeDelta::FromSeconds(100)); | |
1935 | |
1936 struct CookiesInputInfo { | |
1937 std::string gurl; | |
1938 std::string name; | |
1939 std::string value; | |
1940 std::string domain; | |
1941 std::string path; | |
1942 base::Time expires; | |
1943 bool secure; | |
1944 bool http_only; | |
1945 }; | |
1946 const CookiesInputInfo input_info[] = { | |
1947 {"http://a.b.google.com", "a", "1", "", "/path/to/cookie", expires, | |
1948 false, false}, | |
1949 {"https://www.google.com", "b", "2", ".google.com", "/path/from/cookie", | |
1950 expires + TimeDelta::FromSeconds(10), true, true}, | |
1951 {"https://google.com", "c", "3", "", "/another/path/to/cookie", | |
1952 base::Time::Now() + base::TimeDelta::FromSeconds(100), | |
1953 true, false} | |
1954 }; | |
1955 const int INPUT_DELETE = 1; | |
1956 | |
1957 // Create new cookies and flush them to the store. | |
1958 { | |
1959 scoped_refptr<CookieMonster> cmout(new CookieMonster(store, NULL)); | |
1960 for (const CookiesInputInfo* p = input_info; | |
1961 p < &input_info[ARRAYSIZE_UNSAFE(input_info)]; p++) { | |
1962 EXPECT_TRUE(SetCookieWithDetails(cmout, GURL(p->gurl), p->name, p->value, | |
1963 p->domain, p->path, p->expires, | |
1964 p->secure, p->http_only)); | |
1965 } | |
1966 DeleteCookie(cmout, GURL(std::string(input_info[INPUT_DELETE].gurl) + | |
1967 input_info[INPUT_DELETE].path), | |
1968 input_info[INPUT_DELETE].name); | |
1969 } | |
1970 | |
1971 // Create a new cookie monster and make sure that everything is correct | |
1972 { | |
1973 scoped_refptr<CookieMonster> cmin(new CookieMonster(store, NULL)); | |
1974 CookieList cookies(GetAllCookies(cmin)); | |
1975 ASSERT_EQ(2u, cookies.size()); | |
1976 // Ordering is path length, then creation time. So second cookie | |
1977 // will come first, and we need to swap them. | |
1978 std::swap(cookies[0], cookies[1]); | |
1979 for (int output_index = 0; output_index < 2; output_index++) { | |
1980 int input_index = output_index * 2; | |
1981 const CookiesInputInfo* input = &input_info[input_index]; | |
1982 const CookieMonster::CanonicalCookie* output = &cookies[output_index]; | |
1983 | |
1984 EXPECT_EQ(input->name, output->Name()); | |
1985 EXPECT_EQ(input->value, output->Value()); | |
1986 EXPECT_EQ(GURL(input->gurl).host(), output->Domain()); | |
1987 EXPECT_EQ(input->path, output->Path()); | |
1988 EXPECT_LE(current.ToInternalValue(), | |
1989 output->CreationDate().ToInternalValue()); | |
1990 EXPECT_EQ(input->secure, output->IsSecure()); | |
1991 EXPECT_EQ(input->http_only, output->IsHttpOnly()); | |
1992 EXPECT_TRUE(output->IsPersistent()); | |
1993 EXPECT_EQ(input->expires.ToInternalValue(), | |
1994 output->ExpiryDate().ToInternalValue()); | |
1995 } | |
1996 } | |
1997 } | |
1998 | |
1999 TEST_F(CookieMonsterTest, CookieListOrdering) { | |
2000 // Put a random set of cookies into a monster and make sure | |
2001 // they're returned in the right order. | |
2002 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
2003 EXPECT_TRUE(SetCookie(cm, GURL("http://d.c.b.a.google.com/aa/x.html"), | |
2004 "c=1")); | |
2005 EXPECT_TRUE(SetCookie(cm, GURL("http://b.a.google.com/aa/bb/cc/x.html"), | |
2006 "d=1; domain=b.a.google.com")); | |
2007 EXPECT_TRUE(SetCookie(cm, GURL("http://b.a.google.com/aa/bb/cc/x.html"), | |
2008 "a=4; domain=b.a.google.com")); | |
2009 EXPECT_TRUE(SetCookie(cm, GURL("http://c.b.a.google.com/aa/bb/cc/x.html"), | |
2010 "e=1; domain=c.b.a.google.com")); | |
2011 EXPECT_TRUE(SetCookie(cm, GURL("http://d.c.b.a.google.com/aa/bb/x.html"), | |
2012 "b=1")); | |
2013 EXPECT_TRUE(SetCookie(cm, GURL("http://news.bbc.co.uk/midpath/x.html"), | |
2014 "g=10")); | |
2015 { | |
2016 unsigned int i = 0; | |
2017 CookieList cookies(GetAllCookiesForURL( | |
2018 cm, GURL("http://d.c.b.a.google.com/aa/bb/cc/dd"))); | |
2019 ASSERT_EQ(5u, cookies.size()); | |
2020 EXPECT_EQ("d", cookies[i++].Name()); | |
2021 EXPECT_EQ("a", cookies[i++].Name()); | |
2022 EXPECT_EQ("e", cookies[i++].Name()); | |
2023 EXPECT_EQ("b", cookies[i++].Name()); | |
2024 EXPECT_EQ("c", cookies[i++].Name()); | |
2025 } | |
2026 | |
2027 { | |
2028 unsigned int i = 0; | |
2029 CookieList cookies(GetAllCookies(cm)); | |
2030 ASSERT_EQ(6u, cookies.size()); | |
2031 EXPECT_EQ("d", cookies[i++].Name()); | |
2032 EXPECT_EQ("a", cookies[i++].Name()); | |
2033 EXPECT_EQ("e", cookies[i++].Name()); | |
2034 EXPECT_EQ("g", cookies[i++].Name()); | |
2035 EXPECT_EQ("b", cookies[i++].Name()); | |
2036 EXPECT_EQ("c", cookies[i++].Name()); | |
2037 } | |
2038 } | |
2039 | |
2040 // This test and CookieMonstertest.TestGCTimes (in cookie_monster_perftest.cc) | |
2041 // are somewhat complementary twins. This test is probing for whether | |
2042 // garbage collection always happens when it should (i.e. that we actually | |
2043 // get rid of cookies when we should). The perftest is probing for | |
2044 // whether garbage collection happens when it shouldn't. See comments | |
2045 // before that test for more details. | |
2046 TEST_F(CookieMonsterTest, GarbageCollectionTriggers) { | |
2047 // First we check to make sure that a whole lot of recent cookies | |
2048 // doesn't get rid of anything after garbage collection is checked for. | |
2049 { | |
2050 scoped_refptr<CookieMonster> cm( | |
2051 CreateMonsterForGC(CookieMonster::kMaxCookies * 2)); | |
2052 EXPECT_EQ(CookieMonster::kMaxCookies * 2, GetAllCookies(cm).size()); | |
2053 SetCookie(cm, GURL("http://newdomain.com"), "b=2"); | |
2054 EXPECT_EQ(CookieMonster::kMaxCookies * 2 + 1, GetAllCookies(cm).size()); | |
2055 } | |
2056 | |
2057 // Now we explore a series of relationships between cookie last access | |
2058 // time and size of store to make sure we only get rid of cookies when | |
2059 // we really should. | |
2060 const struct TestCase { | |
2061 int num_cookies; | |
2062 int num_old_cookies; | |
2063 int expected_initial_cookies; | |
2064 // Indexed by ExpiryAndKeyScheme | |
2065 int expected_cookies_after_set; | |
2066 } test_cases[] = { | |
2067 { | |
2068 // A whole lot of recent cookies; gc shouldn't happen. | |
2069 CookieMonster::kMaxCookies * 2, | |
2070 0, | |
2071 CookieMonster::kMaxCookies * 2, | |
2072 CookieMonster::kMaxCookies * 2 + 1 | |
2073 }, { | |
2074 // Some old cookies, but still overflowing max. | |
2075 CookieMonster::kMaxCookies * 2, | |
2076 CookieMonster::kMaxCookies / 2, | |
2077 CookieMonster::kMaxCookies * 2, | |
2078 CookieMonster::kMaxCookies * 2 - CookieMonster::kMaxCookies / 2 + 1 | |
2079 }, { | |
2080 // Old cookies enough to bring us right down to our purge line. | |
2081 CookieMonster::kMaxCookies * 2, | |
2082 CookieMonster::kMaxCookies + CookieMonster::kPurgeCookies + 1, | |
2083 CookieMonster::kMaxCookies * 2, | |
2084 CookieMonster::kMaxCookies - CookieMonster::kPurgeCookies | |
2085 }, { | |
2086 // Old cookies enough to bring below our purge line (which we | |
2087 // shouldn't do). | |
2088 CookieMonster::kMaxCookies * 2, | |
2089 CookieMonster::kMaxCookies * 3 / 2, | |
2090 CookieMonster::kMaxCookies * 2, | |
2091 CookieMonster::kMaxCookies - CookieMonster::kPurgeCookies | |
2092 } | |
2093 }; | |
2094 | |
2095 for (int ci = 0; ci < static_cast<int>(ARRAYSIZE_UNSAFE(test_cases)); ++ci) { | |
2096 const TestCase *test_case = &test_cases[ci]; | |
2097 scoped_refptr<CookieMonster> cm( | |
2098 CreateMonsterFromStoreForGC( | |
2099 test_case->num_cookies, test_case->num_old_cookies, | |
2100 CookieMonster::kSafeFromGlobalPurgeDays * 2)); | |
2101 EXPECT_EQ(test_case->expected_initial_cookies, | |
2102 static_cast<int>(GetAllCookies(cm).size())) | |
2103 << "For test case " << ci; | |
2104 // Will trigger GC | |
2105 SetCookie(cm, GURL("http://newdomain.com"), "b=2"); | |
2106 EXPECT_EQ(test_case->expected_cookies_after_set, | |
2107 static_cast<int>((GetAllCookies(cm).size()))) | |
2108 << "For test case " << ci; | |
2109 } | |
2110 } | |
2111 | |
2112 // This test checks that setting a cookie forcing it to be a session only | |
2113 // cookie works as expected. | |
2114 TEST_F(CookieMonsterTest, ForceSessionOnly) { | |
2115 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
2116 CookieOptions options; | |
2117 | |
2118 // Set a persistent cookie, but force it to be a session cookie. | |
2119 options.set_force_session(); | |
2120 ASSERT_TRUE(SetCookieWithOptions( | |
2121 cm, url_google_, | |
2122 std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT", | |
2123 options)); | |
2124 | |
2125 // Get the canonical cookie. | |
2126 CookieList cookie_list = GetAllCookies(cm); | |
2127 ASSERT_EQ(1U, cookie_list.size()); | |
2128 ASSERT_FALSE(cookie_list[0].IsPersistent()); | |
2129 | |
2130 // Use a past expiry date to delete the cookie, but force it to session only. | |
2131 ASSERT_TRUE(SetCookieWithOptions( | |
2132 cm, url_google_, | |
2133 std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-1977 22:50:13 GMT", | |
2134 options)); | |
2135 | |
2136 // Check that the cookie was deleted. | |
2137 cookie_list = GetAllCookies(cm); | |
2138 ASSERT_EQ(0U, cookie_list.size()); | |
2139 } | |
2140 | |
2141 // This test checks that keep expired cookies flag is working. | |
2142 TEST_F(CookieMonsterTest, KeepExpiredCookies) { | |
2143 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
2144 cm->SetKeepExpiredCookies(); | |
2145 CookieOptions options; | |
2146 | |
2147 // Set a persistent cookie. | |
2148 ASSERT_TRUE(SetCookieWithOptions( | |
2149 cm, url_google_, | |
2150 std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT", | |
2151 options)); | |
2152 | |
2153 // Get the canonical cookie. | |
2154 CookieList cookie_list = GetAllCookies(cm); | |
2155 ASSERT_EQ(1U, cookie_list.size()); | |
2156 | |
2157 // Use a past expiry date to delete the cookie. | |
2158 ASSERT_TRUE(SetCookieWithOptions( | |
2159 cm, url_google_, | |
2160 std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-1977 22:50:13 GMT", | |
2161 options)); | |
2162 | |
2163 // Check that the cookie with the past expiry date is still there. | |
2164 // GetAllCookies() also triggers garbage collection. | |
2165 cookie_list = GetAllCookies(cm); | |
2166 ASSERT_EQ(1U, cookie_list.size()); | |
2167 ASSERT_TRUE(cookie_list[0].IsExpired(Time::Now())); | |
2168 } | |
2169 | |
2170 namespace { | |
2171 | |
2172 // Mock PersistentCookieStore that keeps track of the number of Flush() calls. | |
2173 class FlushablePersistentStore : public CookieMonster::PersistentCookieStore { | |
2174 public: | |
2175 FlushablePersistentStore() : flush_count_(0) {} | |
2176 | |
2177 void Load(const LoadedCallback& loaded_callback) { | |
2178 std::vector<CookieMonster::CanonicalCookie*> out_cookies; | |
2179 MessageLoop::current()->PostTask(FROM_HERE, | |
2180 base::Bind(&net::LoadedCallbackTask::Run, | |
2181 new net::LoadedCallbackTask(loaded_callback, out_cookies))); | |
2182 } | |
2183 | |
2184 void LoadCookiesForKey(const std::string& key, | |
2185 const LoadedCallback& loaded_callback) { | |
2186 Load(loaded_callback); | |
2187 } | |
2188 | |
2189 void AddCookie(const CookieMonster::CanonicalCookie&) {} | |
2190 void UpdateCookieAccessTime(const CookieMonster::CanonicalCookie&) {} | |
2191 void DeleteCookie(const CookieMonster::CanonicalCookie&) {} | |
2192 void SetClearLocalStateOnExit(bool clear_local_state) {} | |
2193 | |
2194 void Flush(const base::Closure& callback) { | |
2195 ++flush_count_; | |
2196 if (!callback.is_null()) | |
2197 callback.Run(); | |
2198 } | |
2199 | |
2200 int flush_count() { | |
2201 return flush_count_; | |
2202 } | |
2203 | |
2204 private: | |
2205 volatile int flush_count_; | |
2206 }; | |
2207 | |
2208 // Counts the number of times Callback() has been run. | |
2209 class CallbackCounter : public base::RefCountedThreadSafe<CallbackCounter> { | |
2210 public: | |
2211 CallbackCounter() : callback_count_(0) {} | |
2212 | |
2213 void Callback() { | |
2214 ++callback_count_; | |
2215 } | |
2216 | |
2217 int callback_count() { | |
2218 return callback_count_; | |
2219 } | |
2220 | |
2221 private: | |
2222 friend class base::RefCountedThreadSafe<CallbackCounter>; | |
2223 volatile int callback_count_; | |
2224 }; | |
2225 | |
2226 } // namespace | |
2227 | |
2228 // Test that FlushStore() is forwarded to the store and callbacks are posted. | |
2229 TEST_F(CookieMonsterTest, FlushStore) { | |
2230 scoped_refptr<CallbackCounter> counter(new CallbackCounter()); | |
2231 scoped_refptr<FlushablePersistentStore> store(new FlushablePersistentStore()); | |
2232 scoped_refptr<CookieMonster> cm(new CookieMonster(store, NULL)); | |
2233 | |
2234 ASSERT_EQ(0, store->flush_count()); | |
2235 ASSERT_EQ(0, counter->callback_count()); | |
2236 | |
2237 // Before initialization, FlushStore() should just run the callback. | |
2238 cm->FlushStore(base::Bind(&CallbackCounter::Callback, counter.get())); | |
2239 MessageLoop::current()->RunAllPending(); | |
2240 | |
2241 ASSERT_EQ(0, store->flush_count()); | |
2242 ASSERT_EQ(1, counter->callback_count()); | |
2243 | |
2244 // NULL callback is safe. | |
2245 cm->FlushStore(base::Closure()); | |
2246 MessageLoop::current()->RunAllPending(); | |
2247 | |
2248 ASSERT_EQ(0, store->flush_count()); | |
2249 ASSERT_EQ(1, counter->callback_count()); | |
2250 | |
2251 // After initialization, FlushStore() should delegate to the store. | |
2252 GetAllCookies(cm); // Force init. | |
2253 cm->FlushStore(base::Bind(&CallbackCounter::Callback, counter.get())); | |
2254 MessageLoop::current()->RunAllPending(); | |
2255 | |
2256 ASSERT_EQ(1, store->flush_count()); | |
2257 ASSERT_EQ(2, counter->callback_count()); | |
2258 | |
2259 // NULL callback is still safe. | |
2260 cm->FlushStore(base::Closure()); | |
2261 MessageLoop::current()->RunAllPending(); | |
2262 | |
2263 ASSERT_EQ(2, store->flush_count()); | |
2264 ASSERT_EQ(2, counter->callback_count()); | |
2265 | |
2266 // If there's no backing store, FlushStore() is always a safe no-op. | |
2267 cm = new CookieMonster(NULL, NULL); | |
2268 GetAllCookies(cm); // Force init. | |
2269 cm->FlushStore(base::Closure()); | |
2270 MessageLoop::current()->RunAllPending(); | |
2271 | |
2272 ASSERT_EQ(2, counter->callback_count()); | |
2273 | |
2274 cm->FlushStore(base::Bind(&CallbackCounter::Callback, counter.get())); | |
2275 MessageLoop::current()->RunAllPending(); | |
2276 | |
2277 ASSERT_EQ(3, counter->callback_count()); | |
2278 } | |
2279 | |
2280 TEST_F(CookieMonsterTest, GetCookieSourceFromURL) { | |
2281 EXPECT_EQ("http://example.com/", | |
2282 CookieMonster::CanonicalCookie::GetCookieSourceFromURL( | |
2283 GURL("http://example.com"))); | |
2284 EXPECT_EQ("http://example.com/", | |
2285 CookieMonster::CanonicalCookie::GetCookieSourceFromURL( | |
2286 GURL("http://example.com/"))); | |
2287 EXPECT_EQ("http://example.com/", | |
2288 CookieMonster::CanonicalCookie::GetCookieSourceFromURL( | |
2289 GURL("http://example.com/test"))); | |
2290 EXPECT_EQ("file:///tmp/test.html", | |
2291 CookieMonster::CanonicalCookie::GetCookieSourceFromURL( | |
2292 GURL("file:///tmp/test.html"))); | |
2293 EXPECT_EQ("http://example.com/", | |
2294 CookieMonster::CanonicalCookie::GetCookieSourceFromURL( | |
2295 GURL("http://example.com:1234/"))); | |
2296 EXPECT_EQ("http://example.com/", | |
2297 CookieMonster::CanonicalCookie::GetCookieSourceFromURL( | |
2298 GURL("https://example.com/"))); | |
2299 EXPECT_EQ("http://example.com/", | |
2300 CookieMonster::CanonicalCookie::GetCookieSourceFromURL( | |
2301 GURL("http://user:pwd@example.com/"))); | |
2302 EXPECT_EQ("http://example.com/", | |
2303 CookieMonster::CanonicalCookie::GetCookieSourceFromURL( | |
2304 GURL("http://example.com/test?foo"))); | |
2305 EXPECT_EQ("http://example.com/", | |
2306 CookieMonster::CanonicalCookie::GetCookieSourceFromURL( | |
2307 GURL("http://example.com/test#foo"))); | |
2308 } | |
2309 | |
2310 TEST_F(CookieMonsterTest, HistogramCheck) { | |
2311 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
2312 // Should match call in InitializeHistograms, but doesn't really matter | |
2313 // since the histogram should have been initialized by the CM construction | |
2314 // above. | |
2315 base::Histogram* expired_histogram = | |
2316 base::Histogram::FactoryGet( | |
2317 "Cookie.ExpirationDurationMinutes", 1, 10 * 365 * 24 * 60, 50, | |
2318 base::Histogram::kUmaTargetedHistogramFlag); | |
2319 | |
2320 base::Histogram::SampleSet histogram_set_1; | |
2321 expired_histogram->SnapshotSample(&histogram_set_1); | |
2322 ASSERT_TRUE(SetCookieWithDetails( | |
2323 cm, GURL("http://fake.a.url"), "a", "b", "a.url", "/", | |
2324 base::Time::Now() + base::TimeDelta::FromMinutes(59), | |
2325 false, false)); | |
2326 | |
2327 base::Histogram::SampleSet histogram_set_2; | |
2328 expired_histogram->SnapshotSample(&histogram_set_2); | |
2329 EXPECT_EQ(histogram_set_1.TotalCount() + 1, | |
2330 histogram_set_2.TotalCount()); | |
2331 | |
2332 // kValidCookieLine creates a session cookie. | |
2333 ASSERT_TRUE(SetCookie(cm, url_google_, kValidCookieLine)); | |
2334 expired_histogram->SnapshotSample(&histogram_set_1); | |
2335 EXPECT_EQ(histogram_set_2.TotalCount(), | |
2336 histogram_set_1.TotalCount()); | |
2337 } | |
2338 | |
2339 namespace { | |
2340 | |
2341 class MultiThreadedCookieMonsterTest : public CookieMonsterTest { | |
2342 public: | |
2343 MultiThreadedCookieMonsterTest() : other_thread_("CMTthread") {} | |
2344 | |
2345 // Helper methods for calling the asynchronous CookieMonster methods | |
2346 // from a different thread. | |
2347 | |
2348 void GetAllCookiesTask(CookieMonster* cm, | |
2349 GetCookieListCallback* callback) { | |
2350 cm->GetAllCookiesAsync( | |
2351 base::Bind(&GetCookieListCallback::Run, base::Unretained(callback))); | |
2352 } | |
2353 | |
2354 void GetAllCookiesForURLTask(CookieMonster* cm, | |
2355 const GURL& url, | |
2356 GetCookieListCallback* callback) { | |
2357 cm->GetAllCookiesForURLAsync( | |
2358 url, | |
2359 base::Bind(&GetCookieListCallback::Run, base::Unretained(callback))); | |
2360 } | |
2361 | |
2362 void GetAllCookiesForURLWithOptionsTask(CookieMonster* cm, | |
2363 const GURL& url, | |
2364 const CookieOptions& options, | |
2365 GetCookieListCallback* callback) { | |
2366 cm->GetAllCookiesForURLWithOptionsAsync( | |
2367 url, options, | |
2368 base::Bind(&GetCookieListCallback::Run, base::Unretained(callback))); | |
2369 } | |
2370 | |
2371 void SetCookieWithDetailsTask(CookieMonster* cm, const GURL& url, | |
2372 SetCookieCallback* callback) { | |
2373 // Define the parameters here instead of in the calling fucntion. | |
2374 // The maximum number of parameters for Bind function is 6. | |
2375 std::string name = "A"; | |
2376 std::string value = "B"; | |
2377 std::string domain = std::string(); | |
2378 std::string path = "/foo"; | |
2379 base::Time expiration_time = base::Time(); | |
2380 bool secure = false; | |
2381 bool http_only = false; | |
2382 cm->SetCookieWithDetailsAsync( | |
2383 url, name, value, domain, path, expiration_time, secure, http_only, | |
2384 base::Bind(&SetCookieCallback::Run, base::Unretained(callback))); | |
2385 } | |
2386 | |
2387 void DeleteAllCreatedBetweenTask(CookieMonster* cm, | |
2388 const base::Time& delete_begin, | |
2389 const base::Time& delete_end, | |
2390 DeleteCallback* callback) { | |
2391 cm->DeleteAllCreatedBetweenAsync( | |
2392 delete_begin, delete_end, | |
2393 base::Bind(&DeleteCallback::Run, | |
2394 base::Unretained(callback))); | |
2395 } | |
2396 | |
2397 void DeleteAllForHostTask(CookieMonster* cm, | |
2398 const GURL& url, | |
2399 DeleteCallback* callback) { | |
2400 cm->DeleteAllForHostAsync( | |
2401 url, | |
2402 base::Bind(&DeleteCallback::Run, base::Unretained(callback))); | |
2403 } | |
2404 | |
2405 void DeleteCanonicalCookieTask(CookieMonster* cm, | |
2406 const CookieMonster::CanonicalCookie& cookie, | |
2407 SetCookieCallback* callback) { | |
2408 cm->DeleteCanonicalCookieAsync( | |
2409 cookie, | |
2410 base::Bind(&SetCookieCallback::Run, base::Unretained(callback))); | |
2411 } | |
2412 | |
2413 protected: | |
2414 void RunOnOtherThread(const base::Closure& task) { | |
2415 other_thread_.Start(); | |
2416 other_thread_.message_loop()->PostTask(FROM_HERE, task); | |
2417 RunFor(kTimeout); | |
2418 other_thread_.Stop(); | |
2419 } | |
2420 | |
2421 Thread other_thread_; | |
2422 }; | |
2423 | |
2424 } // namespace | |
2425 | |
2426 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckGetAllCookies) { | |
2427 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
2428 EXPECT_TRUE(SetCookie(cm, url_google_, "A=B")); | |
2429 CookieList cookies = GetAllCookies(cm); | |
2430 CookieList::const_iterator it = cookies.begin(); | |
2431 ASSERT_TRUE(it != cookies.end()); | |
2432 EXPECT_EQ("www.google.izzle", it->Domain()); | |
2433 EXPECT_EQ("A", it->Name()); | |
2434 ASSERT_TRUE(++it == cookies.end()); | |
2435 GetCookieListCallback callback(&other_thread_); | |
2436 base::Closure task = | |
2437 base::Bind(&net::MultiThreadedCookieMonsterTest::GetAllCookiesTask, | |
2438 base::Unretained(this), | |
2439 cm, &callback); | |
2440 RunOnOtherThread(task); | |
2441 EXPECT_TRUE(callback.did_run()); | |
2442 it = callback.cookies().begin(); | |
2443 ASSERT_TRUE(it != callback.cookies().end()); | |
2444 EXPECT_EQ("www.google.izzle", it->Domain()); | |
2445 EXPECT_EQ("A", it->Name()); | |
2446 ASSERT_TRUE(++it == callback.cookies().end()); | |
2447 } | |
2448 | |
2449 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckGetAllCookiesForURL) { | |
2450 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
2451 EXPECT_TRUE(SetCookie(cm, url_google_, "A=B")); | |
2452 CookieList cookies = GetAllCookiesForURL(cm, url_google_); | |
2453 CookieList::const_iterator it = cookies.begin(); | |
2454 ASSERT_TRUE(it != cookies.end()); | |
2455 EXPECT_EQ("www.google.izzle", it->Domain()); | |
2456 EXPECT_EQ("A", it->Name()); | |
2457 ASSERT_TRUE(++it == cookies.end()); | |
2458 GetCookieListCallback callback(&other_thread_); | |
2459 base::Closure task = | |
2460 base::Bind(&net::MultiThreadedCookieMonsterTest::GetAllCookiesForURLTask, | |
2461 base::Unretained(this), | |
2462 cm, url_google_, &callback); | |
2463 RunOnOtherThread(task); | |
2464 EXPECT_TRUE(callback.did_run()); | |
2465 it = callback.cookies().begin(); | |
2466 ASSERT_TRUE(it != callback.cookies().end()); | |
2467 EXPECT_EQ("www.google.izzle", it->Domain()); | |
2468 EXPECT_EQ("A", it->Name()); | |
2469 ASSERT_TRUE(++it == callback.cookies().end()); | |
2470 } | |
2471 | |
2472 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckGetAllCookiesForURLWithOpt) { | |
2473 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
2474 EXPECT_TRUE(SetCookie(cm, url_google_, "A=B")); | |
2475 CookieOptions options; | |
2476 CookieList cookies = | |
2477 GetAllCookiesForURLWithOptions(cm, url_google_, options); | |
2478 CookieList::const_iterator it = cookies.begin(); | |
2479 ASSERT_TRUE(it != cookies.end()); | |
2480 EXPECT_EQ("www.google.izzle", it->Domain()); | |
2481 EXPECT_EQ("A", it->Name()); | |
2482 ASSERT_TRUE(++it == cookies.end()); | |
2483 GetCookieListCallback callback(&other_thread_); | |
2484 base::Closure task = base::Bind( | |
2485 &net::MultiThreadedCookieMonsterTest::GetAllCookiesForURLWithOptionsTask, | |
2486 base::Unretained(this), | |
2487 cm, url_google_, options, &callback); | |
2488 RunOnOtherThread(task); | |
2489 EXPECT_TRUE(callback.did_run()); | |
2490 it = callback.cookies().begin(); | |
2491 ASSERT_TRUE(it != callback.cookies().end()); | |
2492 EXPECT_EQ("www.google.izzle", it->Domain()); | |
2493 EXPECT_EQ("A", it->Name()); | |
2494 ASSERT_TRUE(++it == callback.cookies().end()); | |
2495 } | |
2496 | |
2497 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckSetCookieWithDetails) { | |
2498 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
2499 EXPECT_TRUE(SetCookieWithDetails( | |
2500 cm, url_google_foo_, | |
2501 "A", "B", std::string(), "/foo", base::Time(), | |
2502 false, false)); | |
2503 SetCookieCallback callback(&other_thread_); | |
2504 base::Closure task = base::Bind( | |
2505 &net::MultiThreadedCookieMonsterTest::SetCookieWithDetailsTask, | |
2506 base::Unretained(this), | |
2507 cm, url_google_foo_, &callback); | |
2508 RunOnOtherThread(task); | |
2509 EXPECT_TRUE(callback.did_run()); | |
2510 EXPECT_TRUE(callback.result()); | |
2511 } | |
2512 | |
2513 | |
2514 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckDeleteAllCreatedBetween) { | |
2515 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
2516 CookieOptions options; | |
2517 Time now = Time::Now(); | |
2518 EXPECT_TRUE(SetCookieWithOptions(cm, url_google_, "A=B", options)); | |
2519 EXPECT_EQ(1, DeleteAllCreatedBetween(cm, now - TimeDelta::FromDays(99), | |
2520 Time())); | |
2521 EXPECT_TRUE(SetCookieWithOptions(cm, url_google_, "A=B", options)); | |
2522 DeleteCallback callback(&other_thread_); | |
2523 base::Closure task = base::Bind( | |
2524 &net::MultiThreadedCookieMonsterTest::DeleteAllCreatedBetweenTask, | |
2525 base::Unretained(this), | |
2526 cm, now - TimeDelta::FromDays(99), | |
2527 Time(), &callback); | |
2528 RunOnOtherThread(task); | |
2529 EXPECT_TRUE(callback.did_run()); | |
2530 EXPECT_EQ(1, callback.num_deleted()); | |
2531 } | |
2532 | |
2533 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckDeleteAllForHost) { | |
2534 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
2535 CookieOptions options; | |
2536 EXPECT_TRUE(SetCookieWithOptions(cm, url_google_, "A=B", options)); | |
2537 EXPECT_EQ(1, DeleteAllForHost(cm, url_google_)); | |
2538 EXPECT_TRUE(SetCookieWithOptions(cm, url_google_, "A=B", options)); | |
2539 DeleteCallback callback(&other_thread_); | |
2540 base::Closure task = base::Bind( | |
2541 &net::MultiThreadedCookieMonsterTest::DeleteAllForHostTask, | |
2542 base::Unretained(this), | |
2543 cm, url_google_, &callback); | |
2544 RunOnOtherThread(task); | |
2545 EXPECT_TRUE(callback.did_run()); | |
2546 EXPECT_EQ(1, callback.num_deleted()); | |
2547 } | |
2548 | |
2549 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckDeleteCanonicalCookie) { | |
2550 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); | |
2551 CookieOptions options; | |
2552 EXPECT_TRUE(SetCookieWithOptions(cm, url_google_, "A=B", options)); | |
2553 CookieList cookies = GetAllCookies(cm); | |
2554 CookieList::iterator it = cookies.begin(); | |
2555 EXPECT_TRUE(DeleteCanonicalCookie(cm, *it)); | |
2556 | |
2557 EXPECT_TRUE(SetCookieWithOptions(cm, url_google_, "A=B", options)); | |
2558 SetCookieCallback callback(&other_thread_); | |
2559 cookies = GetAllCookies(cm); | |
2560 it = cookies.begin(); | |
2561 base::Closure task = base::Bind( | |
2562 &net::MultiThreadedCookieMonsterTest::DeleteCanonicalCookieTask, | |
2563 base::Unretained(this), | |
2564 cm, *it, &callback); | |
2565 RunOnOtherThread(task); | |
2566 EXPECT_TRUE(callback.did_run()); | |
2567 EXPECT_TRUE(callback.result()); | |
2568 } | |
2569 | |
2570 TEST_F(CookieMonsterTest, ShortLivedSessionCookies) { | |
2571 scoped_refptr<MockPersistentCookieStore> store( | |
2572 new MockPersistentCookieStore); | |
2573 scoped_refptr<CookieMonster> cm(new CookieMonster(store, NULL)); | |
2574 | |
2575 // Create a short-lived session cookie. | |
2576 CookieOptions options; | |
2577 options.set_force_session(); | |
2578 Time current = Time::Now(); | |
2579 EXPECT_TRUE(SetCookieWithOptions(cm, url_google_, | |
2580 std::string(kValidCookieLine) + | |
2581 "; max-age=10", | |
2582 options)); | |
2583 | |
2584 // FindCookiesForKey asserts that its caller holds this lock. | |
2585 base::AutoLock auto_lock(cm->lock_); | |
2586 | |
2587 // Get cookies before the cookie has expired. | |
2588 std::vector<CookieMonster::CanonicalCookie*> cookies; | |
2589 cm->FindCookiesForKey(cm->GetKey(url_google_.host()), url_google_, | |
2590 CookieOptions(), current, false, &cookies); | |
2591 EXPECT_EQ(1U, cookies.size()); | |
2592 | |
2593 // Get cookies after the cookie has expired. | |
2594 cookies.clear(); | |
2595 cm->FindCookiesForKey(cm->GetKey(url_google_.host()), url_google_, | |
2596 CookieOptions(), current + TimeDelta::FromSeconds(20), | |
2597 false, &cookies); | |
2598 EXPECT_EQ(0U, cookies.size()); | |
2599 } | |
2600 | |
2601 TEST_F(CookieMonsterTest, InvalidExpiryTime) { | |
2602 CookieMonster::ParsedCookie pc( | |
2603 std::string(kValidCookieLine) + "; expires=Blarg arg arg"); | |
2604 scoped_ptr<CookieMonster::CanonicalCookie> cookie( | |
2605 CookieMonster::CanonicalCookie::Create(url_google_, pc)); | |
2606 | |
2607 ASSERT_FALSE(cookie->DoesExpire()); | |
2608 } | |
2609 | |
2610 // Test that CookieMonster writes session cookies into the underlying | |
2611 // CookieStore if the "persist session cookies" option is on. | |
2612 TEST_F(CookieMonsterTest, PersistSessionCookies) { | |
2613 scoped_refptr<MockPersistentCookieStore> store( | |
2614 new MockPersistentCookieStore); | |
2615 scoped_refptr<CookieMonster> cm(new CookieMonster(store, NULL)); | |
2616 cm->SetPersistSessionCookies(true); | |
2617 | |
2618 // All cookies set with SetCookie are session cookies. | |
2619 EXPECT_TRUE(SetCookie(cm, url_google_, "A=B")); | |
2620 EXPECT_EQ("A=B", GetCookies(cm, url_google_)); | |
2621 | |
2622 // The cookie was written to the backing store. | |
2623 EXPECT_EQ(1u, store->commands().size()); | |
2624 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type); | |
2625 EXPECT_EQ("A", store->commands()[0].cookie.Name()); | |
2626 EXPECT_EQ("B", store->commands()[0].cookie.Value()); | |
2627 | |
2628 // Modify the cookie. | |
2629 EXPECT_TRUE(SetCookie(cm, url_google_, "A=C")); | |
2630 EXPECT_EQ("A=C", GetCookies(cm, url_google_)); | |
2631 EXPECT_EQ(3u, store->commands().size()); | |
2632 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type); | |
2633 EXPECT_EQ("A", store->commands()[1].cookie.Name()); | |
2634 EXPECT_EQ("B", store->commands()[1].cookie.Value()); | |
2635 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type); | |
2636 EXPECT_EQ("A", store->commands()[2].cookie.Name()); | |
2637 EXPECT_EQ("C", store->commands()[2].cookie.Value()); | |
2638 | |
2639 // Delete the cookie. | |
2640 DeleteCookie(cm, url_google_, "A"); | |
2641 EXPECT_EQ("", GetCookies(cm, url_google_)); | |
2642 EXPECT_EQ(4u, store->commands().size()); | |
2643 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type); | |
2644 EXPECT_EQ("A", store->commands()[3].cookie.Name()); | |
2645 EXPECT_EQ("C", store->commands()[3].cookie.Value()); | |
2646 } | |
2647 | |
2648 // Test the commands sent to the persistent cookie store. | |
2649 TEST_F(CookieMonsterTest, PersisentCookieStorageTest) { | |
2650 scoped_refptr<MockPersistentCookieStore> store( | |
2651 new MockPersistentCookieStore); | |
2652 scoped_refptr<CookieMonster> cm(new CookieMonster(store, NULL)); | |
2653 | |
2654 // Add a cookie. | |
2655 EXPECT_TRUE(SetCookie(cm, url_google_, | |
2656 "A=B; expires=Mon, 18-Apr-22 22:50:13 GMT")); | |
2657 this->MatchCookieLines("A=B", GetCookies(cm, url_google_)); | |
2658 ASSERT_EQ(1u, store->commands().size()); | |
2659 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type); | |
2660 // Remove it. | |
2661 EXPECT_TRUE(SetCookie(cm, url_google_,"A=B; max-age=0")); | |
2662 this->MatchCookieLines("", GetCookies(cm, url_google_)); | |
2663 ASSERT_EQ(2u, store->commands().size()); | |
2664 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type); | |
2665 | |
2666 // Add a cookie. | |
2667 EXPECT_TRUE(SetCookie(cm, url_google_, | |
2668 "A=B; expires=Mon, 18-Apr-22 22:50:13 GMT")); | |
2669 this->MatchCookieLines("A=B", GetCookies(cm, url_google_)); | |
2670 ASSERT_EQ(3u, store->commands().size()); | |
2671 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type); | |
2672 // Overwrite it. | |
2673 EXPECT_TRUE(SetCookie(cm, url_google_, | |
2674 "A=Foo; expires=Mon, 18-Apr-22 22:50:14 GMT")); | |
2675 this->MatchCookieLines("A=Foo", GetCookies(cm, url_google_)); | |
2676 ASSERT_EQ(5u, store->commands().size()); | |
2677 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type); | |
2678 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[4].type); | |
2679 | |
2680 // Create some non-persistent cookies and check that they don't go to the | |
2681 // persistent storage. | |
2682 EXPECT_TRUE(SetCookie(cm, url_google_, "B=Bar")); | |
2683 this->MatchCookieLines("A=Foo; B=Bar", GetCookies(cm, url_google_)); | |
2684 EXPECT_EQ(5u, store->commands().size()); | |
2685 } | |
2686 | |
2687 } // namespace net | |
OLD | NEW |