cookie_monster_unittest.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <time.h>
6
7#include <string>
8
9#include "base/basictypes.h"
10#include "base/platform_thread.h"
11#include "base/ref_counted.h"
12#include "base/scoped_ptr.h"
13#include "base/string_util.h"
14#include "base/time.h"
15#include "googleurl/src/gurl.h"
16#include "net/base/cookie_monster.h"
17#include "testing/gtest/include/gtest/gtest.h"
18
19using base::Time;
20using base::TimeDelta;
21
22namespace {
23
24class ParsedCookieTest : public testing::Test { };
25class CookieMonsterTest : public testing::Test { };
26
27// Describes a call to one of the 3 functions of PersistentCookieStore.
28struct CookieStoreCommand {
29  enum Type {
30    ADD,
31    UPDATE_ACCESS_TIME,
32    REMOVE,
33  };
34
35  CookieStoreCommand(Type type,
36                     const std::string& key,
37                     const net::CookieMonster::CanonicalCookie& cookie)
38      : type(type), key(key), cookie(cookie) {}
39
40  Type type;
41  std::string key;  // Only applicable to the ADD command.
42  net::CookieMonster::CanonicalCookie cookie;
43};
44
45// Implementation of PersistentCookieStore that captures the
46// received commands and saves them to a list.
47// The result of calls to Load() can be configured using SetLoadExpectation().
48class MockPersistentCookieStore
49    : public net::CookieMonster::PersistentCookieStore {
50 public:
51  typedef std::vector<CookieStoreCommand> CommandList;
52
53  MockPersistentCookieStore() : load_return_value_(true) {
54  }
55
56  virtual bool Load(
57      std::vector<net::CookieMonster::KeyedCanonicalCookie>* out_cookies) {
58    bool ok = load_return_value_;
59    if (ok)
60      *out_cookies = load_result_;
61    return ok;
62  }
63
64  virtual void AddCookie(const std::string& key,
65                         const net::CookieMonster::CanonicalCookie& cookie) {
66    commands_.push_back(
67        CookieStoreCommand(CookieStoreCommand::ADD, key, cookie));
68  }
69
70  virtual void UpdateCookieAccessTime(
71      const net::CookieMonster::CanonicalCookie& cookie) {
72    commands_.push_back(CookieStoreCommand(
73        CookieStoreCommand::UPDATE_ACCESS_TIME, std::string(), cookie));
74  }
75
76  virtual void DeleteCookie(
77      const net::CookieMonster::CanonicalCookie& cookie) {
78    commands_.push_back(
79        CookieStoreCommand(CookieStoreCommand::REMOVE, std::string(), cookie));
80  }
81
82  void SetLoadExpectation(
83      bool return_value,
84      const std::vector<net::CookieMonster::KeyedCanonicalCookie>& result) {
85    load_return_value_ = return_value;
86    load_result_ = result;
87  }
88
89  const CommandList& commands() const {
90    return commands_;
91  }
92
93 private:
94  CommandList commands_;
95
96  // Deferred result to use when Load() is called.
97  bool load_return_value_;
98  std::vector<net::CookieMonster::KeyedCanonicalCookie> load_result_;
99
100  DISALLOW_COPY_AND_ASSIGN(MockPersistentCookieStore);
101};
102
103// Mock for CookieMonster::Delegate
104class MockCookieMonsterDelegate : public net::CookieMonster::Delegate {
105 public:
106  typedef std::pair<net::CookieMonster::CanonicalCookie, bool>
107      CookieNotification;
108
109  MockCookieMonsterDelegate() {}
110
111  virtual void OnCookieChanged(
112      const net::CookieMonster::CanonicalCookie& cookie,
113      bool removed) {
114    CookieNotification notification(cookie, removed);
115    changes_.push_back(notification);
116  }
117
118  const std::vector<CookieNotification>& changes() const { return changes_; }
119
120  void reset() { changes_.clear(); }
121
122 private:
123  virtual ~MockCookieMonsterDelegate() {}
124
125  std::vector<CookieNotification> changes_;
126
127  DISALLOW_COPY_AND_ASSIGN(MockCookieMonsterDelegate);
128};
129
130// Helper to build a list of KeyedCanonicalCookies.
131void AddKeyedCookieToList(
132    const std::string& key,
133    const std::string& cookie_line,
134    const Time& creation_time,
135    std::vector<net::CookieMonster::KeyedCanonicalCookie>* out_list) {
136
137  // Parse the cookie line.
138  net::CookieMonster::ParsedCookie pc(cookie_line);
139  EXPECT_TRUE(pc.IsValid());
140
141  // This helper is simplistic in interpreting a parsed cookie, in order to
142  // avoid duplicated CookieMonster's CanonPath() and CanonExpiration()
143  // functions. Would be nice to export them, and re-use here.
144  EXPECT_FALSE(pc.HasMaxAge());
145  EXPECT_TRUE(pc.HasPath());
146  Time cookie_expires = pc.HasExpires() ?
147      net::CookieMonster::ParseCookieTime(pc.Expires()) : Time();
148  std::string cookie_path = pc.Path();
149
150  scoped_ptr<net::CookieMonster::CanonicalCookie> cookie(
151      new net::CookieMonster::CanonicalCookie(
152          pc.Name(), pc.Value(), key, cookie_path,
153          pc.IsSecure(), pc.IsHttpOnly(),
154          creation_time, creation_time,
155          !cookie_expires.is_null(),
156          cookie_expires));
157
158  out_list->push_back(
159      net::CookieMonster::KeyedCanonicalCookie(
160          key, cookie.release()));
161}
162
163// Helper for DeleteAllForHost test; repopulates CM with same layout
164// each time.
165const char* kTopLevelDomainPlus1 = "http://www.harvard.edu";
166const char* kTopLevelDomainPlus2 = "http://www.math.harvard.edu";
167const char* kTopLevelDomainPlus2Secure = "https://www.math.harvard.edu";
168const char* kTopLevelDomainPlus3 =
169    "http://www.bourbaki.math.harvard.edu";
170const char* kOtherDomain = "http://www.mit.edu";
171
172void PopulateCmForDeleteAllForHost(scoped_refptr<net::CookieMonster> cm) {
173  GURL url_top_level_domain_plus_1(kTopLevelDomainPlus1);
174  GURL url_top_level_domain_plus_2(kTopLevelDomainPlus2);
175  GURL url_top_level_domain_plus_2_secure(kTopLevelDomainPlus2Secure);
176  GURL url_top_level_domain_plus_3(kTopLevelDomainPlus3);
177  GURL url_other(kOtherDomain);
178
179  cm->DeleteAll(true);
180
181  // Static population for probe:
182  //    * Three levels of domain cookie (.b.a, .c.b.a, .d.c.b.a)
183  //    * Three levels of host cookie (w.b.a, w.c.b.a, w.d.c.b.a)
184  //    * http_only cookie (w.c.b.a)
185  //    * Two secure cookies (.c.b.a, w.c.b.a)
186  //    * Two domain path cookies (.c.b.a/dir1, .c.b.a/dir1/dir2)
187  //    * Two host path cookies (w.c.b.a/dir1, w.c.b.a/dir1/dir2)
188
189  // Domain cookies
190  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_1,
191                                       "dom_1", "X", ".harvard.edu", "/",
192                                       base::Time(), false, false));
193  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2,
194                                       "dom_2", "X", ".math.harvard.edu", "/",
195                                       base::Time(), false, false));
196  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_3,
197                                       "dom_3", "X",
198                                       ".bourbaki.math.harvard.edu", "/",
199                                       base::Time(), false, false));
200
201  // Host cookies
202  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_1,
203                                       "host_1", "X", "", "/",
204                                       base::Time(), false, false));
205  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2,
206                                       "host_2", "X", "", "/",
207                                       base::Time(), false, false));
208  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_3,
209                                       "host_3", "X", "", "/",
210                                       base::Time(), false, false));
211
212  // Http_only cookie
213  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2,
214                                       "httpo_check", "X", "", "/",
215                                       base::Time(), false, true));
216
217  // Secure cookies
218  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2_secure,
219                                       "sec_dom", "X", ".math.harvard.edu",
220                                       "/", base::Time(), true, false));
221  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2_secure,
222                                       "sec_host", "X", "", "/",
223                                       base::Time(), true, false));
224
225  // Domain path cookies
226  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2,
227                                       "dom_path_1", "X",
228                                       ".math.harvard.edu", "/dir1",
229                                       base::Time(), false, false));
230  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2,
231                                       "dom_path_2", "X",
232                                       ".math.harvard.edu", "/dir1/dir2",
233                                       base::Time(), false, false));
234
235  // Host path cookies
236  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2,
237                                       "host_path_1", "X",
238                                       "", "/dir1",
239                                       base::Time(), false, false));
240  EXPECT_TRUE(cm->SetCookieWithDetails(url_top_level_domain_plus_2,
241                                       "host_path_2", "X",
242                                       "", "/dir1/dir2",
243                                       base::Time(), false, false));
244
245  EXPECT_EQ(13U, cm->GetAllCookies().size());
246}
247
248}  // namespace
249
250
251TEST(ParsedCookieTest, TestBasic) {
252  net::CookieMonster::ParsedCookie pc("a=b");
253  EXPECT_TRUE(pc.IsValid());
254  EXPECT_FALSE(pc.IsSecure());
255  EXPECT_EQ("a", pc.Name());
256  EXPECT_EQ("b", pc.Value());
257}
258
259TEST(ParsedCookieTest, TestQuoted) {
260  // These are some quoting cases which the major browsers all
261  // handle differently.  I've tested Internet Explorer 6, Opera 9.6,
262  // Firefox 3, and Safari Windows 3.2.1.  We originally tried to match
263  // Firefox closely, however we now match Internet Explorer and Safari.
264  const char* values[] = {
265    // Trailing whitespace after a quoted value.  The whitespace after
266    // the quote is stripped in all browsers.
267    "\"zzz \"  ",              "\"zzz \"",
268    // Handling a quoted value with a ';', like FOO="zz;pp"  ;
269    // IE and Safari: "zz;
270    // Firefox and Opera: "zz;pp"
271    "\"zz;pp\" ;",             "\"zz",
272    // Handling a value with multiple quoted parts, like FOO="zzz "   "ppp" ;
273    // IE and Safari: "zzz "   "ppp";
274    // Firefox: "zzz ";
275    // Opera: <rejects cookie>
276    "\"zzz \"   \"ppp\" ",     "\"zzz \"   \"ppp\"",
277    // A quote in a value that didn't start quoted.  like FOO=A"B ;
278    // IE, Safari, and Firefox: A"B;
279    // Opera: <rejects cookie>
280    "A\"B",                    "A\"B",
281  };
282
283  for (size_t i = 0; i < arraysize(values); i += 2) {
284    std::string input(values[i]);
285    std::string expected(values[i + 1]);
286
287    net::CookieMonster::ParsedCookie pc(
288        "aBc=" + input + " ; path=\"/\"  ; httponly ");
289    EXPECT_TRUE(pc.IsValid());
290    EXPECT_FALSE(pc.IsSecure());
291    EXPECT_TRUE(pc.IsHttpOnly());
292    EXPECT_TRUE(pc.HasPath());
293    EXPECT_EQ("aBc", pc.Name());
294    EXPECT_EQ(expected, pc.Value());
295
296    // If a path was quoted, the path attribute keeps the quotes.  This will
297    // make the cookie effectively useless, but path parameters aren't supposed
298    // to be quoted.  Bug 1261605.
299    EXPECT_EQ("\"/\"", pc.Path());
300  }
301}
302
303TEST(ParsedCookieTest, TestNameless) {
304  net::CookieMonster::ParsedCookie pc("BLAHHH; path=/; secure;");
305  EXPECT_TRUE(pc.IsValid());
306  EXPECT_TRUE(pc.IsSecure());
307  EXPECT_TRUE(pc.HasPath());
308  EXPECT_EQ("/", pc.Path());
309  EXPECT_EQ("", pc.Name());
310  EXPECT_EQ("BLAHHH", pc.Value());
311}
312
313TEST(ParsedCookieTest, TestAttributeCase) {
314  net::CookieMonster::ParsedCookie pc("BLAHHH; Path=/; sECuRe; httpONLY");
315  EXPECT_TRUE(pc.IsValid());
316  EXPECT_TRUE(pc.IsSecure());
317  EXPECT_TRUE(pc.IsHttpOnly());
318  EXPECT_TRUE(pc.HasPath());
319  EXPECT_EQ("/", pc.Path());
320  EXPECT_EQ("", pc.Name());
321  EXPECT_EQ("BLAHHH", pc.Value());
322  EXPECT_EQ(3U, pc.NumberOfAttributes());
323}
324
325TEST(ParsedCookieTest, TestDoubleQuotedNameless) {
326  net::CookieMonster::ParsedCookie pc("\"BLA\\\"HHH\"; path=/; secure;");
327  EXPECT_TRUE(pc.IsValid());
328  EXPECT_TRUE(pc.IsSecure());
329  EXPECT_TRUE(pc.HasPath());
330  EXPECT_EQ("/", pc.Path());
331  EXPECT_EQ("", pc.Name());
332  EXPECT_EQ("\"BLA\\\"HHH\"", pc.Value());
333  EXPECT_EQ(2U, pc.NumberOfAttributes());
334}
335
336TEST(ParsedCookieTest, QuoteOffTheEnd) {
337  net::CookieMonster::ParsedCookie pc("a=\"B");
338  EXPECT_TRUE(pc.IsValid());
339  EXPECT_EQ("a", pc.Name());
340  EXPECT_EQ("\"B", pc.Value());
341  EXPECT_EQ(0U, pc.NumberOfAttributes());
342}
343
344TEST(ParsedCookieTest, MissingName) {
345  net::CookieMonster::ParsedCookie pc("=ABC");
346  EXPECT_TRUE(pc.IsValid());
347  EXPECT_EQ("", pc.Name());
348  EXPECT_EQ("ABC", pc.Value());
349  EXPECT_EQ(0U, pc.NumberOfAttributes());
350}
351
352TEST(ParsedCookieTest, MissingValue) {
353  net::CookieMonster::ParsedCookie pc("ABC=;  path = /wee");
354  EXPECT_TRUE(pc.IsValid());
355  EXPECT_EQ("ABC", pc.Name());
356  EXPECT_EQ("", pc.Value());
357  EXPECT_TRUE(pc.HasPath());
358  EXPECT_EQ("/wee", pc.Path());
359  EXPECT_EQ(1U, pc.NumberOfAttributes());
360}
361
362TEST(ParsedCookieTest, Whitespace) {
363  net::CookieMonster::ParsedCookie pc("  A  = BC  ;secure;;;   httponly");
364  EXPECT_TRUE(pc.IsValid());
365  EXPECT_EQ("A", pc.Name());
366  EXPECT_EQ("BC", pc.Value());
367  EXPECT_FALSE(pc.HasPath());
368  EXPECT_FALSE(pc.HasDomain());
369  EXPECT_TRUE(pc.IsSecure());
370  EXPECT_TRUE(pc.IsHttpOnly());
371  // We parse anything between ; as attributes, so we end up with two
372  // attributes with an empty string name and value.
373  EXPECT_EQ(4U, pc.NumberOfAttributes());
374}
375TEST(ParsedCookieTest, MultipleEquals) {
376  net::CookieMonster::ParsedCookie pc("  A=== BC  ;secure;;;   httponly");
377  EXPECT_TRUE(pc.IsValid());
378  EXPECT_EQ("A", pc.Name());
379  EXPECT_EQ("== BC", pc.Value());
380  EXPECT_FALSE(pc.HasPath());
381  EXPECT_FALSE(pc.HasDomain());
382  EXPECT_TRUE(pc.IsSecure());
383  EXPECT_TRUE(pc.IsHttpOnly());
384  EXPECT_EQ(4U, pc.NumberOfAttributes());
385}
386
387TEST(ParsedCookieTest, QuotedTrailingWhitespace) {
388  net::CookieMonster::ParsedCookie pc("ANCUUID=\"zohNumRKgI0oxyhSsV3Z7D\"  ; "
389                                      "expires=Sun, 18-Apr-2027 21:06:29 GMT ; "
390                                      "path=/  ;  ");
391  EXPECT_TRUE(pc.IsValid());
392  EXPECT_EQ("ANCUUID", pc.Name());
393  // Stripping whitespace after the quotes matches all other major browsers.
394  EXPECT_EQ("\"zohNumRKgI0oxyhSsV3Z7D\"", pc.Value());
395  EXPECT_TRUE(pc.HasExpires());
396  EXPECT_TRUE(pc.HasPath());
397  EXPECT_EQ("/", pc.Path());
398  EXPECT_EQ(2U, pc.NumberOfAttributes());
399}
400
401TEST(ParsedCookieTest, TrailingWhitespace) {
402  net::CookieMonster::ParsedCookie pc("ANCUUID=zohNumRKgI0oxyhSsV3Z7D  ; "
403                                      "expires=Sun, 18-Apr-2027 21:06:29 GMT ; "
404                                      "path=/  ;  ");
405  EXPECT_TRUE(pc.IsValid());
406  EXPECT_EQ("ANCUUID", pc.Name());
407  EXPECT_EQ("zohNumRKgI0oxyhSsV3Z7D", pc.Value());
408  EXPECT_TRUE(pc.HasExpires());
409  EXPECT_TRUE(pc.HasPath());
410  EXPECT_EQ("/", pc.Path());
411  EXPECT_EQ(2U, pc.NumberOfAttributes());
412}
413
414TEST(ParsedCookieTest, TooManyPairs) {
415  std::string blankpairs;
416  blankpairs.resize(net::CookieMonster::ParsedCookie::kMaxPairs - 1, ';');
417
418  net::CookieMonster::ParsedCookie pc1(blankpairs + "secure");
419  EXPECT_TRUE(pc1.IsValid());
420  EXPECT_TRUE(pc1.IsSecure());
421
422  net::CookieMonster::ParsedCookie pc2(blankpairs + ";secure");
423  EXPECT_TRUE(pc2.IsValid());
424  EXPECT_FALSE(pc2.IsSecure());
425}
426
427// TODO some better test cases for invalid cookies.
428TEST(ParsedCookieTest, InvalidWhitespace) {
429  net::CookieMonster::ParsedCookie pc("    ");
430  EXPECT_FALSE(pc.IsValid());
431}
432
433TEST(ParsedCookieTest, InvalidTooLong) {
434  std::string maxstr;
435  maxstr.resize(net::CookieMonster::ParsedCookie::kMaxCookieSize, 'a');
436
437  net::CookieMonster::ParsedCookie pc1(maxstr);
438  EXPECT_TRUE(pc1.IsValid());
439
440  net::CookieMonster::ParsedCookie pc2(maxstr + "A");
441  EXPECT_FALSE(pc2.IsValid());
442}
443
444TEST(ParsedCookieTest, InvalidEmpty) {
445  net::CookieMonster::ParsedCookie pc("");
446  EXPECT_FALSE(pc.IsValid());
447}
448
449TEST(ParsedCookieTest, EmbeddedTerminator) {
450  net::CookieMonster::ParsedCookie pc1("AAA=BB\0ZYX");
451  net::CookieMonster::ParsedCookie pc2("AAA=BB\rZYX");
452  net::CookieMonster::ParsedCookie pc3("AAA=BB\nZYX");
453  EXPECT_TRUE(pc1.IsValid());
454  EXPECT_EQ("AAA", pc1.Name());
455  EXPECT_EQ("BB", pc1.Value());
456  EXPECT_TRUE(pc2.IsValid());
457  EXPECT_EQ("AAA", pc2.Name());
458  EXPECT_EQ("BB", pc2.Value());
459  EXPECT_TRUE(pc3.IsValid());
460  EXPECT_EQ("AAA", pc3.Name());
461  EXPECT_EQ("BB", pc3.Value());
462}
463
464TEST(ParsedCookieTest, ParseTokensAndValues) {
465  EXPECT_EQ("hello",
466            net::CookieMonster::ParsedCookie::ParseTokenString(
467                "hello\nworld"));
468  EXPECT_EQ("fs!!@",
469            net::CookieMonster::ParsedCookie::ParseTokenString(
470                "fs!!@;helloworld"));
471  EXPECT_EQ("hello world\tgood",
472            net::CookieMonster::ParsedCookie::ParseTokenString(
473                "hello world\tgood\rbye"));
474  EXPECT_EQ("A",
475            net::CookieMonster::ParsedCookie::ParseTokenString(
476                "A=B=C;D=E"));
477  EXPECT_EQ("hello",
478            net::CookieMonster::ParsedCookie::ParseValueString(
479                "hello\nworld"));
480  EXPECT_EQ("fs!!@",
481            net::CookieMonster::ParsedCookie::ParseValueString(
482                "fs!!@;helloworld"));
483  EXPECT_EQ("hello world\tgood",
484            net::CookieMonster::ParsedCookie::ParseValueString(
485                "hello world\tgood\rbye"));
486  EXPECT_EQ("A=B=C",
487            net::CookieMonster::ParsedCookie::ParseValueString(
488                "A=B=C;D=E"));
489}
490
491static const char kUrlGoogle[] = "http://www.google.izzle";
492static const char kUrlGoogleSecure[] = "https://www.google.izzle";
493static const char kUrlFtp[] = "ftp://ftp.google.izzle/";
494static const char kValidCookieLine[] = "A=B; path=/";
495static const char kValidDomainCookieLine[] = "A=B; path=/; domain=google.izzle";
496
497TEST(CookieMonsterTest, DomainTest) {
498  GURL url_google(kUrlGoogle);
499
500  scoped_refptr<MockPersistentCookieStore> store(
501      new MockPersistentCookieStore);
502  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, NULL));
503  EXPECT_TRUE(cm->SetCookie(url_google, "A=B"));
504  EXPECT_EQ("A=B", cm->GetCookies(url_google));
505  EXPECT_TRUE(cm->SetCookie(url_google, "C=D; domain=.google.izzle"));
506  EXPECT_EQ("A=B; C=D", cm->GetCookies(url_google));
507
508  // Verify that A=B was set as a host cookie rather than a domain
509  // cookie -- should not be accessible from a sub sub-domain.
510  EXPECT_EQ("C=D", cm->GetCookies(GURL("http://foo.www.google.izzle")));
511
512  // Test and make sure we find domain cookies on the same domain.
513  EXPECT_TRUE(cm->SetCookie(url_google, "E=F; domain=.www.google.izzle"));
514  EXPECT_EQ("A=B; C=D; E=F", cm->GetCookies(url_google));
515
516  // Test setting a domain= that doesn't start w/ a dot, should
517  // treat it as a domain cookie, as if there was a pre-pended dot.
518  EXPECT_TRUE(cm->SetCookie(url_google, "G=H; domain=www.google.izzle"));
519  EXPECT_EQ("A=B; C=D; E=F; G=H", cm->GetCookies(url_google));
520
521  // Test domain enforcement, should fail on a sub-domain or something too deep.
522  EXPECT_FALSE(cm->SetCookie(url_google, "I=J; domain=.izzle"));
523  EXPECT_EQ("", cm->GetCookies(GURL("http://a.izzle")));
524  EXPECT_FALSE(cm->SetCookie(url_google, "K=L; domain=.bla.www.google.izzle"));
525  EXPECT_EQ("C=D; E=F; G=H",
526            cm->GetCookies(GURL("http://bla.www.google.izzle")));
527  EXPECT_EQ("A=B; C=D; E=F; G=H", cm->GetCookies(url_google));
528
529  // Nothing was persisted to the backing store.
530  EXPECT_EQ(0u, store->commands().size());
531}
532
533// FireFox recognizes domains containing trailing periods as valid.
534// IE and Safari do not. Assert the expected policy here.
535TEST(CookieMonsterTest, DomainWithTrailingDotTest) {
536  scoped_refptr<MockPersistentCookieStore> store(
537      new MockPersistentCookieStore);
538  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, NULL));
539  GURL url_google("http://www.google.com");
540
541  EXPECT_FALSE(cm->SetCookie(url_google, "a=1; domain=.www.google.com."));
542  EXPECT_FALSE(cm->SetCookie(url_google, "b=2; domain=.www.google.com.."));
543  EXPECT_EQ("", cm->GetCookies(url_google));
544
545  // Nothing was persisted to the backing store.
546  EXPECT_EQ(0u, store->commands().size());
547}
548
549// Test that cookies can bet set on higher level domains.
550// http://b/issue?id=896491
551TEST(CookieMonsterTest, ValidSubdomainTest) {
552  scoped_refptr<MockPersistentCookieStore> store(
553      new MockPersistentCookieStore);
554  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, NULL));
555  GURL url_abcd("http://a.b.c.d.com");
556  GURL url_bcd("http://b.c.d.com");
557  GURL url_cd("http://c.d.com");
558  GURL url_d("http://d.com");
559
560  EXPECT_TRUE(cm->SetCookie(url_abcd, "a=1; domain=.a.b.c.d.com"));
561  EXPECT_TRUE(cm->SetCookie(url_abcd, "b=2; domain=.b.c.d.com"));
562  EXPECT_TRUE(cm->SetCookie(url_abcd, "c=3; domain=.c.d.com"));
563  EXPECT_TRUE(cm->SetCookie(url_abcd, "d=4; domain=.d.com"));
564
565  EXPECT_EQ("a=1; b=2; c=3; d=4", cm->GetCookies(url_abcd));
566  EXPECT_EQ("b=2; c=3; d=4", cm->GetCookies(url_bcd));
567  EXPECT_EQ("c=3; d=4", cm->GetCookies(url_cd));
568  EXPECT_EQ("d=4", cm->GetCookies(url_d));
569
570  // Check that the same cookie can exist on different sub-domains.
571  EXPECT_TRUE(cm->SetCookie(url_bcd, "X=bcd; domain=.b.c.d.com"));
572  EXPECT_TRUE(cm->SetCookie(url_bcd, "X=cd; domain=.c.d.com"));
573  EXPECT_EQ("b=2; c=3; d=4; X=bcd; X=cd", cm->GetCookies(url_bcd));
574  EXPECT_EQ("c=3; d=4; X=cd", cm->GetCookies(url_cd));
575
576  // Nothing was persisted to the backing store.
577  EXPECT_EQ(0u, store->commands().size());
578}
579
580// Test that setting a cookie which specifies an invalid domain has
581// no side-effect. An invalid domain in this context is one which does
582// not match the originating domain.
583// http://b/issue?id=896472
584TEST(CookieMonsterTest, InvalidDomainTest) {
585  {
586    scoped_refptr<MockPersistentCookieStore> store(
587        new MockPersistentCookieStore);
588
589    scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, NULL));
590    GURL url_foobar("http://foo.bar.com");
591
592    // More specific sub-domain than allowed.
593    EXPECT_FALSE(cm->SetCookie(url_foobar, "a=1; domain=.yo.foo.bar.com"));
594
595    EXPECT_FALSE(cm->SetCookie(url_foobar, "b=2; domain=.foo.com"));
596    EXPECT_FALSE(cm->SetCookie(url_foobar, "c=3; domain=.bar.foo.com"));
597
598    // Different TLD, but the rest is a substring.
599    EXPECT_FALSE(cm->SetCookie(url_foobar, "d=4; domain=.foo.bar.com.net"));
600
601    // A substring that isn't really a parent domain.
602    EXPECT_FALSE(cm->SetCookie(url_foobar, "e=5; domain=ar.com"));
603
604    // Completely invalid domains:
605    EXPECT_FALSE(cm->SetCookie(url_foobar, "f=6; domain=."));
606    EXPECT_FALSE(cm->SetCookie(url_foobar, "g=7; domain=/"));
607    EXPECT_FALSE(cm->SetCookie(url_foobar, "h=8; domain=http://foo.bar.com"));
608    EXPECT_FALSE(cm->SetCookie(url_foobar, "i=9; domain=..foo.bar.com"));
609    EXPECT_FALSE(cm->SetCookie(url_foobar, "j=10; domain=..bar.com"));
610
611    // Make sure there isn't something quirky in the domain canonicalization
612    // that supports full URL semantics.
613    EXPECT_FALSE(cm->SetCookie(url_foobar, "k=11; domain=.foo.bar.com?blah"));
614    EXPECT_FALSE(cm->SetCookie(url_foobar, "l=12; domain=.foo.bar.com/blah"));
615    EXPECT_FALSE(cm->SetCookie(url_foobar, "m=13; domain=.foo.bar.com:80"));
616    EXPECT_FALSE(cm->SetCookie(url_foobar, "n=14; domain=.foo.bar.com:"));
617    EXPECT_FALSE(cm->SetCookie(url_foobar, "o=15; domain=.foo.bar.com#sup"));
618
619    EXPECT_EQ("", cm->GetCookies(url_foobar));
620
621    // Nothing was persisted to the backing store.
622    EXPECT_EQ(0u, store->commands().size());
623  }
624
625  {
626    // Make sure the cookie code hasn't gotten its subdomain string handling
627    // reversed, missed a suffix check, etc.  It's important here that the two
628    // hosts below have the same domain + registry.
629    scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
630    GURL url_foocom("http://foo.com.com");
631    EXPECT_FALSE(cm->SetCookie(url_foocom, "a=1; domain=.foo.com.com.com"));
632    EXPECT_EQ("", cm->GetCookies(url_foocom));
633  }
634}
635
636// Test the behavior of omitting dot prefix from domain, should
637// function the same as FireFox.
638// http://b/issue?id=889898
639TEST(CookieMonsterTest, DomainWithoutLeadingDotTest) {
640  {  // The omission of dot results in setting a domain cookie.
641    scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
642    GURL url_hosted("http://manage.hosted.filefront.com");
643    GURL url_filefront("http://www.filefront.com");
644    EXPECT_TRUE(cm->SetCookie(url_hosted, "sawAd=1; domain=filefront.com"));
645    EXPECT_EQ("sawAd=1", cm->GetCookies(url_hosted));
646    EXPECT_EQ("sawAd=1", cm->GetCookies(url_filefront));
647  }
648
649  {  // Even when the domains match exactly, don't consider it host cookie.
650    scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
651    GURL url("http://www.google.com");
652    EXPECT_TRUE(cm->SetCookie(url, "a=1; domain=www.google.com"));
653    EXPECT_EQ("a=1", cm->GetCookies(url));
654    EXPECT_EQ("a=1", cm->GetCookies(GURL("http://sub.www.google.com")));
655    EXPECT_EQ("", cm->GetCookies(GURL("http://something-else.com")));
656  }
657}
658
659// Test that the domain specified in cookie string is treated case-insensitive
660// http://b/issue?id=896475.
661TEST(CookieMonsterTest, CaseInsensitiveDomainTest) {
662  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
663  GURL url_google("http://www.google.com");
664  EXPECT_TRUE(cm->SetCookie(url_google, "a=1; domain=.GOOGLE.COM"));
665  EXPECT_TRUE(cm->SetCookie(url_google, "b=2; domain=.wWw.gOOgLE.coM"));
666  EXPECT_EQ("a=1; b=2", cm->GetCookies(url_google));
667}
668
669TEST(CookieMonsterTest, TestIpAddress) {
670  GURL url_ip("http://1.2.3.4/weee");
671  {
672    scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
673    EXPECT_TRUE(cm->SetCookie(url_ip, kValidCookieLine));
674    EXPECT_EQ("A=B", cm->GetCookies(url_ip));
675  }
676
677  {  // IP addresses should not be able to set domain cookies.
678    scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
679    EXPECT_FALSE(cm->SetCookie(url_ip, "b=2; domain=.1.2.3.4"));
680    EXPECT_FALSE(cm->SetCookie(url_ip, "c=3; domain=.3.4"));
681    EXPECT_EQ("", cm->GetCookies(url_ip));
682    // It should be allowed to set a cookie if domain= matches the IP address
683    // exactly.  This matches IE/Firefox, even though it seems a bit wrong.
684    EXPECT_FALSE(cm->SetCookie(url_ip, "b=2; domain=1.2.3.3"));
685    EXPECT_EQ("", cm->GetCookies(url_ip));
686    EXPECT_TRUE(cm->SetCookie(url_ip, "b=2; domain=1.2.3.4"));
687    EXPECT_EQ("b=2", cm->GetCookies(url_ip));
688  }
689}
690
691// Test host cookies, and setting of cookies on TLD.
692TEST(CookieMonsterTest, TestNonDottedAndTLD) {
693  {
694    scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
695    GURL url("http://com/");
696    // Allow setting on "com", (but only as a host cookie).
697    EXPECT_TRUE(cm->SetCookie(url, "a=1"));
698    EXPECT_FALSE(cm->SetCookie(url, "b=2; domain=.com"));
699    EXPECT_FALSE(cm->SetCookie(url, "c=3; domain=com"));
700    EXPECT_EQ("a=1", cm->GetCookies(url));
701    // Make sure it doesn't show up for a normal .com, it should be a host
702    // not a domain cookie.
703    EXPECT_EQ("", cm->GetCookies(GURL("http://hopefully-no-cookies.com/")));
704    EXPECT_EQ("", cm->GetCookies(GURL("http://.com/")));
705  }
706
707  {  // http://com. should be treated the same as http://com.
708    scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
709    GURL url("http://com./index.html");
710    EXPECT_TRUE(cm->SetCookie(url, "a=1"));
711    EXPECT_EQ("a=1", cm->GetCookies(url));
712    EXPECT_EQ("", cm->GetCookies(GURL("http://hopefully-no-cookies.com./")));
713  }
714
715  {  // Should not be able to set host cookie from a subdomain.
716    scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
717    GURL url("http://a.b");
718    EXPECT_FALSE(cm->SetCookie(url, "a=1; domain=.b"));
719    EXPECT_FALSE(cm->SetCookie(url, "b=2; domain=b"));
720    EXPECT_EQ("", cm->GetCookies(url));
721  }
722
723  {  // Same test as above, but explicitly on a known TLD (com).
724    scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
725    GURL url("http://google.com");
726    EXPECT_FALSE(cm->SetCookie(url, "a=1; domain=.com"));
727    EXPECT_FALSE(cm->SetCookie(url, "b=2; domain=com"));
728    EXPECT_EQ("", cm->GetCookies(url));
729  }
730
731  {  // Make sure can't set cookie on TLD which is dotted.
732    scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
733    GURL url("http://google.co.uk");
734    EXPECT_FALSE(cm->SetCookie(url, "a=1; domain=.co.uk"));
735    EXPECT_FALSE(cm->SetCookie(url, "b=2; domain=.uk"));
736    EXPECT_EQ("", cm->GetCookies(url));
737    EXPECT_EQ("", cm->GetCookies(GURL("http://something-else.co.uk")));
738    EXPECT_EQ("", cm->GetCookies(GURL("http://something-else.uk")));
739  }
740
741  {  // Intranet URLs should only be able to set host cookies.
742    scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
743    GURL url("http://b");
744    EXPECT_TRUE(cm->SetCookie(url, "a=1"));
745    EXPECT_FALSE(cm->SetCookie(url, "b=2; domain=.b"));
746    EXPECT_FALSE(cm->SetCookie(url, "c=3; domain=b"));
747    EXPECT_EQ("a=1", cm->GetCookies(url));
748  }
749}
750
751// Test reading/writing cookies when the domain ends with a period,
752// as in "www.google.com."
753TEST(CookieMonsterTest, TestHostEndsWithDot) {
754  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
755  GURL url("http://www.google.com");
756  GURL url_with_dot("http://www.google.com.");
757  EXPECT_TRUE(cm->SetCookie(url, "a=1"));
758  EXPECT_EQ("a=1", cm->GetCookies(url));
759
760  // Do not share cookie space with the dot version of domain.
761  // Note: this is not what FireFox does, but it _is_ what IE+Safari do.
762  EXPECT_FALSE(cm->SetCookie(url, "b=2; domain=.www.google.com."));
763  EXPECT_EQ("a=1", cm->GetCookies(url));
764
765  EXPECT_TRUE(cm->SetCookie(url_with_dot, "b=2; domain=.google.com."));
766  EXPECT_EQ("b=2", cm->GetCookies(url_with_dot));
767
768  // Make sure there weren't any side effects.
769  EXPECT_EQ(cm->GetCookies(GURL("http://hopefully-no-cookies.com/")), "");
770  EXPECT_EQ("", cm->GetCookies(GURL("http://.com/")));
771}
772
773TEST(CookieMonsterTest, InvalidScheme) {
774  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
775  EXPECT_FALSE(cm->SetCookie(GURL(kUrlFtp), kValidCookieLine));
776}
777
778TEST(CookieMonsterTest, InvalidScheme_Read) {
779  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
780  EXPECT_TRUE(cm->SetCookie(GURL(kUrlGoogle), kValidDomainCookieLine));
781  EXPECT_EQ("", cm->GetCookies(GURL(kUrlFtp)));
782}
783
784TEST(CookieMonsterTest, PathTest) {
785  std::string url("http://www.google.izzle");
786  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
787  EXPECT_TRUE(cm->SetCookie(GURL(url), "A=B; path=/wee"));
788  EXPECT_EQ("A=B", cm->GetCookies(GURL(url + "/wee")));
789  EXPECT_EQ("A=B", cm->GetCookies(GURL(url + "/wee/")));
790  EXPECT_EQ("A=B", cm->GetCookies(GURL(url + "/wee/war")));
791  EXPECT_EQ("A=B", cm->GetCookies(GURL(url + "/wee/war/more/more")));
792  EXPECT_EQ("", cm->GetCookies(GURL(url + "/weehee")));
793  EXPECT_EQ("", cm->GetCookies(GURL(url + "/")));
794
795  // If we add a 0 length path, it should default to /
796  EXPECT_TRUE(cm->SetCookie(GURL(url), "A=C; path="));
797  EXPECT_EQ("A=B; A=C", cm->GetCookies(GURL(url + "/wee")));
798  EXPECT_EQ("A=C", cm->GetCookies(GURL(url + "/")));
799}
800
801TEST(CookieMonsterTest, HttpOnlyTest) {
802  GURL url_google(kUrlGoogle);
803  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
804  net::CookieOptions options;
805  options.set_include_httponly();
806
807  // Create a httponly cookie.
808  EXPECT_TRUE(cm->SetCookieWithOptions(url_google, "A=B; httponly", options));
809
810  // Check httponly read protection.
811  EXPECT_EQ("", cm->GetCookies(url_google));
812  EXPECT_EQ("A=B", cm->GetCookiesWithOptions(url_google, options));
813
814  // Check httponly overwrite protection.
815  EXPECT_FALSE(cm->SetCookie(url_google, "A=C"));
816  EXPECT_EQ("", cm->GetCookies(url_google));
817  EXPECT_EQ("A=B", cm->GetCookiesWithOptions(url_google, options));
818  EXPECT_TRUE(cm->SetCookieWithOptions(url_google, "A=C", options));
819  EXPECT_EQ("A=C", cm->GetCookies(url_google));
820
821  // Check httponly create protection.
822  EXPECT_FALSE(cm->SetCookie(url_google, "B=A; httponly"));
823  EXPECT_EQ("A=C", cm->GetCookiesWithOptions(url_google, options));
824  EXPECT_TRUE(cm->SetCookieWithOptions(url_google, "B=A; httponly", options));
825  EXPECT_EQ("A=C; B=A", cm->GetCookiesWithOptions(url_google, options));
826  EXPECT_EQ("A=C", cm->GetCookies(url_google));
827}
828
829namespace {
830
831struct CookieDateParsingCase {
832  const char* str;
833  const bool valid;
834  const time_t epoch;
835};
836
837struct DomainIsHostOnlyCase {
838  const char* str;
839  const bool is_host_only;
840};
841
842}  // namespace
843
844TEST(CookieMonsterTest, TestCookieDateParsing) {
845  const CookieDateParsingCase tests[] = {
846    { "Sat, 15-Apr-17 21:01:22 GMT",           true, 1492290082 },
847    { "Thu, 19-Apr-2007 16:00:00 GMT",         true, 1176998400 },
848    { "Wed, 25 Apr 2007 21:02:13 GMT",         true, 1177534933 },
849    { "Thu, 19/Apr\\2007 16:00:00 GMT",        true, 1176998400 },
850    { "Fri, 1 Jan 2010 01:01:50 GMT",          true, 1262307710 },
851    { "Wednesday, 1-Jan-2003 00:00:00 GMT",    true, 1041379200 },
852    { ", 1-Jan-2003 00:00:00 GMT",             true, 1041379200 },
853    { " 1-Jan-2003 00:00:00 GMT",              true, 1041379200 },
854    { "1-Jan-2003 00:00:00 GMT",               true, 1041379200 },
855    { "Wed,18-Apr-07 22:50:12 GMT",            true, 1176936612 },
856    { "WillyWonka  , 18-Apr-07 22:50:12 GMT",  true, 1176936612 },
857    { "WillyWonka  , 18-Apr-07 22:50:12",      true, 1176936612 },
858    { "WillyWonka  ,  18-apr-07   22:50:12",   true, 1176936612 },
859    { "Mon, 18-Apr-1977 22:50:13 GMT",         true, 230251813 },
860    { "Mon, 18-Apr-77 22:50:13 GMT",           true, 230251813 },
861    // If the cookie came in with the expiration quoted (which in terms of
862    // the RFC you shouldn't do), we will get string quoted.  Bug 1261605.
863    { "\"Sat, 15-Apr-17\\\"21:01:22\\\"GMT\"", true, 1492290082 },
864    // Test with full month names and partial names.
865    { "Partyday, 18- April-07 22:50:12",       true, 1176936612 },
866    { "Partyday, 18 - Apri-07 22:50:12",       true, 1176936612 },
867    { "Wednes, 1-Januar-2003 00:00:00 GMT",    true, 1041379200 },
868    // Test that we always take GMT even with other time zones or bogus
869    // values.  The RFC says everything should be GMT, and in the worst case
870    // we are 24 hours off because of zone issues.
871    { "Sat, 15-Apr-17 21:01:22",               true, 1492290082 },
872    { "Sat, 15-Apr-17 21:01:22 GMT-2",         true, 1492290082 },
873    { "Sat, 15-Apr-17 21:01:22 GMT BLAH",      true, 1492290082 },
874    { "Sat, 15-Apr-17 21:01:22 GMT-0400",      true, 1492290082 },
875    { "Sat, 15-Apr-17 21:01:22 GMT-0400 (EDT)",true, 1492290082 },
876    { "Sat, 15-Apr-17 21:01:22 DST",           true, 1492290082 },
877    { "Sat, 15-Apr-17 21:01:22 -0400",         true, 1492290082 },
878    { "Sat, 15-Apr-17 21:01:22 (hello there)", true, 1492290082 },
879    // Test that if we encounter multiple : fields, that we take the first
880    // that correctly parses.
881    { "Sat, 15-Apr-17 21:01:22 11:22:33",      true, 1492290082 },
882    { "Sat, 15-Apr-17 ::00 21:01:22",          true, 1492290082 },
883    { "Sat, 15-Apr-17 boink:z 21:01:22",       true, 1492290082 },
884    // We take the first, which in this case is invalid.
885    { "Sat, 15-Apr-17 91:22:33 21:01:22",      false, 0 },
886    // amazon.com formats their cookie expiration like this.
887    { "Thu Apr 18 22:50:12 2007 GMT",          true, 1176936612 },
888    // Test that hh:mm:ss can occur anywhere.
889    { "22:50:12 Thu Apr 18 2007 GMT",          true, 1176936612 },
890    { "Thu 22:50:12 Apr 18 2007 GMT",          true, 1176936612 },
891    { "Thu Apr 22:50:12 18 2007 GMT",          true, 1176936612 },
892    { "Thu Apr 18 22:50:12 2007 GMT",          true, 1176936612 },
893    { "Thu Apr 18 2007 22:50:12 GMT",          true, 1176936612 },
894    { "Thu Apr 18 2007 GMT 22:50:12",          true, 1176936612 },
895    // Test that the day and year can be anywhere if they are unambigious.
896    { "Sat, 15-Apr-17 21:01:22 GMT",           true, 1492290082 },
897    { "15-Sat, Apr-17 21:01:22 GMT",           true, 1492290082 },
898    { "15-Sat, Apr 21:01:22 GMT 17",           true, 1492290082 },
899    { "15-Sat, Apr 21:01:22 GMT 2017",         true, 1492290082 },
900    { "15 Apr 21:01:22 2017",                  true, 1492290082 },
901    { "15 17 Apr 21:01:22",                    true, 1492290082 },
902    { "Apr 15 17 21:01:22",                    true, 1492290082 },
903    { "Apr 15 21:01:22 17",                    true, 1492290082 },
904    { "2017 April 15 21:01:22",                true, 1492290082 },
905    { "15 April 2017 21:01:22",                true, 1492290082 },
906    // Some invalid dates
907    { "98 April 17 21:01:22",                    false, 0 },
908    { "Thu, 012-Aug-2008 20:49:07 GMT",          false, 0 },
909    { "Thu, 12-Aug-31841 20:49:07 GMT",          false, 0 },
910    { "Thu, 12-Aug-9999999999 20:49:07 GMT",     false, 0 },
911    { "Thu, 999999999999-Aug-2007 20:49:07 GMT", false, 0 },
912    { "Thu, 12-Aug-2007 20:61:99999999999 GMT",  false, 0 },
913    { "IAintNoDateFool",                         false, 0 },
914  };
915
916  Time parsed_time;
917  for (size_t i = 0; i < arraysize(tests); ++i) {
918    parsed_time = net::CookieMonster::ParseCookieTime(tests[i].str);
919    if (!tests[i].valid) {
920      EXPECT_FALSE(!parsed_time.is_null()) << tests[i].str;
921      continue;
922    }
923    EXPECT_TRUE(!parsed_time.is_null()) << tests[i].str;
924    EXPECT_EQ(tests[i].epoch, parsed_time.ToTimeT()) << tests[i].str;
925  }
926}
927
928TEST(CookieMonsterTest, TestDomainIsHostOnly) {
929  const DomainIsHostOnlyCase tests[] = {
930    { "",               true },
931    { "www.google.com", true },
932    { ".google.com",    false }
933  };
934
935  for (size_t i = 0; i < arraysize(tests); ++i) {
936    EXPECT_EQ(tests[i].is_host_only,
937              net::CookieMonster::DomainIsHostOnly(tests[i].str));
938  }
939}
940
941TEST(CookieMonsterTest, TestCookieDeletion) {
942  GURL url_google(kUrlGoogle);
943  scoped_refptr<MockPersistentCookieStore> store(
944      new MockPersistentCookieStore);
945  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, NULL));
946
947  // Create a session cookie.
948  EXPECT_TRUE(cm->SetCookie(url_google, kValidCookieLine));
949  EXPECT_EQ("A=B", cm->GetCookies(url_google));
950  // Delete it via Max-Age.
951  EXPECT_TRUE(cm->SetCookie(url_google,
952                           std::string(kValidCookieLine) + "; max-age=0"));
953  EXPECT_EQ("", cm->GetCookies(url_google));
954
955  // Create a session cookie.
956  EXPECT_TRUE(cm->SetCookie(url_google, kValidCookieLine));
957  EXPECT_EQ("A=B", cm->GetCookies(url_google));
958  // Delete it via Expires.
959  EXPECT_TRUE(cm->SetCookie(url_google,
960                           std::string(kValidCookieLine) +
961                           "; expires=Mon, 18-Apr-1977 22:50:13 GMT"));
962  EXPECT_EQ("", cm->GetCookies(url_google));
963
964  // Create a persistent cookie.
965  EXPECT_TRUE(cm->SetCookie(url_google,
966                           std::string(kValidCookieLine) +
967                           "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
968  ASSERT_EQ(1u, store->commands().size());
969  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
970
971  EXPECT_EQ("A=B", cm->GetCookies(url_google));
972  // Delete it via Max-Age.
973  EXPECT_TRUE(cm->SetCookie(url_google,
974                           std::string(kValidCookieLine) + "; max-age=0"));
975  ASSERT_EQ(2u, store->commands().size());
976  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
977  EXPECT_EQ("", cm->GetCookies(url_google));
978
979  // Create a persistent cookie.
980  EXPECT_TRUE(cm->SetCookie(url_google,
981                           std::string(kValidCookieLine) +
982                           "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
983  ASSERT_EQ(3u, store->commands().size());
984  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type);
985  EXPECT_EQ("A=B", cm->GetCookies(url_google));
986  // Delete it via Expires.
987  EXPECT_TRUE(cm->SetCookie(url_google,
988                           std::string(kValidCookieLine) +
989                           "; expires=Mon, 18-Apr-1977 22:50:13 GMT"));
990  ASSERT_EQ(4u, store->commands().size());
991  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type);
992  EXPECT_EQ("", cm->GetCookies(url_google));
993
994  // Create a persistent cookie.
995  EXPECT_TRUE(cm->SetCookie(url_google,
996                           std::string(kValidCookieLine) +
997                           "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
998  ASSERT_EQ(5u, store->commands().size());
999  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[4].type);
1000  EXPECT_EQ("A=B", cm->GetCookies(url_google));
1001  // Delete it via Expires, with a unix epoch of 0.
1002  EXPECT_TRUE(cm->SetCookie(url_google,
1003                           std::string(kValidCookieLine) +
1004                           "; expires=Thu, 1-Jan-1970 00:00:00 GMT"));
1005  ASSERT_EQ(6u, store->commands().size());
1006  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[5].type);
1007  EXPECT_EQ("", cm->GetCookies(url_google));
1008}
1009
1010TEST(CookieMonsterTest, TestCookieDeleteAll) {
1011  GURL url_google(kUrlGoogle);
1012  scoped_refptr<MockPersistentCookieStore> store(
1013      new MockPersistentCookieStore);
1014  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, NULL));
1015  net::CookieOptions options;
1016  options.set_include_httponly();
1017
1018  EXPECT_TRUE(cm->SetCookie(url_google, kValidCookieLine));
1019  EXPECT_EQ("A=B", cm->GetCookies(url_google));
1020
1021  EXPECT_TRUE(cm->SetCookieWithOptions(url_google, "C=D; httponly", options));
1022  EXPECT_EQ("A=B; C=D", cm->GetCookiesWithOptions(url_google, options));
1023
1024  EXPECT_EQ(2, cm->DeleteAll(false));
1025  EXPECT_EQ("", cm->GetCookiesWithOptions(url_google, options));
1026
1027  EXPECT_EQ(0u, store->commands().size());
1028
1029  // Create a persistent cookie.
1030  EXPECT_TRUE(cm->SetCookie(url_google,
1031                            std::string(kValidCookieLine) +
1032                            "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
1033  ASSERT_EQ(1u, store->commands().size());
1034  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
1035
1036  EXPECT_EQ(1, cm->DeleteAll(true));  // sync_to_store = true.
1037  ASSERT_EQ(2u, store->commands().size());
1038  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
1039
1040  EXPECT_EQ("", cm->GetCookiesWithOptions(url_google, options));
1041}
1042
1043TEST(CookieMonsterTest, TestCookieDeleteAllCreatedAfterTimestamp) {
1044  GURL url_google(kUrlGoogle);
1045  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
1046  Time now = Time::Now();
1047
1048  // Nothing has been added so nothing should be deleted.
1049  EXPECT_EQ(0, cm->DeleteAllCreatedAfter(now - TimeDelta::FromDays(99), false));
1050
1051  // Create 3 cookies with creation date of today, yesterday and the day before.
1052  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-0=Now", now));
1053  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-1=Yesterday",
1054                                           now - TimeDelta::FromDays(1)));
1055  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-2=DayBefore",
1056                                           now - TimeDelta::FromDays(2)));
1057
1058  // Try to delete everything from now onwards.
1059  EXPECT_EQ(1, cm->DeleteAllCreatedAfter(now, false));
1060  // Now delete the one cookie created in the last day.
1061  EXPECT_EQ(1, cm->DeleteAllCreatedAfter(now - TimeDelta::FromDays(1), false));
1062  // Now effectively delete all cookies just created (1 is remaining).
1063  EXPECT_EQ(1, cm->DeleteAllCreatedAfter(now - TimeDelta::FromDays(99), false));
1064
1065  // Make sure everything is gone.
1066  EXPECT_EQ(0, cm->DeleteAllCreatedAfter(Time(), false));
1067  // Really make sure everything is gone.
1068  EXPECT_EQ(0, cm->DeleteAll(false));
1069}
1070
1071TEST(CookieMonsterTest, TestCookieDeleteAllCreatedBetweenTimestamps) {
1072  GURL url_google(kUrlGoogle);
1073  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
1074  Time now = Time::Now();
1075
1076  // Nothing has been added so nothing should be deleted.
1077  EXPECT_EQ(0, cm->DeleteAllCreatedAfter(now - TimeDelta::FromDays(99), false));
1078
1079  // Create 3 cookies with creation date of today, yesterday and the day before.
1080  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-0=Now", now));
1081  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-1=Yesterday",
1082                                           now - TimeDelta::FromDays(1)));
1083  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-2=DayBefore",
1084                                           now - TimeDelta::FromDays(2)));
1085  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-3=ThreeDays",
1086                                           now - TimeDelta::FromDays(3)));
1087  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google, "T-7=LastWeek",
1088                                           now - TimeDelta::FromDays(7)));
1089
1090  // Try to delete threedays and the daybefore.
1091  EXPECT_EQ(2, cm->DeleteAllCreatedBetween(now - TimeDelta::FromDays(3),
1092                                          now - TimeDelta::FromDays(1),
1093                                          false));
1094
1095  // Try to delete yesterday, also make sure that delete_end is not
1096  // inclusive.
1097  EXPECT_EQ(1, cm->DeleteAllCreatedBetween(now - TimeDelta::FromDays(2),
1098                                          now,
1099                                          false));
1100
1101  // Make sure the delete_begin is inclusive.
1102  EXPECT_EQ(1, cm->DeleteAllCreatedBetween(now - TimeDelta::FromDays(7),
1103                                          now,
1104                                          false));
1105
1106  // Delete the last (now) item.
1107  EXPECT_EQ(1, cm->DeleteAllCreatedAfter(Time(), false));
1108
1109  // Really make sure everything is gone.
1110  EXPECT_EQ(0, cm->DeleteAll(false));
1111}
1112
1113TEST(CookieMonsterTest, TestSecure) {
1114  GURL url_google(kUrlGoogle);
1115  GURL url_google_secure(kUrlGoogleSecure);
1116  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
1117
1118  EXPECT_TRUE(cm->SetCookie(url_google, "A=B"));
1119  EXPECT_EQ("A=B", cm->GetCookies(url_google));
1120  EXPECT_EQ("A=B", cm->GetCookies(url_google_secure));
1121
1122  EXPECT_TRUE(cm->SetCookie(url_google_secure, "A=B; secure"));
1123  // The secure should overwrite the non-secure.
1124  EXPECT_EQ("", cm->GetCookies(url_google));
1125  EXPECT_EQ("A=B", cm->GetCookies(url_google_secure));
1126
1127  EXPECT_TRUE(cm->SetCookie(url_google_secure, "D=E; secure"));
1128  EXPECT_EQ("", cm->GetCookies(url_google));
1129  EXPECT_EQ("A=B; D=E", cm->GetCookies(url_google_secure));
1130
1131  EXPECT_TRUE(cm->SetCookie(url_google_secure, "A=B"));
1132  // The non-secure should overwrite the secure.
1133  EXPECT_EQ("A=B", cm->GetCookies(url_google));
1134  EXPECT_EQ("D=E; A=B", cm->GetCookies(url_google_secure));
1135}
1136
1137static Time GetFirstCookieAccessDate(net::CookieMonster* cm) {
1138  const net::CookieMonster::CookieList all_cookies(cm->GetAllCookies());
1139  return all_cookies.front().LastAccessDate();
1140}
1141
1142static const int kLastAccessThresholdMilliseconds = 200;
1143
1144TEST(CookieMonsterTest, TestLastAccess) {
1145  GURL url_google(kUrlGoogle);
1146  scoped_refptr<net::CookieMonster> cm(
1147      new net::CookieMonster(NULL, NULL, kLastAccessThresholdMilliseconds));
1148
1149  EXPECT_TRUE(cm->SetCookie(url_google, "A=B"));
1150  const Time last_access_date(GetFirstCookieAccessDate(cm));
1151
1152  // Reading the cookie again immediately shouldn't update the access date,
1153  // since we're inside the threshold.
1154  EXPECT_EQ("A=B", cm->GetCookies(url_google));
1155  EXPECT_TRUE(last_access_date == GetFirstCookieAccessDate(cm));
1156
1157  // Reading after a short wait should update the access date.
1158  PlatformThread::Sleep(kLastAccessThresholdMilliseconds + 20);
1159  EXPECT_EQ("A=B", cm->GetCookies(url_google));
1160  EXPECT_FALSE(last_access_date == GetFirstCookieAccessDate(cm));
1161}
1162
1163static int CountInString(const std::string& str, char c) {
1164  int count = 0;
1165  for (std::string::const_iterator it = str.begin();
1166       it != str.end(); ++it) {
1167    if (*it == c)
1168      ++count;
1169  }
1170  return count;
1171}
1172
1173TEST(CookieMonsterTest, TestHostGarbageCollection) {
1174  GURL url_google(kUrlGoogle);
1175  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
1176  // Add a bunch of cookies on a single host, should purge them.
1177  for (int i = 0; i < 101; i++) {
1178    std::string cookie = StringPrintf("a%03d=b", i);
1179    EXPECT_TRUE(cm->SetCookie(url_google, cookie));
1180    std::string cookies = cm->GetCookies(url_google);
1181    // Make sure we find it in the cookies.
1182    EXPECT_TRUE(cookies.find(cookie) != std::string::npos);
1183    // Count the number of cookies.
1184    EXPECT_LE(CountInString(cookies, '='), 70);
1185  }
1186}
1187
1188TEST(CookieMonsterTest, TestTotalGarbageCollection) {
1189  scoped_refptr<net::CookieMonster> cm(
1190      new net::CookieMonster(NULL, NULL, kLastAccessThresholdMilliseconds));
1191
1192  // Add a bunch of cookies on a bunch of host, some should get purged.
1193  const GURL sticky_cookie("http://a0000.izzle");
1194  for (int i = 0; i < 4000; ++i) {
1195    GURL url(StringPrintf("http://a%04d.izzle", i));
1196    EXPECT_TRUE(cm->SetCookie(url, "a=b"));
1197    EXPECT_EQ("a=b", cm->GetCookies(url));
1198
1199    // Keep touching the first cookie to ensure it's not purged (since it will
1200    // always have the most recent access time).
1201    if (!(i % 500)) {
1202      // Ensure the timestamps will be different enough to update.
1203      PlatformThread::Sleep(kLastAccessThresholdMilliseconds + 20);
1204      EXPECT_EQ("a=b", cm->GetCookies(sticky_cookie));
1205    }
1206  }
1207
1208  // Check that cookies that still exist.
1209  for (int i = 0; i < 4000; ++i) {
1210    GURL url(StringPrintf("http://a%04d.izzle", i));
1211    if ((i == 0) || (i > 1001)) {
1212      // Cookies should still be around.
1213      EXPECT_FALSE(cm->GetCookies(url).empty());
1214    } else if (i < 701) {
1215      // Cookies should have gotten purged.
1216      EXPECT_TRUE(cm->GetCookies(url).empty());
1217    }
1218  }
1219}
1220
1221// Formerly NetUtilTest.CookieTest back when we used wininet's cookie handling.
1222TEST(CookieMonsterTest, NetUtilCookieTest) {
1223  const GURL test_url("http://mojo.jojo.google.izzle/");
1224
1225  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
1226
1227  EXPECT_TRUE(cm->SetCookie(test_url, "foo=bar"));
1228  std::string value = cm->GetCookies(test_url);
1229  EXPECT_EQ("foo=bar", value);
1230
1231  // test that we can retrieve all cookies:
1232  EXPECT_TRUE(cm->SetCookie(test_url, "x=1"));
1233  EXPECT_TRUE(cm->SetCookie(test_url, "y=2"));
1234
1235  std::string result = cm->GetCookies(test_url);
1236  EXPECT_FALSE(result.empty());
1237  EXPECT_NE(result.find("x=1"), std::string::npos) << result;
1238  EXPECT_NE(result.find("y=2"), std::string::npos) << result;
1239}
1240
1241static bool FindAndDeleteCookie(net::CookieMonster* cm,
1242                                const std::string& domain,
1243                                const std::string& name) {
1244  net::CookieMonster::CookieList cookies = cm->GetAllCookies();
1245  for (net::CookieMonster::CookieList::iterator it = cookies.begin();
1246       it != cookies.end(); ++it)
1247    if (it->Domain() == domain && it->Name() == name)
1248      return cm->DeleteCookie(domain, *it, false);
1249  return false;
1250}
1251
1252TEST(CookieMonsterTest, TestDeleteSingleCookie) {
1253  GURL url_google(kUrlGoogle);
1254
1255  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
1256
1257  EXPECT_TRUE(cm->SetCookie(url_google, "A=B"));
1258  EXPECT_TRUE(cm->SetCookie(url_google, "C=D"));
1259  EXPECT_TRUE(cm->SetCookie(url_google, "E=F"));
1260  EXPECT_EQ("A=B; C=D; E=F", cm->GetCookies(url_google));
1261
1262  EXPECT_TRUE(FindAndDeleteCookie(cm, url_google.host(), "C"));
1263  EXPECT_EQ("A=B; E=F", cm->GetCookies(url_google));
1264
1265  EXPECT_FALSE(FindAndDeleteCookie(cm, "random.host", "E"));
1266  EXPECT_EQ("A=B; E=F", cm->GetCookies(url_google));
1267}
1268
1269TEST(CookieMonsterTest, SetCookieableSchemes) {
1270  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
1271  scoped_refptr<net::CookieMonster> cm_foo(new net::CookieMonster(NULL, NULL));
1272
1273  // Only cm_foo should allow foo:// cookies.
1274  const char* kSchemes[] = {"foo"};
1275  cm_foo->SetCookieableSchemes(kSchemes, 1);
1276
1277  GURL foo_url("foo://host/path");
1278  GURL http_url("http://host/path");
1279
1280  EXPECT_TRUE(cm->SetCookie(http_url, "x=1"));
1281  EXPECT_FALSE(cm->SetCookie(foo_url, "x=1"));
1282  EXPECT_TRUE(cm_foo->SetCookie(foo_url, "x=1"));
1283  EXPECT_FALSE(cm_foo->SetCookie(http_url, "x=1"));
1284}
1285
1286TEST(CookieMonsterTest, GetAllCookiesForURL) {
1287  GURL url_google(kUrlGoogle);
1288  GURL url_google_secure(kUrlGoogleSecure);
1289
1290  scoped_refptr<net::CookieMonster> cm(
1291      new net::CookieMonster(NULL, NULL, kLastAccessThresholdMilliseconds));
1292
1293  // Create an httponly cookie.
1294  net::CookieOptions options;
1295  options.set_include_httponly();
1296
1297  EXPECT_TRUE(cm->SetCookieWithOptions(url_google, "A=B; httponly", options));
1298  EXPECT_TRUE(cm->SetCookieWithOptions(url_google,
1299                                       "C=D; domain=.google.izzle",
1300                                       options));
1301  EXPECT_TRUE(cm->SetCookieWithOptions(url_google_secure,
1302                                       "E=F; domain=.google.izzle; secure",
1303                                       options));
1304
1305  const Time last_access_date(GetFirstCookieAccessDate(cm));
1306
1307  PlatformThread::Sleep(kLastAccessThresholdMilliseconds + 20);
1308
1309  // Check cookies for url.
1310  net::CookieMonster::CookieList cookies =
1311      cm->GetAllCookiesForURL(url_google);
1312  net::CookieMonster::CookieList::iterator it = cookies.begin();
1313
1314  ASSERT_TRUE(it != cookies.end());
1315  EXPECT_EQ("www.google.izzle", it->Domain());
1316  EXPECT_EQ("A", it->Name());
1317
1318  ASSERT_TRUE(++it != cookies.end());
1319  EXPECT_EQ(".google.izzle", it->Domain());
1320  EXPECT_EQ("C", it->Name());
1321
1322  ASSERT_TRUE(++it == cookies.end());
1323
1324  // Test secure cookies.
1325  cookies = cm->GetAllCookiesForURL(url_google_secure);
1326  it = cookies.begin();
1327
1328  ASSERT_TRUE(it != cookies.end());
1329  EXPECT_EQ("www.google.izzle", it->Domain());
1330  EXPECT_EQ("A", it->Name());
1331
1332  ASSERT_TRUE(++it != cookies.end());
1333  EXPECT_EQ(".google.izzle", it->Domain());
1334  EXPECT_EQ("C", it->Name());
1335
1336  ASSERT_TRUE(++it != cookies.end());
1337  EXPECT_EQ(".google.izzle", it->Domain());
1338  EXPECT_EQ("E", it->Name());
1339
1340  ASSERT_TRUE(++it == cookies.end());
1341
1342  // Reading after a short wait should not update the access date.
1343  EXPECT_TRUE(last_access_date == GetFirstCookieAccessDate(cm));
1344}
1345
1346TEST(CookieMonsterTest, GetAllCookiesForURLPathMatching) {
1347  GURL url_google(kUrlGoogle);
1348  GURL url_google_foo("http://www.google.izzle/foo");
1349  GURL url_google_bar("http://www.google.izzle/bar");
1350
1351  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
1352  net::CookieOptions options;
1353
1354  EXPECT_TRUE(cm->SetCookieWithOptions(url_google_foo,
1355                                       "A=B; path=/foo;",
1356                                       options));
1357  EXPECT_TRUE(cm->SetCookieWithOptions(url_google_bar,
1358                                       "C=D; path=/bar;",
1359                                       options));
1360  EXPECT_TRUE(cm->SetCookieWithOptions(url_google,
1361                                       "E=F;",
1362                                       options));
1363
1364  net::CookieMonster::CookieList cookies =
1365      cm->GetAllCookiesForURL(url_google_foo);
1366  net::CookieMonster::CookieList::iterator it = cookies.begin();
1367
1368  ASSERT_TRUE(it != cookies.end());
1369  EXPECT_EQ("A", it->Name());
1370  EXPECT_EQ("/foo", it->Path());
1371
1372  ASSERT_TRUE(++it != cookies.end());
1373  EXPECT_EQ("E", it->Name());
1374  EXPECT_EQ("/", it->Path());
1375
1376  ASSERT_TRUE(++it == cookies.end());
1377
1378  cookies = cm->GetAllCookiesForURL(url_google_bar);
1379  it = cookies.begin();
1380
1381  ASSERT_TRUE(it != cookies.end());
1382  EXPECT_EQ("C", it->Name());
1383  EXPECT_EQ("/bar", it->Path());
1384
1385  ASSERT_TRUE(++it != cookies.end());
1386  EXPECT_EQ("E", it->Name());
1387  EXPECT_EQ("/", it->Path());
1388
1389  ASSERT_TRUE(++it == cookies.end());
1390}
1391
1392TEST(CookieMonsterTest, DeleteCookieByName) {
1393  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
1394  GURL url_google(kUrlGoogle);
1395
1396  EXPECT_TRUE(cm->SetCookie(url_google, "A=A1; path=/"));
1397  EXPECT_TRUE(cm->SetCookie(url_google, "A=A2; path=/foo"));
1398  EXPECT_TRUE(cm->SetCookie(url_google, "A=A3; path=/bar"));
1399  EXPECT_TRUE(cm->SetCookie(url_google, "B=B1; path=/"));
1400  EXPECT_TRUE(cm->SetCookie(url_google, "B=B2; path=/foo"));
1401  EXPECT_TRUE(cm->SetCookie(url_google, "B=B3; path=/bar"));
1402
1403  cm->DeleteCookie(GURL(std::string(kUrlGoogle) + "/foo/bar"), "A");
1404
1405  net::CookieMonster::CookieList cookies = cm->GetAllCookies();
1406  size_t expected_size = 4;
1407  EXPECT_EQ(expected_size, cookies.size());
1408  for (net::CookieMonster::CookieList::iterator it = cookies.begin();
1409       it != cookies.end(); ++it) {
1410    EXPECT_NE("A1", it->Value());
1411    EXPECT_NE("A2", it->Value());
1412  }
1413}
1414
1415// Test that overwriting persistent cookies deletes the old one from the
1416// backing store.
1417TEST(CookieMonsterTest, OverwritePersistentCookie) {
1418  GURL url_google("http://www.google.com/");
1419  GURL url_chromium("http://chromium.org");
1420  scoped_refptr<MockPersistentCookieStore> store(
1421      new MockPersistentCookieStore);
1422  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, NULL));
1423
1424  // Insert a cookie "a" for path "/path1"
1425  EXPECT_TRUE(
1426      cm->SetCookie(url_google, "a=val1; path=/path1; "
1427                                "expires=Mon, 18-Apr-22 22:50:13 GMT"));
1428  ASSERT_EQ(1u, store->commands().size());
1429  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
1430
1431  // Insert a cookie "b" for path "/path1"
1432  EXPECT_TRUE(
1433      cm->SetCookie(url_google, "b=val1; path=/path1; "
1434                                "expires=Mon, 18-Apr-22 22:50:14 GMT"));
1435  ASSERT_EQ(2u, store->commands().size());
1436  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[1].type);
1437
1438  // Insert a cookie "b" for path "/path1", that is httponly. This should
1439  // overwrite the non-http-only version.
1440  net::CookieOptions allow_httponly;
1441  allow_httponly.set_include_httponly();
1442  EXPECT_TRUE(
1443    cm->SetCookieWithOptions(url_google,
1444                             "b=val2; path=/path1; httponly; "
1445                             "expires=Mon, 18-Apr-22 22:50:14 GMT",
1446                             allow_httponly));
1447  ASSERT_EQ(4u, store->commands().size());
1448  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[2].type);
1449  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[3].type);
1450
1451  // Insert a cookie "a" for path "/path1". This should overwrite.
1452  EXPECT_TRUE(cm->SetCookie(url_google,
1453                            "a=val33; path=/path1; "
1454                            "expires=Mon, 18-Apr-22 22:50:14 GMT"));
1455  ASSERT_EQ(6u, store->commands().size());
1456  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[4].type);
1457  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[5].type);
1458
1459  // Insert a cookie "a" for path "/path2". This should NOT overwrite
1460  // cookie "a", since the path is different.
1461  EXPECT_TRUE(cm->SetCookie(url_google,
1462                            "a=val9; path=/path2; "
1463                            "expires=Mon, 18-Apr-22 22:50:14 GMT"));
1464  ASSERT_EQ(7u, store->commands().size());
1465  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[6].type);
1466
1467  // Insert a cookie "a" for path "/path1", but this time for "chromium.org".
1468  // Although the name and path match, the hostnames do not, so shouldn't
1469  // overwrite.
1470  EXPECT_TRUE(cm->SetCookie(url_chromium,
1471                            "a=val99; path=/path1; "
1472                            "expires=Mon, 18-Apr-22 22:50:14 GMT"));
1473  ASSERT_EQ(8u, store->commands().size());
1474  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[7].type);
1475
1476  EXPECT_EQ("a=val33", cm->GetCookies(GURL("http://www.google.com/path1")));
1477  EXPECT_EQ("a=val9", cm->GetCookies(GURL("http://www.google.com/path2")));
1478  EXPECT_EQ("a=val99", cm->GetCookies(GURL("http://chromium.org/path1")));
1479}
1480
1481// Tests importing from a persistent cookie store that contains duplicate
1482// equivalent cookies. This situation should be handled by removing the
1483// duplicate cookie (both from the in-memory cache, and from the backing store).
1484//
1485// This is a regression test for: http://crbug.com/17855.
1486TEST(CookieMonsterTest, DontImportDuplicateCookies) {
1487  GURL url_google("http://www.google.com/");
1488
1489  scoped_refptr<MockPersistentCookieStore> store(
1490      new MockPersistentCookieStore);
1491
1492  // We will fill some initial cookies into the PersistentCookieStore,
1493  // to simulate a database with 4 duplicates.
1494  std::vector<net::CookieMonster::KeyedCanonicalCookie> initial_cookies;
1495
1496  // Insert 4 cookies with name "X" on path "/", with varying creation
1497  // dates. We expect only the most recent one to be preserved following
1498  // the import.
1499
1500  AddKeyedCookieToList("www.google.com",
1501                       "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1502                       Time::Now() + TimeDelta::FromDays(3),
1503                       &initial_cookies);
1504
1505  AddKeyedCookieToList("www.google.com",
1506                       "X=2; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1507                       Time::Now() + TimeDelta::FromDays(1),
1508                       &initial_cookies);
1509
1510  // ===> This one is the WINNER (biggest creation time).  <====
1511  AddKeyedCookieToList("www.google.com",
1512                       "X=3; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1513                       Time::Now() + TimeDelta::FromDays(4),
1514                       &initial_cookies);
1515
1516  AddKeyedCookieToList("www.google.com",
1517                       "X=4; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1518                       Time::Now(),
1519                       &initial_cookies);
1520
1521  // Insert 2 cookies with name "X" on path "/2", with varying creation
1522  // dates. We expect only the most recent one to be preserved the import.
1523
1524  // ===> This one is the WINNER (biggest creation time).  <====
1525  AddKeyedCookieToList("www.google.com",
1526                       "X=a1; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
1527                       Time::Now() + TimeDelta::FromDays(9),
1528                       &initial_cookies);
1529
1530  AddKeyedCookieToList("www.google.com",
1531                       "X=a2; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
1532                       Time::Now() + TimeDelta::FromDays(1),
1533                       &initial_cookies);
1534
1535  // Insert 1 cookie with name "Y" on path "/".
1536  AddKeyedCookieToList("www.google.com",
1537                       "Y=a; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1538                       Time::Now() + TimeDelta::FromDays(9),
1539                       &initial_cookies);
1540
1541  // Inject our initial cookies into the mock PersistentCookieStore.
1542  store->SetLoadExpectation(true, initial_cookies);
1543
1544  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, NULL));
1545
1546  // Verify that duplicates were not imported for path "/".
1547  // (If this had failed, GetCookies() would have also returned X=1, X=2, X=4).
1548  EXPECT_EQ("X=3; Y=a", cm->GetCookies(GURL("http://www.google.com/")));
1549
1550  // Verify that same-named cookie on a different path ("/x2") didn't get
1551  // messed up.
1552  EXPECT_EQ("X=a1; X=3; Y=a",
1553            cm->GetCookies(GURL("http://www.google.com/2/x")));
1554
1555  // Verify that the PersistentCookieStore was told to kill its 4 duplicates.
1556  ASSERT_EQ(4u, store->commands().size());
1557  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[0].type);
1558  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
1559  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[2].type);
1560  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type);
1561}
1562
1563TEST(CookieMonsterTest, Delegate) {
1564  GURL url_google(kUrlGoogle);
1565
1566  scoped_refptr<MockPersistentCookieStore> store(
1567      new MockPersistentCookieStore);
1568  scoped_refptr<MockCookieMonsterDelegate> delegate(
1569      new MockCookieMonsterDelegate);
1570  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, delegate));
1571
1572  EXPECT_TRUE(cm->SetCookie(url_google, "A=B"));
1573  EXPECT_TRUE(cm->SetCookie(url_google, "C=D"));
1574  EXPECT_TRUE(cm->SetCookie(url_google, "E=F"));
1575  EXPECT_EQ("A=B; C=D; E=F", cm->GetCookies(url_google));
1576  ASSERT_EQ(3u, delegate->changes().size());
1577  EXPECT_EQ(false, delegate->changes()[0].second);
1578  EXPECT_EQ(url_google.host(), delegate->changes()[0].first.Domain());
1579  EXPECT_EQ("A", delegate->changes()[0].first.Name());
1580  EXPECT_EQ("B", delegate->changes()[0].first.Value());
1581  EXPECT_EQ(url_google.host(), delegate->changes()[1].first.Domain());
1582  EXPECT_EQ(false, delegate->changes()[1].second);
1583  EXPECT_EQ("C", delegate->changes()[1].first.Name());
1584  EXPECT_EQ("D", delegate->changes()[1].first.Value());
1585  EXPECT_EQ(url_google.host(), delegate->changes()[2].first.Domain());
1586  EXPECT_EQ(false, delegate->changes()[2].second);
1587  EXPECT_EQ("E", delegate->changes()[2].first.Name());
1588  EXPECT_EQ("F", delegate->changes()[2].first.Value());
1589  delegate->reset();
1590
1591  EXPECT_TRUE(FindAndDeleteCookie(cm, url_google.host(), "C"));
1592  EXPECT_EQ("A=B; E=F", cm->GetCookies(url_google));
1593  ASSERT_EQ(1u, delegate->changes().size());
1594  EXPECT_EQ(url_google.host(), delegate->changes()[0].first.Domain());
1595  EXPECT_EQ(true, delegate->changes()[0].second);
1596  EXPECT_EQ("C", delegate->changes()[0].first.Name());
1597  EXPECT_EQ("D", delegate->changes()[0].first.Value());
1598  delegate->reset();
1599
1600  EXPECT_FALSE(FindAndDeleteCookie(cm, "random.host", "E"));
1601  EXPECT_EQ("A=B; E=F", cm->GetCookies(url_google));
1602  EXPECT_EQ(0u, delegate->changes().size());
1603
1604  // Insert a cookie "a" for path "/path1"
1605  EXPECT_TRUE(
1606      cm->SetCookie(url_google, "a=val1; path=/path1; "
1607                                "expires=Mon, 18-Apr-22 22:50:13 GMT"));
1608  ASSERT_EQ(1u, store->commands().size());
1609  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
1610  ASSERT_EQ(1u, delegate->changes().size());
1611  EXPECT_EQ(false, delegate->changes()[0].second);
1612  EXPECT_EQ(url_google.host(), delegate->changes()[0].first.Domain());
1613  EXPECT_EQ("a", delegate->changes()[0].first.Name());
1614  EXPECT_EQ("val1", delegate->changes()[0].first.Value());
1615  delegate->reset();
1616
1617  // Insert a cookie "a" for path "/path1", that is httponly. This should
1618  // overwrite the non-http-only version.
1619  net::CookieOptions allow_httponly;
1620  allow_httponly.set_include_httponly();
1621  EXPECT_TRUE(
1622    cm->SetCookieWithOptions(url_google,
1623                             "a=val2; path=/path1; httponly; "
1624                             "expires=Mon, 18-Apr-22 22:50:14 GMT",
1625                             allow_httponly));
1626  ASSERT_EQ(3u, store->commands().size());
1627  EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
1628  EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type);
1629  ASSERT_EQ(2u, delegate->changes().size());
1630  EXPECT_EQ(url_google.host(), delegate->changes()[0].first.Domain());
1631  EXPECT_EQ(true, delegate->changes()[0].second);
1632  EXPECT_EQ("a", delegate->changes()[0].first.Name());
1633  EXPECT_EQ("val1", delegate->changes()[0].first.Value());
1634  EXPECT_EQ(url_google.host(), delegate->changes()[1].first.Domain());
1635  EXPECT_EQ(false, delegate->changes()[1].second);
1636  EXPECT_EQ("a", delegate->changes()[1].first.Name());
1637  EXPECT_EQ("val2", delegate->changes()[1].first.Value());
1638  delegate->reset();
1639}
1640
1641TEST(CookieMonsterTest, SetCookieWithDetails) {
1642  GURL url_google(kUrlGoogle);
1643  GURL url_google_foo("http://www.google.izzle/foo");
1644  GURL url_google_bar("http://www.google.izzle/bar");
1645  GURL url_google_secure(kUrlGoogleSecure);
1646
1647  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
1648
1649  EXPECT_TRUE(cm->SetCookieWithDetails(
1650      url_google_foo, "A", "B", std::string(), "/foo", base::Time(),
1651      false, false));
1652  EXPECT_TRUE(cm->SetCookieWithDetails(
1653      url_google_bar, "C", "D", "google.izzle", "/bar", base::Time(),
1654      false, true));
1655  EXPECT_TRUE(cm->SetCookieWithDetails(
1656      url_google, "E", "F", std::string(), std::string(), base::Time(),
1657      true, false));
1658
1659  // Test that malformed attributes fail to set the cookie.
1660  EXPECT_FALSE(cm->SetCookieWithDetails(
1661      url_google_foo, " A", "B", std::string(), "/foo", base::Time(),
1662      false, false));
1663  EXPECT_FALSE(cm->SetCookieWithDetails(
1664      url_google_foo, "A;", "B", std::string(), "/foo", base::Time(),
1665      false, false));
1666  EXPECT_FALSE(cm->SetCookieWithDetails(
1667      url_google_foo, "A=", "B", std::string(), "/foo", base::Time(),
1668      false, false));
1669  EXPECT_FALSE(cm->SetCookieWithDetails(
1670      url_google_foo, "A", "B", "google.ozzzzzzle", "foo", base::Time(),
1671      false, false));
1672  EXPECT_FALSE(cm->SetCookieWithDetails(
1673      url_google_foo, "A=", "B", std::string(), "foo", base::Time(),
1674      false, false));
1675
1676  net::CookieMonster::CookieList cookies =
1677      cm->GetAllCookiesForURL(url_google_foo);
1678  net::CookieMonster::CookieList::iterator it = cookies.begin();
1679
1680  ASSERT_TRUE(it != cookies.end());
1681  EXPECT_EQ("A", it->Name());
1682  EXPECT_EQ("B", it->Value());
1683  EXPECT_EQ("www.google.izzle", it->Domain());
1684  EXPECT_EQ("/foo", it->Path());
1685  EXPECT_FALSE(it->DoesExpire());
1686  EXPECT_FALSE(it->IsSecure());
1687  EXPECT_FALSE(it->IsHttpOnly());
1688
1689  ASSERT_TRUE(++it == cookies.end());
1690
1691  cookies = cm->GetAllCookiesForURL(url_google_bar);
1692  it = cookies.begin();
1693
1694  ASSERT_TRUE(it != cookies.end());
1695  EXPECT_EQ("C", it->Name());
1696  EXPECT_EQ("D", it->Value());
1697  EXPECT_EQ(".google.izzle", it->Domain());
1698  EXPECT_EQ("/bar", it->Path());
1699  EXPECT_FALSE(it->IsSecure());
1700  EXPECT_TRUE(it->IsHttpOnly());
1701
1702  ASSERT_TRUE(++it == cookies.end());
1703
1704  cookies = cm->GetAllCookiesForURL(url_google_secure);
1705  it = cookies.begin();
1706
1707  ASSERT_TRUE(it != cookies.end());
1708  EXPECT_EQ("E", it->Name());
1709  EXPECT_EQ("F", it->Value());
1710  EXPECT_EQ("/", it->Path());
1711  EXPECT_EQ("www.google.izzle", it->Domain());
1712  EXPECT_TRUE(it->IsSecure());
1713  EXPECT_FALSE(it->IsHttpOnly());
1714
1715  ASSERT_TRUE(++it == cookies.end());
1716}
1717
1718
1719
1720TEST(CookieMonsterTest, DeleteAllForHost) {
1721  scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
1722
1723  // Test probes:
1724  //    * Non-secure URL, mid-level (http://w.c.b.a)
1725  //    * Secure URL, mid-level (https://w.c.b.a)
1726  //    * URL with path, mid-level (https:/w.c.b.a/dir1/xx)
1727  // All three tests should nuke only the midlevel host cookie,
1728  // the http_only cookie, the host secure cookie, and the two host
1729  // path cookies.  http_only, secure, and paths are ignored by
1730  // this call, and domain cookies arent touched.
1731  PopulateCmForDeleteAllForHost(cm);
1732  EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1733            cm->GetCookies(GURL(kTopLevelDomainPlus3)));
1734  EXPECT_EQ("dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X",
1735            cm->GetCookies(GURL(kTopLevelDomainPlus2Secure)));
1736  EXPECT_EQ("dom_1=X; host_1=X", cm->GetCookies(GURL(kTopLevelDomainPlus1)));
1737  EXPECT_EQ("dom_path_2=X; host_path_2=X; dom_path_1=X; host_path_1=X; "
1738            "dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X",
1739            cm->GetCookies(GURL(kTopLevelDomainPlus2Secure +
1740                                std::string("/dir1/dir2/xxx"))));
1741
1742  EXPECT_EQ(5, cm->DeleteAllForHost(GURL(kTopLevelDomainPlus2)));
1743  EXPECT_EQ(8U, cm->GetAllCookies().size());
1744
1745  EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1746            cm->GetCookies(GURL(kTopLevelDomainPlus3)));
1747  EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1748            cm->GetCookies(GURL(kTopLevelDomainPlus2Secure)));
1749  EXPECT_EQ("dom_1=X; host_1=X", cm->GetCookies(GURL(kTopLevelDomainPlus1)));
1750  EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1751            cm->GetCookies(GURL(kTopLevelDomainPlus2Secure +
1752                                std::string("/dir1/dir2/xxx"))));
1753
1754  PopulateCmForDeleteAllForHost(cm);
1755  EXPECT_EQ(5, cm->DeleteAllForHost(GURL(kTopLevelDomainPlus2Secure)));
1756  EXPECT_EQ(8U, cm->GetAllCookies().size());
1757
1758  EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1759            cm->GetCookies(GURL(kTopLevelDomainPlus3)));
1760  EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1761            cm->GetCookies(GURL(kTopLevelDomainPlus2Secure)));
1762  EXPECT_EQ("dom_1=X; host_1=X", cm->GetCookies(GURL(kTopLevelDomainPlus1)));
1763  EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1764            cm->GetCookies(GURL(kTopLevelDomainPlus2Secure +
1765                                std::string("/dir1/dir2/xxx"))));
1766
1767  PopulateCmForDeleteAllForHost(cm);
1768  EXPECT_EQ(5, cm->DeleteAllForHost(GURL(kTopLevelDomainPlus2Secure +
1769                                         std::string("/dir1/xxx"))));
1770  EXPECT_EQ(8U, cm->GetAllCookies().size());
1771
1772  EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1773            cm->GetCookies(GURL(kTopLevelDomainPlus3)));
1774  EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1775            cm->GetCookies(GURL(kTopLevelDomainPlus2Secure)));
1776  EXPECT_EQ("dom_1=X; host_1=X", cm->GetCookies(GURL(kTopLevelDomainPlus1)));
1777  EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1778            cm->GetCookies(GURL(kTopLevelDomainPlus2Secure +
1779                                std::string("/dir1/dir2/xxx"))));
1780
1781}
1782