• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <algorithm>
6 
7 #include "net/base/cookie_monster.h"
8 
9 #include "base/perftimer.h"
10 #include "base/string_util.h"
11 #include "base/stringprintf.h"
12 #include "googleurl/src/gurl.h"
13 #include "net/base/cookie_monster.h"
14 #include "net/base/cookie_monster_store_test.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
17 namespace {
18   class ParsedCookieTest : public testing::Test { };
19   class CookieMonsterTest : public testing::Test { };
20 }
21 
22 static const int kNumCookies = 20000;
23 static const char kCookieLine[] = "A  = \"b=;\\\"\"  ;secure;;;";
24 
25 namespace net {
26 
TEST(ParsedCookieTest,TestParseCookies)27 TEST(ParsedCookieTest, TestParseCookies) {
28   std::string cookie(kCookieLine);
29   PerfTimeLogger timer("Parsed_cookie_parse_cookies");
30   for (int i = 0; i < kNumCookies; ++i) {
31     CookieMonster::ParsedCookie pc(cookie);
32     EXPECT_TRUE(pc.IsValid());
33   }
34   timer.Done();
35 }
36 
TEST(ParsedCookieTest,TestParseBigCookies)37 TEST(ParsedCookieTest, TestParseBigCookies) {
38   std::string cookie(3800, 'z');
39   cookie += kCookieLine;
40   PerfTimeLogger timer("Parsed_cookie_parse_big_cookies");
41   for (int i = 0; i < kNumCookies; ++i) {
42     CookieMonster::ParsedCookie pc(cookie);
43     EXPECT_TRUE(pc.IsValid());
44   }
45   timer.Done();
46 }
47 
48 static const GURL kUrlGoogle("http://www.google.izzle");
49 
TEST(CookieMonsterTest,TestAddCookiesOnSingleHost)50 TEST(CookieMonsterTest, TestAddCookiesOnSingleHost) {
51   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
52   std::vector<std::string> cookies;
53   for (int i = 0; i < kNumCookies; i++) {
54     cookies.push_back(base::StringPrintf("a%03d=b", i));
55   }
56 
57   // Add a bunch of cookies on a single host
58   PerfTimeLogger timer("Cookie_monster_add_single_host");
59   for (std::vector<std::string>::const_iterator it = cookies.begin();
60        it != cookies.end(); ++it) {
61     EXPECT_TRUE(cm->SetCookie(kUrlGoogle, *it));
62   }
63   timer.Done();
64 
65   PerfTimeLogger timer2("Cookie_monster_query_single_host");
66   for (std::vector<std::string>::const_iterator it = cookies.begin();
67        it != cookies.end(); ++it) {
68     cm->GetCookies(kUrlGoogle);
69   }
70   timer2.Done();
71 
72   PerfTimeLogger timer3("Cookie_monster_deleteall_single_host");
73   cm->DeleteAll(false);
74   timer3.Done();
75 }
76 
TEST(CookieMonsterTest,TestAddCookieOnManyHosts)77 TEST(CookieMonsterTest, TestAddCookieOnManyHosts) {
78   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
79   std::string cookie(kCookieLine);
80   std::vector<GURL> gurls;  // just wanna have ffffuunnn
81   for (int i = 0; i < kNumCookies; ++i) {
82     gurls.push_back(GURL(base::StringPrintf("http://a%04d.izzle", i)));
83   }
84 
85   // Add a cookie on a bunch of host
86   PerfTimeLogger timer("Cookie_monster_add_many_hosts");
87   for (std::vector<GURL>::const_iterator it = gurls.begin();
88        it != gurls.end(); ++it) {
89     EXPECT_TRUE(cm->SetCookie(*it, cookie));
90   }
91   timer.Done();
92 
93   PerfTimeLogger timer2("Cookie_monster_query_many_hosts");
94   for (std::vector<GURL>::const_iterator it = gurls.begin();
95        it != gurls.end(); ++it) {
96     cm->GetCookies(*it);
97   }
98   timer2.Done();
99 
100   PerfTimeLogger timer3("Cookie_monster_deleteall_many_hosts");
101   cm->DeleteAll(false);
102   timer3.Done();
103 }
104 
CountInString(const std::string & str,char c)105 static int CountInString(const std::string& str, char c) {
106   return std::count(str.begin(), str.end(), c);
107 }
108 
TEST(CookieMonsterTest,TestDomainTree)109 TEST(CookieMonsterTest, TestDomainTree) {
110   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
111   const char* domain_cookie_format_tree = "a=b; domain=%s";
112   const std::string domain_base("top.com");
113 
114   std::vector<std::string> domain_list;
115 
116   // Create a balanced binary tree of domains on which the cookie is set.
117   domain_list.push_back(domain_base);
118   for (int i1 = 0; i1 < 2; i1++) {
119     std::string domain_base_1((i1 ? "a." : "b.") + domain_base);
120     EXPECT_EQ("top.com", cm->GetKey(domain_base_1));
121     domain_list.push_back(domain_base_1);
122     for (int i2 = 0; i2 < 2; i2++) {
123       std::string domain_base_2((i2 ? "a." : "b.") + domain_base_1);
124       EXPECT_EQ("top.com", cm->GetKey(domain_base_2));
125       domain_list.push_back(domain_base_2);
126       for (int i3 = 0; i3 < 2; i3++) {
127         std::string domain_base_3((i3 ? "a." : "b.") + domain_base_2);
128         EXPECT_EQ("top.com", cm->GetKey(domain_base_3));
129         domain_list.push_back(domain_base_3);
130         for (int i4 = 0; i4 < 2; i4++) {
131           std::string domain_base_4((i4 ? "a." : "b.") + domain_base_3);
132           EXPECT_EQ("top.com", cm->GetKey(domain_base_4));
133           domain_list.push_back(domain_base_4);
134         }
135       }
136     }
137   }
138 
139 
140   EXPECT_EQ(31u, domain_list.size());
141   for (std::vector<std::string>::const_iterator it = domain_list.begin();
142        it != domain_list.end(); it++) {
143     GURL gurl("https://" + *it + "/");
144     const std::string cookie = base::StringPrintf(domain_cookie_format_tree,
145                                                   it->c_str());
146     EXPECT_TRUE(cm->SetCookie(gurl, cookie));
147   }
148   EXPECT_EQ(31u, cm->GetAllCookies().size());
149 
150   GURL probe_gurl("https://b.a.b.a.top.com/");
151   std::string cookie_line;
152   cookie_line = cm->GetCookies(probe_gurl);
153   EXPECT_EQ(5, CountInString(cookie_line, '=')) << "Cookie line: "
154                                                 << cookie_line;
155   PerfTimeLogger timer("Cookie_monster_query_domain_tree");
156   for (int i = 0; i < kNumCookies; i++) {
157     cm->GetCookies(probe_gurl);
158   }
159   timer.Done();
160 
161 }
162 
TEST(CookieMonsterTest,TestDomainLine)163 TEST(CookieMonsterTest, TestDomainLine) {
164   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
165   std::vector<std::string> domain_list;
166   GURL probe_gurl("https://b.a.b.a.top.com/");
167   std::string cookie_line;
168 
169   // Create a line of 32 domain cookies such that all cookies stored
170   // by effective TLD+1 will apply to probe GURL.
171   // (TLD + 1 is the level above .com/org/net/etc, e.g. "top.com"
172   // or "google.com".  "Effective" is added to include sites like
173   // bbc.co.uk, where the effetive TLD+1 is more than one level
174   // below the top level.)
175   domain_list.push_back("a.top.com");
176   domain_list.push_back("b.a.top.com");
177   domain_list.push_back("a.b.a.top.com");
178   domain_list.push_back("b.a.b.a.top.com");
179   EXPECT_EQ(4u, domain_list.size());
180 
181   const char* domain_cookie_format_line = "a%03d=b; domain=%s";
182   for (int i = 0; i < 8; i++) {
183     for (std::vector<std::string>::const_iterator it = domain_list.begin();
184          it != domain_list.end(); it++) {
185       GURL gurl("https://" + *it + "/");
186       const std::string cookie = base::StringPrintf(domain_cookie_format_line,
187                                                     i, it->c_str());
188       EXPECT_TRUE(cm->SetCookie(gurl, cookie));
189     }
190   }
191   EXPECT_EQ(32u, cm->GetAllCookies().size());
192 
193   cookie_line = cm->GetCookies(probe_gurl);
194   EXPECT_EQ(32, CountInString(cookie_line, '='));
195   PerfTimeLogger timer2("Cookie_monster_query_domain_line");
196   for (int i = 0; i < kNumCookies; i++) {
197     cm->GetCookies(probe_gurl);
198   }
199   timer2.Done();
200 }
201 
TEST(CookieMonsterTest,TestImport)202 TEST(CookieMonsterTest, TestImport) {
203   scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
204   std::vector<CookieMonster::CanonicalCookie*> initial_cookies;
205 
206   // We want to setup a fairly large backing store, with 300 domains of 50
207   // cookies each.  Creation times must be unique.
208   int64 time_tick(base::Time::Now().ToInternalValue());
209 
210   for (int domain_num = 0; domain_num < 300; domain_num++) {
211     std::string domain_name(base::StringPrintf(".Domain_%d.com", domain_num));
212     std::string gurl("www" + domain_name);
213     for (int cookie_num = 0; cookie_num < 50; cookie_num++) {
214       std::string cookie_line(base::StringPrintf("Cookie_%d=1; Path=/",
215                                                  cookie_num));
216       AddCookieToList(gurl, cookie_line,
217                       base::Time::FromInternalValue(time_tick++),
218                       &initial_cookies);
219     }
220   }
221 
222   store->SetLoadExpectation(true, initial_cookies);
223 
224   scoped_refptr<CookieMonster> cm(new CookieMonster(store, NULL));
225 
226   // Import will happen on first access.
227   GURL gurl("www.google.com");
228   CookieOptions options;
229   PerfTimeLogger timer("Cookie_monster_import_from_store");
230   cm->GetCookiesWithOptions(gurl, options);
231   timer.Done();
232 
233   // Just confirm keys were set as expected.
234   EXPECT_EQ("domain_1.com", cm->GetKey("www.Domain_1.com"));
235 }
236 
TEST(CookieMonsterTest,TestGetKey)237 TEST(CookieMonsterTest, TestGetKey) {
238   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
239   PerfTimeLogger timer("Cookie_monster_get_key");
240   for (int i = 0; i < kNumCookies; i++)
241     cm->GetKey("www.google.com");
242   timer.Done();
243 }
244 
245 // This test is probing for whether garbage collection happens when it
246 // shouldn't.  This will not in general be visible functionally, since
247 // if GC runs twice in a row without any change to the store, the second
248 // GC run will not do anything the first one didn't.  That's why this is
249 // a performance test.  The test should be considered to pass if all the
250 // times reported are approximately the same--this indicates that no GC
251 // happened repeatedly for any case.
TEST(CookieMonsterTest,TestGCTimes)252 TEST(CookieMonsterTest, TestGCTimes) {
253   const struct TestCase {
254     const char* name;
255     int num_cookies;
256     int num_old_cookies;
257   } test_cases[] = {
258     {
259       // A whole lot of recent cookies; gc shouldn't happen.
260       "all_recent",
261       CookieMonster::kMaxCookies * 2,
262       0,
263     }, {
264       // Some old cookies, but still overflowing max.
265       "mostly_recent",
266       CookieMonster::kMaxCookies * 2,
267       CookieMonster::kMaxCookies / 2,
268     }, {
269       // Old cookies enough to bring us right down to our purge line.
270       "balanced",
271       CookieMonster::kMaxCookies * 2,
272       CookieMonster::kMaxCookies + CookieMonster::kPurgeCookies + 1,
273     }, {
274       "mostly_old",
275       // Old cookies enough to bring below our purge line (which we
276       // shouldn't do).
277       CookieMonster::kMaxCookies * 2,
278       CookieMonster::kMaxCookies * 3 / 4,
279     }, {
280       "less_than_gc_thresh",
281       // Few enough cookies that gc shouldn't happen at all.
282       CookieMonster::kMaxCookies - 5,
283       0,
284     },
285   };
286   for (int ci = 0; ci < static_cast<int>(ARRAYSIZE_UNSAFE(test_cases)); ++ci) {
287     const TestCase& test_case(test_cases[ci]);
288     scoped_refptr<CookieMonster> cm(
289         CreateMonsterFromStoreForGC(
290             test_case.num_cookies, test_case.num_old_cookies,
291             CookieMonster::kSafeFromGlobalPurgeDays * 2));
292 
293     GURL gurl("http://google.com");
294     std::string cookie_line("z=3");
295     // Trigger the Garbage collection we're allowed.
296     EXPECT_TRUE(cm->SetCookie(gurl, cookie_line));
297 
298     PerfTimeLogger timer((std::string("GC_") + test_case.name).c_str());
299     for (int i = 0; i < kNumCookies; i++)
300       EXPECT_TRUE(cm->SetCookie(gurl, cookie_line));
301     timer.Done();
302   }
303 }
304 
305 } // namespace
306