1 // Copyright 2012 The Chromium Authors
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/cookies/cookie_monster.h"
6
7 #include <stdint.h>
8
9 #include <algorithm>
10 #include <memory>
11 #include <optional>
12 #include <string>
13 #include <string_view>
14 #include <utility>
15 #include <vector>
16
17 #include "base/containers/queue.h"
18 #include "base/functional/bind.h"
19 #include "base/functional/callback.h"
20 #include "base/functional/callback_helpers.h"
21 #include "base/location.h"
22 #include "base/memory/raw_ptr.h"
23 #include "base/memory/ref_counted.h"
24 #include "base/metrics/histogram.h"
25 #include "base/metrics/histogram_samples.h"
26 #include "base/ranges/algorithm.h"
27 #include "base/run_loop.h"
28 #include "base/strings/strcat.h"
29 #include "base/strings/string_number_conversions.h"
30 #include "base/strings/string_split.h"
31 #include "base/strings/string_tokenizer.h"
32 #include "base/strings/stringprintf.h"
33 #include "base/task/single_thread_task_runner.h"
34 #include "base/test/bind.h"
35 #include "base/test/metrics/histogram_tester.h"
36 #include "base/test/mock_callback.h"
37 #include "base/test/scoped_feature_list.h"
38 #include "base/test/test_future.h"
39 #include "base/threading/thread.h"
40 #include "base/time/time.h"
41 #include "cookie_partition_key.h"
42 #include "net/base/features.h"
43 #include "net/cookies/canonical_cookie.h"
44 #include "net/cookies/canonical_cookie_test_helpers.h"
45 #include "net/cookies/cookie_change_dispatcher.h"
46 #include "net/cookies/cookie_constants.h"
47 #include "net/cookies/cookie_inclusion_status.h"
48 #include "net/cookies/cookie_monster_store_test.h" // For CookieStore mock
49 #include "net/cookies/cookie_partition_key.h"
50 #include "net/cookies/cookie_store.h"
51 #include "net/cookies/cookie_store_change_unittest.h"
52 #include "net/cookies/cookie_store_test_callbacks.h"
53 #include "net/cookies/cookie_store_test_helpers.h"
54 #include "net/cookies/cookie_store_unittest.h"
55 #include "net/cookies/cookie_util.h"
56 #include "net/cookies/parsed_cookie.h"
57 #include "net/cookies/test_cookie_access_delegate.h"
58 #include "net/log/net_log_with_source.h"
59 #include "net/log/test_net_log.h"
60 #include "net/log/test_net_log_util.h"
61 #include "testing/gmock/include/gmock/gmock-matchers.h"
62 #include "testing/gmock/include/gmock/gmock.h"
63 #include "testing/gtest/include/gtest/gtest.h"
64 #include "url/gurl.h"
65 #include "url/third_party/mozilla/url_parse.h"
66 #include "url/url_constants.h"
67
68 namespace net {
69
70 using base::Time;
71 using CookieDeletionInfo = net::CookieDeletionInfo;
72
73 namespace {
74
75 using testing::ElementsAre;
76
77 // False means 'less than or equal', so we test both ways for full equal.
78 MATCHER_P(CookieEquals, expected, "") {
79 return !(arg.FullCompare(expected) || expected.FullCompare(arg));
80 }
81
82 MATCHER_P2(MatchesCookieNameDomain, name, domain, "") {
83 return testing::ExplainMatchResult(
84 testing::AllOf(testing::Property(&net::CanonicalCookie::Name, name),
85 testing::Property(&net::CanonicalCookie::Domain, domain)),
86 arg, result_listener);
87 }
88
89 MATCHER_P4(MatchesCookieNameValueCreationExpiry,
90 name,
91 value,
92 creation,
93 expiry,
94 "") {
95 return testing::ExplainMatchResult(
96 testing::AllOf(
97 testing::Property(&net::CanonicalCookie::Name, name),
98 testing::Property(&net::CanonicalCookie::Value, value),
99 testing::Property(&net::CanonicalCookie::CreationDate, creation),
100 // We need a margin of error when testing the ExpiryDate as, if
101 // clamped, it is set relative to the current time.
102 testing::Property(&net::CanonicalCookie::ExpiryDate,
103 testing::Gt(expiry - base::Minutes(1))),
104 testing::Property(&net::CanonicalCookie::ExpiryDate,
105 testing::Lt(expiry + base::Minutes(1)))),
106 arg, result_listener);
107 }
108
109 const char kTopLevelDomainPlus1[] = "http://www.harvard.edu";
110 const char kTopLevelDomainPlus2[] = "http://www.math.harvard.edu";
111 const char kTopLevelDomainPlus2Secure[] = "https://www.math.harvard.edu";
112 const char kTopLevelDomainPlus3[] = "http://www.bourbaki.math.harvard.edu";
113 const char kOtherDomain[] = "http://www.mit.edu";
114
115 struct CookieMonsterTestTraits {
Createnet::__anon138ee7670111::CookieMonsterTestTraits116 static std::unique_ptr<CookieStore> Create() {
117 return std::make_unique<CookieMonster>(nullptr /* store */,
118 nullptr /* netlog */);
119 }
120
DeliverChangeNotificationsnet::__anon138ee7670111::CookieMonsterTestTraits121 static void DeliverChangeNotifications() { base::RunLoop().RunUntilIdle(); }
122
123 static const bool supports_http_only = true;
124 static const bool supports_non_dotted_domains = true;
125 static const bool preserves_trailing_dots = true;
126 static const bool filters_schemes = true;
127 static const bool has_path_prefix_bug = false;
128 static const bool forbids_setting_empty_name = false;
129 static const bool supports_global_cookie_tracking = true;
130 static const bool supports_url_cookie_tracking = true;
131 static const bool supports_named_cookie_tracking = true;
132 static const bool supports_multiple_tracking_callbacks = true;
133 static const bool has_exact_change_cause = true;
134 static const bool has_exact_change_ordering = true;
135 static const int creation_time_granularity_in_ms = 0;
136 static const bool supports_cookie_access_semantics = true;
137 static const bool supports_partitioned_cookies = true;
138 };
139
140 INSTANTIATE_TYPED_TEST_SUITE_P(CookieMonster,
141 CookieStoreTest,
142 CookieMonsterTestTraits);
143 INSTANTIATE_TYPED_TEST_SUITE_P(CookieMonster,
144 CookieStoreChangeGlobalTest,
145 CookieMonsterTestTraits);
146 INSTANTIATE_TYPED_TEST_SUITE_P(CookieMonster,
147 CookieStoreChangeUrlTest,
148 CookieMonsterTestTraits);
149 INSTANTIATE_TYPED_TEST_SUITE_P(CookieMonster,
150 CookieStoreChangeNamedTest,
151 CookieMonsterTestTraits);
152
153 template <typename T>
154 class CookieMonsterTestBase : public CookieStoreTest<T> {
155 public:
156 using CookieStoreTest<T>::SetCookie;
157
158 protected:
159 using CookieStoreTest<T>::http_www_foo_;
160 using CookieStoreTest<T>::https_www_foo_;
161
GetAllCookiesForURLWithOptions(CookieMonster * cm,const GURL & url,const CookieOptions & options,const CookiePartitionKeyCollection & cookie_partition_key_collection=CookiePartitionKeyCollection ())162 CookieList GetAllCookiesForURLWithOptions(
163 CookieMonster* cm,
164 const GURL& url,
165 const CookieOptions& options,
166 const CookiePartitionKeyCollection& cookie_partition_key_collection =
167 CookiePartitionKeyCollection()) {
168 DCHECK(cm);
169 GetCookieListCallback callback;
170 cm->GetCookieListWithOptionsAsync(
171 url, options, cookie_partition_key_collection, callback.MakeCallback());
172 callback.WaitUntilDone();
173 return callback.cookies();
174 }
175
GetAllCookies(CookieMonster * cm)176 CookieList GetAllCookies(CookieMonster* cm) {
177 DCHECK(cm);
178 GetAllCookiesCallback callback;
179 cm->GetAllCookiesAsync(callback.MakeCallback());
180 callback.WaitUntilDone();
181 return callback.cookies();
182 }
183
GetExcludedCookiesForURLWithOptions(CookieMonster * cm,const GURL & url,const CookieOptions & options,const CookiePartitionKeyCollection & cookie_partition_key_collection=CookiePartitionKeyCollection ())184 CookieAccessResultList GetExcludedCookiesForURLWithOptions(
185 CookieMonster* cm,
186 const GURL& url,
187 const CookieOptions& options,
188 const CookiePartitionKeyCollection& cookie_partition_key_collection =
189 CookiePartitionKeyCollection()) {
190 DCHECK(cm);
191 GetCookieListCallback callback;
192 cm->GetCookieListWithOptionsAsync(
193 url, options, cookie_partition_key_collection, callback.MakeCallback());
194 callback.WaitUntilDone();
195 return callback.excluded_cookies();
196 }
197
SetAllCookies(CookieMonster * cm,const CookieList & list)198 bool SetAllCookies(CookieMonster* cm, const CookieList& list) {
199 DCHECK(cm);
200 ResultSavingCookieCallback<CookieAccessResult> callback;
201 cm->SetAllCookiesAsync(list, callback.MakeCallback());
202 callback.WaitUntilDone();
203 return callback.result().status.IsInclude();
204 }
205
SetCookieWithCreationTime(CookieMonster * cm,const GURL & url,const std::string & cookie_line,base::Time creation_time,std::optional<CookiePartitionKey> cookie_partition_key=std::nullopt)206 bool SetCookieWithCreationTime(
207 CookieMonster* cm,
208 const GURL& url,
209 const std::string& cookie_line,
210 base::Time creation_time,
211 std::optional<CookiePartitionKey> cookie_partition_key = std::nullopt) {
212 DCHECK(cm);
213 DCHECK(!creation_time.is_null());
214 ResultSavingCookieCallback<CookieAccessResult> callback;
215 cm->SetCanonicalCookieAsync(
216 CanonicalCookie::CreateForTesting(url, cookie_line, creation_time,
217 std::nullopt /* server_time */,
218 cookie_partition_key),
219 url, CookieOptions::MakeAllInclusive(), callback.MakeCallback());
220 callback.WaitUntilDone();
221 return callback.result().status.IsInclude();
222 }
223
DeleteAllCreatedInTimeRange(CookieMonster * cm,const TimeRange & creation_range)224 uint32_t DeleteAllCreatedInTimeRange(CookieMonster* cm,
225 const TimeRange& creation_range) {
226 DCHECK(cm);
227 ResultSavingCookieCallback<uint32_t> callback;
228 cm->DeleteAllCreatedInTimeRangeAsync(creation_range,
229 callback.MakeCallback());
230 callback.WaitUntilDone();
231 return callback.result();
232 }
233
DeleteAllMatchingInfo(CookieMonster * cm,CookieDeletionInfo delete_info)234 uint32_t DeleteAllMatchingInfo(CookieMonster* cm,
235 CookieDeletionInfo delete_info) {
236 DCHECK(cm);
237 ResultSavingCookieCallback<uint32_t> callback;
238 cm->DeleteAllMatchingInfoAsync(std::move(delete_info),
239 callback.MakeCallback());
240 callback.WaitUntilDone();
241 return callback.result();
242 }
243
DeleteMatchingCookies(CookieMonster * cm,CookieStore::DeletePredicate predicate)244 uint32_t DeleteMatchingCookies(CookieMonster* cm,
245 CookieStore::DeletePredicate predicate) {
246 DCHECK(cm);
247 ResultSavingCookieCallback<uint32_t> callback;
248 cm->DeleteMatchingCookiesAsync(std::move(predicate),
249 callback.MakeCallback());
250 callback.WaitUntilDone();
251 return callback.result();
252 }
253
254 // Helper for PredicateSeesAllCookies test; repopulates CM with same layout
255 // each time. Returns the time which is strictly greater than any creation
256 // time which was passed to created cookies.
PopulateCmForPredicateCheck(CookieMonster * cm)257 base::Time PopulateCmForPredicateCheck(CookieMonster* cm) {
258 std::string url_top_level_domain_plus_1(GURL(kTopLevelDomainPlus1).host());
259 std::string url_top_level_domain_plus_2(GURL(kTopLevelDomainPlus2).host());
260 std::string url_top_level_domain_plus_3(GURL(kTopLevelDomainPlus3).host());
261 std::string url_top_level_domain_secure(
262 GURL(kTopLevelDomainPlus2Secure).host());
263 std::string url_other(GURL(kOtherDomain).host());
264
265 this->DeleteAll(cm);
266
267 // Static population for probe:
268 // * Three levels of domain cookie (.b.a, .c.b.a, .d.c.b.a)
269 // * Three levels of host cookie (w.b.a, w.c.b.a, w.d.c.b.a)
270 // * http_only cookie (w.c.b.a)
271 // * same_site cookie (w.c.b.a)
272 // * Two secure cookies (.c.b.a, w.c.b.a)
273 // * Two domain path cookies (.c.b.a/dir1, .c.b.a/dir1/dir2)
274 // * Two host path cookies (w.c.b.a/dir1, w.c.b.a/dir1/dir2)
275
276 std::vector<std::unique_ptr<CanonicalCookie>> cookies;
277 const base::Time now = base::Time::Now();
278
279 // Domain cookies
280 cookies.push_back(CanonicalCookie::CreateUnsafeCookieForTesting(
281 "dom_1", "A", ".harvard.edu", "/", now, base::Time(), base::Time(),
282 base::Time(), false, false, CookieSameSite::LAX_MODE,
283 COOKIE_PRIORITY_DEFAULT));
284 cookies.push_back(CanonicalCookie::CreateUnsafeCookieForTesting(
285 "dom_2", "B", ".math.harvard.edu", "/", now, base::Time(), base::Time(),
286 base::Time(), false, false, CookieSameSite::LAX_MODE,
287 COOKIE_PRIORITY_DEFAULT));
288 cookies.push_back(CanonicalCookie::CreateUnsafeCookieForTesting(
289 "dom_3", "C", ".bourbaki.math.harvard.edu", "/", now, base::Time(),
290 base::Time(), base::Time(), false, false, CookieSameSite::LAX_MODE,
291 COOKIE_PRIORITY_DEFAULT));
292
293 // Host cookies
294 cookies.push_back(CanonicalCookie::CreateUnsafeCookieForTesting(
295 "host_1", "A", url_top_level_domain_plus_1, "/", now, base::Time(),
296 base::Time(), base::Time(), false, false, CookieSameSite::LAX_MODE,
297 COOKIE_PRIORITY_DEFAULT));
298 cookies.push_back(CanonicalCookie::CreateUnsafeCookieForTesting(
299 "host_2", "B", url_top_level_domain_plus_2, "/", now, base::Time(),
300 base::Time(), base::Time(), false, false, CookieSameSite::LAX_MODE,
301 COOKIE_PRIORITY_DEFAULT));
302 cookies.push_back(CanonicalCookie::CreateUnsafeCookieForTesting(
303 "host_3", "C", url_top_level_domain_plus_3, "/", now, base::Time(),
304 base::Time(), base::Time(), false, false, CookieSameSite::LAX_MODE,
305 COOKIE_PRIORITY_DEFAULT));
306
307 // http_only cookie
308 cookies.push_back(CanonicalCookie::CreateUnsafeCookieForTesting(
309 "httpo_check", "A", url_top_level_domain_plus_2, "/", now, base::Time(),
310 base::Time(), base::Time(), false, true, CookieSameSite::LAX_MODE,
311 COOKIE_PRIORITY_DEFAULT));
312
313 // same-site cookie
314 cookies.push_back(CanonicalCookie::CreateUnsafeCookieForTesting(
315 "same_site_check", "A", url_top_level_domain_plus_2, "/", now,
316 base::Time(), base::Time(), base::Time(), false, false,
317 CookieSameSite::STRICT_MODE, COOKIE_PRIORITY_DEFAULT));
318
319 // Secure cookies
320 cookies.push_back(CanonicalCookie::CreateUnsafeCookieForTesting(
321 "sec_dom", "A", ".math.harvard.edu", "/", now, base::Time(),
322 base::Time(), base::Time(), true, false, CookieSameSite::NO_RESTRICTION,
323 COOKIE_PRIORITY_DEFAULT));
324 cookies.push_back(CanonicalCookie::CreateUnsafeCookieForTesting(
325 "sec_host", "B", url_top_level_domain_plus_2, "/", now, base::Time(),
326 base::Time(), base::Time(), true, false, CookieSameSite::NO_RESTRICTION,
327 COOKIE_PRIORITY_DEFAULT));
328
329 // Domain path cookies
330 cookies.push_back(CanonicalCookie::CreateUnsafeCookieForTesting(
331 "dom_path_1", "A", ".math.harvard.edu", "/dir1", now, base::Time(),
332 base::Time(), base::Time(), false, false, CookieSameSite::LAX_MODE,
333 COOKIE_PRIORITY_DEFAULT));
334 cookies.push_back(CanonicalCookie::CreateUnsafeCookieForTesting(
335 "dom_path_2", "B", ".math.harvard.edu", "/dir1/dir2", now, base::Time(),
336 base::Time(), base::Time(), false, false, CookieSameSite::LAX_MODE,
337 COOKIE_PRIORITY_DEFAULT));
338
339 // Host path cookies
340 cookies.push_back(CanonicalCookie::CreateUnsafeCookieForTesting(
341 "host_path_1", "A", url_top_level_domain_plus_2, "/dir1", now,
342 base::Time(), base::Time(), base::Time(), false, false,
343 CookieSameSite::LAX_MODE, COOKIE_PRIORITY_DEFAULT));
344 cookies.push_back(CanonicalCookie::CreateUnsafeCookieForTesting(
345 "host_path_2", "B", url_top_level_domain_plus_2, "/dir1/dir2", now,
346 base::Time(), base::Time(), base::Time(), false, false,
347 CookieSameSite::LAX_MODE, COOKIE_PRIORITY_DEFAULT));
348
349 // Partitioned cookies
350 cookies.push_back(CanonicalCookie::CreateUnsafeCookieForTesting(
351 "__Host-pc_1", "A", url_top_level_domain_secure, "/", now, base::Time(),
352 base::Time(), base::Time(), true, false, CookieSameSite::NO_RESTRICTION,
353 CookiePriority::COOKIE_PRIORITY_DEFAULT,
354 CookiePartitionKey::FromURLForTesting(GURL(kTopLevelDomainPlus1))));
355 cookies.push_back(CanonicalCookie::CreateUnsafeCookieForTesting(
356 "__Host-pc_2", "B", url_top_level_domain_secure, "/", now, base::Time(),
357 base::Time(), base::Time(), true, false, CookieSameSite::NO_RESTRICTION,
358 CookiePriority::COOKIE_PRIORITY_DEFAULT,
359 CookiePartitionKey::FromURLForTesting(GURL(kTopLevelDomainPlus1))));
360
361 for (auto& cookie : cookies) {
362 GURL source_url = cookie_util::SimulatedCookieSource(
363 *cookie, cookie->SecureAttribute() ? "https" : "http");
364 EXPECT_TRUE(this->SetCanonicalCookie(cm, std::move(cookie), source_url,
365 true /* modify_httponly */));
366 }
367
368 EXPECT_EQ(cookies.size(), this->GetAllCookies(cm).size());
369 return now + base::Milliseconds(100);
370 }
371
GetFirstCookieAccessDate(CookieMonster * cm)372 Time GetFirstCookieAccessDate(CookieMonster* cm) {
373 const CookieList all_cookies(this->GetAllCookies(cm));
374 return all_cookies.front().LastAccessDate();
375 }
376
FindAndDeleteCookie(CookieMonster * cm,const std::string & domain,const std::string & name)377 bool FindAndDeleteCookie(CookieMonster* cm,
378 const std::string& domain,
379 const std::string& name) {
380 CookieList cookies = this->GetAllCookies(cm);
381 for (auto& cookie : cookies)
382 if (cookie.Domain() == domain && cookie.Name() == name)
383 return this->DeleteCanonicalCookie(cm, cookie);
384 return false;
385 }
386
TestHostGarbageCollectHelper()387 void TestHostGarbageCollectHelper() {
388 int domain_max_cookies = CookieMonster::kDomainMaxCookies;
389 int domain_purge_cookies = CookieMonster::kDomainPurgeCookies;
390 const int more_than_enough_cookies = domain_max_cookies + 10;
391 // Add a bunch of cookies on a single host, should purge them.
392 {
393 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
394 for (int i = 0; i < more_than_enough_cookies; ++i) {
395 std::string cookie = base::StringPrintf("a%03d=b", i);
396 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), cookie));
397 std::string cookies = this->GetCookies(cm.get(), http_www_foo_.url());
398 // Make sure we find it in the cookies.
399 EXPECT_NE(cookies.find(cookie), std::string::npos);
400 // Count the number of cookies.
401 EXPECT_LE(base::ranges::count(cookies, '='), domain_max_cookies);
402 }
403 }
404
405 // Add a bunch of cookies on multiple hosts within a single eTLD.
406 // Should keep at least kDomainMaxCookies - kDomainPurgeCookies
407 // between them. We shouldn't go above kDomainMaxCookies for both together.
408 GURL url_google_specific(http_www_foo_.Format("http://www.gmail.%D"));
409 {
410 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
411 for (int i = 0; i < more_than_enough_cookies; ++i) {
412 std::string cookie_general = base::StringPrintf("a%03d=b", i);
413 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), cookie_general));
414 std::string cookie_specific = base::StringPrintf("c%03d=b", i);
415 EXPECT_TRUE(SetCookie(cm.get(), url_google_specific, cookie_specific));
416 std::string cookies_general =
417 this->GetCookies(cm.get(), http_www_foo_.url());
418 EXPECT_NE(cookies_general.find(cookie_general), std::string::npos);
419 std::string cookies_specific =
420 this->GetCookies(cm.get(), url_google_specific);
421 EXPECT_NE(cookies_specific.find(cookie_specific), std::string::npos);
422 EXPECT_LE((base::ranges::count(cookies_general, '=') +
423 base::ranges::count(cookies_specific, '=')),
424 domain_max_cookies);
425 }
426 // After all this, there should be at least
427 // kDomainMaxCookies - kDomainPurgeCookies for both URLs.
428 std::string cookies_general =
429 this->GetCookies(cm.get(), http_www_foo_.url());
430 std::string cookies_specific =
431 this->GetCookies(cm.get(), url_google_specific);
432 int total_cookies = (base::ranges::count(cookies_general, '=') +
433 base::ranges::count(cookies_specific, '='));
434 EXPECT_GE(total_cookies, domain_max_cookies - domain_purge_cookies);
435 EXPECT_LE(total_cookies, domain_max_cookies);
436 }
437
438 // Test histogram for the number of registrable domains affected by domain
439 // purge.
440 {
441 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
442 GURL url;
443 for (int domain_num = 0; domain_num < 3; ++domain_num) {
444 url = GURL(base::StringPrintf("http://domain%d.test", domain_num));
445 for (int i = 0; i < more_than_enough_cookies; ++i) {
446 std::string cookie = base::StringPrintf("a%03d=b", i);
447 EXPECT_TRUE(SetCookie(cm.get(), url, cookie));
448 std::string cookies = this->GetCookies(cm.get(), url);
449 // Make sure we find it in the cookies.
450 EXPECT_NE(cookies.find(cookie), std::string::npos);
451 // Count the number of cookies.
452 EXPECT_LE(base::ranges::count(cookies, '='), domain_max_cookies);
453 }
454 }
455
456 // Triggering eviction again for a previously affected registrable domain
457 // does not increment the histogram.
458 for (int i = 0; i < domain_purge_cookies * 2; ++i) {
459 // Add some extra cookies (different names than before).
460 std::string cookie = base::StringPrintf("b%03d=b", i);
461 EXPECT_TRUE(SetCookie(cm.get(), url, cookie));
462 std::string cookies = this->GetCookies(cm.get(), url);
463 // Make sure we find it in the cookies.
464 EXPECT_NE(cookies.find(cookie), std::string::npos);
465 // Count the number of cookies.
466 EXPECT_LE(base::ranges::count(cookies, '='), domain_max_cookies);
467 }
468 }
469 }
470
CharToPriority(char ch)471 CookiePriority CharToPriority(char ch) {
472 switch (ch) {
473 case 'L':
474 return COOKIE_PRIORITY_LOW;
475 case 'M':
476 return COOKIE_PRIORITY_MEDIUM;
477 case 'H':
478 return COOKIE_PRIORITY_HIGH;
479 }
480 NOTREACHED();
481 return COOKIE_PRIORITY_DEFAULT;
482 }
483
484 // Instantiates a CookieMonster, adds multiple cookies (to http_www_foo_)
485 // with priorities specified by |coded_priority_str|, and tests priority-aware
486 // domain cookie eviction.
487 //
488 // Example: |coded_priority_string| of "2MN 3LS MN 4HN" specifies sequential
489 // (i.e., from least- to most-recently accessed) insertion of 2
490 // medium-priority non-secure cookies, 3 low-priority secure cookies, 1
491 // medium-priority non-secure cookie, and 4 high-priority non-secure cookies.
492 //
493 // Within each priority, only the least-accessed cookies should be evicted.
494 // Thus, to describe expected suriving cookies, it suffices to specify the
495 // expected population of surviving cookies per priority, i.e.,
496 // |expected_low_count|, |expected_medium_count|, and |expected_high_count|.
TestPriorityCookieCase(CookieMonster * cm,const std::string & coded_priority_str,size_t expected_low_count,size_t expected_medium_count,size_t expected_high_count,size_t expected_nonsecure,size_t expected_secure)497 void TestPriorityCookieCase(CookieMonster* cm,
498 const std::string& coded_priority_str,
499 size_t expected_low_count,
500 size_t expected_medium_count,
501 size_t expected_high_count,
502 size_t expected_nonsecure,
503 size_t expected_secure) {
504 SCOPED_TRACE(coded_priority_str);
505 this->DeleteAll(cm);
506 int next_cookie_id = 0;
507 // A list of cookie IDs, indexed by secure status, then by priority.
508 std::vector<int> id_list[2][3];
509 // A list of all the cookies stored, along with their properties.
510 std::vector<std::pair<bool, CookiePriority>> cookie_data;
511
512 // Parse |coded_priority_str| and add cookies.
513 for (const std::string& token :
514 base::SplitString(coded_priority_str, " ", base::TRIM_WHITESPACE,
515 base::SPLIT_WANT_ALL)) {
516 DCHECK(!token.empty());
517
518 bool is_secure = token.back() == 'S';
519
520 // The second-to-last character is the priority. Grab and discard it.
521 CookiePriority priority = CharToPriority(token[token.size() - 2]);
522
523 // Discard the security status and priority tokens. The rest of the string
524 // (possibly empty) specifies repetition.
525 int rep = 1;
526 if (!token.empty()) {
527 bool result = base::StringToInt(
528 base::MakeStringPiece(token.begin(), token.end() - 2), &rep);
529 DCHECK(result);
530 }
531 for (; rep > 0; --rep, ++next_cookie_id) {
532 std::string cookie =
533 base::StringPrintf("a%d=b;priority=%s;%s", next_cookie_id,
534 CookiePriorityToString(priority).c_str(),
535 is_secure ? "secure" : "");
536
537 EXPECT_TRUE(SetCookie(
538 cm, is_secure ? https_www_foo_.url() : http_www_foo_.url(),
539 cookie));
540 cookie_data.emplace_back(is_secure, priority);
541 id_list[is_secure][priority].push_back(next_cookie_id);
542 }
543 }
544
545 int num_cookies = static_cast<int>(cookie_data.size());
546 // A list of cookie IDs, indexed by secure status, then by priority.
547 std::vector<int> surviving_id_list[2][3];
548
549 // Parse the list of cookies
550 std::string cookie_str = this->GetCookies(cm, https_www_foo_.url());
551 // If any part of OBC is active then we also need to query the insecure url
552 // and combine the resulting strings.
553 if (cookie_util::IsOriginBoundCookiesPartiallyEnabled()) {
554 std::string cookie_str_insecure =
555 this->GetCookies(cm, http_www_foo_.url());
556
557 std::vector<std::string_view> to_be_combined;
558 // The cookie strings may be empty, only add them to our vector if
559 // they're not. Otherwise we'll get an extra separator added which is bad.
560 if (!cookie_str.empty()) {
561 to_be_combined.push_back(cookie_str);
562 }
563 if (!cookie_str_insecure.empty()) {
564 to_be_combined.push_back(cookie_str_insecure);
565 }
566
567 cookie_str = base::JoinString(to_be_combined, /*separator=*/"; ");
568 }
569
570 size_t num_nonsecure = 0;
571 size_t num_secure = 0;
572 for (const std::string& token : base::SplitString(
573 cookie_str, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
574 // Assuming *it is "a#=b", so extract and parse "#" portion.
575 int id = -1;
576 bool result = base::StringToInt(
577 base::MakeStringPiece(token.begin() + 1, token.end() - 2), &id);
578 DCHECK(result);
579 DCHECK_GE(id, 0);
580 DCHECK_LT(id, num_cookies);
581 surviving_id_list[cookie_data[id].first][cookie_data[id].second]
582 .push_back(id);
583 if (cookie_data[id].first)
584 num_secure += 1;
585 else
586 num_nonsecure += 1;
587 }
588
589 EXPECT_EQ(expected_nonsecure, num_nonsecure);
590 EXPECT_EQ(expected_secure, num_secure);
591
592 // Validate each priority.
593 size_t expected_count[3] = {expected_low_count, expected_medium_count,
594 expected_high_count};
595 for (int i = 0; i < 3; ++i) {
596 size_t num_for_priority =
597 surviving_id_list[0][i].size() + surviving_id_list[1][i].size();
598 EXPECT_EQ(expected_count[i], num_for_priority);
599 // Verify that the remaining cookies are the most recent among those
600 // with the same priorities.
601 if (expected_count[i] == num_for_priority) {
602 // Non-secure:
603 std::sort(surviving_id_list[0][i].begin(),
604 surviving_id_list[0][i].end());
605 EXPECT_TRUE(std::equal(
606 surviving_id_list[0][i].begin(), surviving_id_list[0][i].end(),
607 id_list[0][i].end() - surviving_id_list[0][i].size()));
608
609 // Secure:
610 std::sort(surviving_id_list[1][i].begin(),
611 surviving_id_list[1][i].end());
612 EXPECT_TRUE(std::equal(
613 surviving_id_list[1][i].begin(), surviving_id_list[1][i].end(),
614 id_list[1][i].end() - surviving_id_list[1][i].size()));
615 }
616 }
617 }
618
619 // Represents a number of cookies to create, if they are Secure cookies, and
620 // a url to add them to.
621 struct CookiesEntry {
622 size_t num_cookies;
623 bool is_secure;
624 };
625 // A number of secure and a number of non-secure alternative hosts to create
626 // for testing.
627 typedef std::pair<size_t, size_t> AltHosts;
628 // Takes an array of CookieEntries which specify the number, type, and order
629 // of cookies to create. Cookies are created in the order they appear in
630 // cookie_entries. The value of cookie_entries[x].num_cookies specifies how
631 // many cookies of that type to create consecutively, while if
632 // cookie_entries[x].is_secure is |true|, those cookies will be marked as
633 // Secure.
TestSecureCookieEviction(base::span<const CookiesEntry> cookie_entries,size_t expected_secure_cookies,size_t expected_non_secure_cookies,const AltHosts * alt_host_entries)634 void TestSecureCookieEviction(base::span<const CookiesEntry> cookie_entries,
635 size_t expected_secure_cookies,
636 size_t expected_non_secure_cookies,
637 const AltHosts* alt_host_entries) {
638 std::unique_ptr<CookieMonster> cm;
639
640 if (alt_host_entries == nullptr) {
641 cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
642 } else {
643 // When generating all of these cookies on alternate hosts, they need to
644 // be all older than the max "safe" date for GC, which is currently 30
645 // days, so we set them to 60.
646 cm = CreateMonsterFromStoreForGC(
647 alt_host_entries->first, alt_host_entries->first,
648 alt_host_entries->second, alt_host_entries->second, 60);
649 }
650
651 int next_cookie_id = 0;
652 for (const auto& cookie_entry : cookie_entries) {
653 for (size_t j = 0; j < cookie_entry.num_cookies; j++) {
654 std::string cookie;
655 if (cookie_entry.is_secure)
656 cookie = base::StringPrintf("a%d=b; Secure", next_cookie_id);
657 else
658 cookie = base::StringPrintf("a%d=b", next_cookie_id);
659 EXPECT_TRUE(SetCookie(cm.get(), https_www_foo_.url(), cookie));
660 ++next_cookie_id;
661 }
662 }
663
664 CookieList cookies = this->GetAllCookies(cm.get());
665 EXPECT_EQ(expected_secure_cookies + expected_non_secure_cookies,
666 cookies.size());
667 size_t total_secure_cookies = 0;
668 size_t total_non_secure_cookies = 0;
669 for (const auto& cookie : cookies) {
670 if (cookie.SecureAttribute()) {
671 ++total_secure_cookies;
672 } else {
673 ++total_non_secure_cookies;
674 }
675 }
676
677 EXPECT_EQ(expected_secure_cookies, total_secure_cookies);
678 EXPECT_EQ(expected_non_secure_cookies, total_non_secure_cookies);
679 }
680
TestPriorityAwareGarbageCollectHelperNonSecure()681 void TestPriorityAwareGarbageCollectHelperNonSecure() {
682 // Hard-coding limits in the test, but use DCHECK_EQ to enforce constraint.
683 DCHECK_EQ(180U, CookieMonster::kDomainMaxCookies);
684 DCHECK_EQ(150U, CookieMonster::kDomainMaxCookies -
685 CookieMonster::kDomainPurgeCookies);
686
687 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
688 // Key:
689 // Round 1 => LN; round 2 => LS; round 3 => MN.
690 // Round 4 => HN; round 5 => MS; round 6 => HS
691
692 // Each test case adds 181 cookies, so 31 cookies are evicted.
693 // Cookie same priority, repeated for each priority.
694 TestPriorityCookieCase(cm.get(), "181LN", 150U, 0U, 0U, 150U, 0U);
695 TestPriorityCookieCase(cm.get(), "181MN", 0U, 150U, 0U, 150U, 0U);
696 TestPriorityCookieCase(cm.get(), "181HN", 0U, 0U, 150U, 150U, 0U);
697
698 // Pairwise scenarios.
699 // Round 1 => none; round2 => 31M; round 3 => none.
700 TestPriorityCookieCase(cm.get(), "10HN 171MN", 0U, 140U, 10U, 150U, 0U);
701 // Round 1 => 10L; round2 => 21M; round 3 => none.
702 TestPriorityCookieCase(cm.get(), "141MN 40LN", 30U, 120U, 0U, 150U, 0U);
703 // Round 1 => none; round2 => 30M; round 3 => 1H.
704 TestPriorityCookieCase(cm.get(), "101HN 80MN", 0U, 50U, 100U, 150U, 0U);
705
706 // For {low, medium} priorities right on quota, different orders.
707 // Round 1 => 1L; round 2 => none, round3 => 30H.
708 TestPriorityCookieCase(cm.get(), "31LN 50MN 100HN", 30U, 50U, 70U, 150U,
709 0U);
710 // Round 1 => none; round 2 => 1M, round3 => 30H.
711 TestPriorityCookieCase(cm.get(), "51MN 100HN 30LN", 30U, 50U, 70U, 150U,
712 0U);
713 // Round 1 => none; round 2 => none; round3 => 31H.
714 TestPriorityCookieCase(cm.get(), "101HN 50MN 30LN", 30U, 50U, 70U, 150U,
715 0U);
716
717 // Round 1 => 10L; round 2 => 10M; round3 => 11H.
718 TestPriorityCookieCase(cm.get(), "81HN 60MN 40LN", 30U, 50U, 70U, 150U, 0U);
719
720 // More complex scenarios.
721 // Round 1 => 10L; round 2 => 10M; round 3 => 11H.
722 TestPriorityCookieCase(cm.get(), "21HN 60MN 40LN 60HN", 30U, 50U, 70U, 150U,
723 0U);
724 // Round 1 => 10L; round 2 => 21M; round 3 => 0H.
725 TestPriorityCookieCase(cm.get(), "11HN 10MN 20LN 110MN 20LN 10HN", 30U, 99U,
726 21U, 150U, 0U);
727 // Round 1 => none; round 2 => none; round 3 => 31H.
728 TestPriorityCookieCase(cm.get(), "11LN 10MN 140HN 10MN 10LN", 21U, 20U,
729 109U, 150U, 0U);
730 // Round 1 => none; round 2 => 21M; round 3 => 10H.
731 TestPriorityCookieCase(cm.get(), "11MN 10HN 10LN 60MN 90HN", 10U, 50U, 90U,
732 150U, 0U);
733 // Round 1 => none; round 2 => 31M; round 3 => none.
734 TestPriorityCookieCase(cm.get(), "11MN 10HN 10LN 90MN 60HN", 10U, 70U, 70U,
735 150U, 0U);
736
737 // Round 1 => 20L; round 2 => 0; round 3 => 11H
738 TestPriorityCookieCase(cm.get(), "50LN 131HN", 30U, 0U, 120U, 150U, 0U);
739 // Round 1 => 20L; round 2 => 0; round 3 => 11H
740 TestPriorityCookieCase(cm.get(), "131HN 50LN", 30U, 0U, 120U, 150U, 0U);
741 // Round 1 => 20L; round 2 => none; round 3 => 11H.
742 TestPriorityCookieCase(cm.get(), "50HN 50LN 81HN", 30U, 0U, 120U, 150U, 0U);
743 // Round 1 => 20L; round 2 => none; round 3 => 11H.
744 TestPriorityCookieCase(cm.get(), "81HN 50LN 50HN", 30U, 0U, 120U, 150U, 0U);
745 }
746
TestPriorityAwareGarbageCollectHelperSecure()747 void TestPriorityAwareGarbageCollectHelperSecure() {
748 // Hard-coding limits in the test, but use DCHECK_EQ to enforce constraint.
749 DCHECK_EQ(180U, CookieMonster::kDomainMaxCookies);
750 DCHECK_EQ(150U, CookieMonster::kDomainMaxCookies -
751 CookieMonster::kDomainPurgeCookies);
752
753 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
754 // Key:
755 // Round 1 => LN; round 2 => LS; round 3 => MN.
756 // Round 4 => HN; round 5 => MS; round 6 => HS
757
758 // Each test case adds 181 cookies, so 31 cookies are evicted.
759 // Cookie same priority, repeated for each priority.
760 // Round 1 => 31L; round2 => none; round 3 => none.
761 TestPriorityCookieCase(cm.get(), "181LS", 150U, 0U, 0U, 0U, 150U);
762 // Round 1 => none; round2 => 31M; round 3 => none.
763 TestPriorityCookieCase(cm.get(), "181MS", 0U, 150U, 0U, 0U, 150U);
764 // Round 1 => none; round2 => none; round 3 => 31H.
765 TestPriorityCookieCase(cm.get(), "181HS", 0U, 0U, 150U, 0U, 150U);
766
767 // Pairwise scenarios.
768 // Round 1 => none; round2 => 31M; round 3 => none.
769 TestPriorityCookieCase(cm.get(), "10HS 171MS", 0U, 140U, 10U, 0U, 150U);
770 // Round 1 => 10L; round2 => 21M; round 3 => none.
771 TestPriorityCookieCase(cm.get(), "141MS 40LS", 30U, 120U, 0U, 0U, 150U);
772 // Round 1 => none; round2 => 30M; round 3 => 1H.
773 TestPriorityCookieCase(cm.get(), "101HS 80MS", 0U, 50U, 100U, 0U, 150U);
774
775 // For {low, medium} priorities right on quota, different orders.
776 // Round 1 => 1L; round 2 => none, round3 => 30H.
777 TestPriorityCookieCase(cm.get(), "31LS 50MS 100HS", 30U, 50U, 70U, 0U,
778 150U);
779 // Round 1 => none; round 2 => 1M, round3 => 30H.
780 TestPriorityCookieCase(cm.get(), "51MS 100HS 30LS", 30U, 50U, 70U, 0U,
781 150U);
782 // Round 1 => none; round 2 => none; round3 => 31H.
783 TestPriorityCookieCase(cm.get(), "101HS 50MS 30LS", 30U, 50U, 70U, 0U,
784 150U);
785
786 // Round 1 => 10L; round 2 => 10M; round3 => 11H.
787 TestPriorityCookieCase(cm.get(), "81HS 60MS 40LS", 30U, 50U, 70U, 0U, 150U);
788
789 // More complex scenarios.
790 // Round 1 => 10L; round 2 => 10M; round 3 => 11H.
791 TestPriorityCookieCase(cm.get(), "21HS 60MS 40LS 60HS", 30U, 50U, 70U, 0U,
792 150U);
793 // Round 1 => 10L; round 2 => 21M; round 3 => none.
794 TestPriorityCookieCase(cm.get(), "11HS 10MS 20LS 110MS 20LS 10HS", 30U, 99U,
795 21U, 0U, 150U);
796 // Round 1 => none; round 2 => none; round 3 => 31H.
797 TestPriorityCookieCase(cm.get(), "11LS 10MS 140HS 10MS 10LS", 21U, 20U,
798 109U, 0U, 150U);
799 // Round 1 => none; round 2 => 21M; round 3 => 10H.
800 TestPriorityCookieCase(cm.get(), "11MS 10HS 10LS 60MS 90HS", 10U, 50U, 90U,
801 0U, 150U);
802 // Round 1 => none; round 2 => 31M; round 3 => none.
803 TestPriorityCookieCase(cm.get(), "11MS 10HS 10LS 90MS 60HS", 10U, 70U, 70U,
804 0U, 150U);
805 }
806
TestPriorityAwareGarbageCollectHelperMixed()807 void TestPriorityAwareGarbageCollectHelperMixed() {
808 // Hard-coding limits in the test, but use DCHECK_EQ to enforce constraint.
809 DCHECK_EQ(180U, CookieMonster::kDomainMaxCookies);
810 DCHECK_EQ(150U, CookieMonster::kDomainMaxCookies -
811 CookieMonster::kDomainPurgeCookies);
812
813 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
814 // Key:
815 // Round 1 => LN; round 2 => LS; round 3 => MN.
816 // Round 4 => HN; round 5 => MS; round 6 => HS
817
818 // Each test case adds 180 secure cookies, and some non-secure cookie. The
819 // secure cookies take priority, so the non-secure cookie is removed, along
820 // with 30 secure cookies. Repeated for each priority, and with the
821 // non-secure cookie as older and newer.
822 // Round 1 => 1LN; round 2 => 30LS; round 3 => none.
823 // Round 4 => none; round 5 => none; round 6 => none.
824 TestPriorityCookieCase(cm.get(), "1LN 180LS", 150U, 0U, 0U, 0U, 150U);
825 // Round 1 => none; round 2 => none; round 3 => 1MN.
826 // Round 4 => none; round 5 => 30MS; round 6 => none.
827 TestPriorityCookieCase(cm.get(), "1MN 180MS", 0U, 150U, 0U, 0U, 150U);
828 // Round 1 => none; round 2 => none; round 3 => none.
829 // Round 4 => 1HN; round 5 => none; round 6 => 30HS.
830 TestPriorityCookieCase(cm.get(), "1HN 180HS", 0U, 0U, 150U, 0U, 150U);
831 // Round 1 => 1LN; round 2 => 30LS; round 3 => none.
832 // Round 4 => none; round 5 => none; round 6 => none.
833 TestPriorityCookieCase(cm.get(), "180LS 1LN", 150U, 0U, 0U, 0U, 150U);
834 // Round 1 => none; round 2 => none; round 3 => 1MN.
835 // Round 4 => none; round 5 => 30MS; round 6 => none.
836 TestPriorityCookieCase(cm.get(), "180MS 1MN", 0U, 150U, 0U, 0U, 150U);
837 // Round 1 => none; round 2 => none; round 3 => none.
838 // Round 4 => 1HN; round 5 => none; round 6 => 30HS.
839 TestPriorityCookieCase(cm.get(), "180HS 1HN", 0U, 0U, 150U, 0U, 150U);
840
841 // Quotas should be correctly maintained when a given priority has both
842 // secure and non-secure cookies.
843 //
844 // Round 1 => 10LN; round 2 => none; round 3 => none.
845 // Round 4 => 21HN; round 5 => none; round 6 => none.
846 TestPriorityCookieCase(cm.get(), "39LN 1LS 141HN", 30U, 0U, 120U, 149U, 1U);
847 // Round 1 => none; round 2 => none; round 3 => 10MN.
848 // Round 4 => none; round 5 => none; round 6 => 21HS.
849 TestPriorityCookieCase(cm.get(), "29LN 1LS 59MN 1MS 91HS", 30U, 50U, 70U,
850 78U, 72U);
851
852 // Low-priority secure cookies are removed before higher priority non-secure
853 // cookies.
854 // Round 1 => none; round 2 => 31LS; round 3 => none.
855 // Round 4 => none; round 5 => none; round 6 => none.
856 TestPriorityCookieCase(cm.get(), "180LS 1MN", 149U, 1U, 0U, 1U, 149U);
857 // Round 1 => none; round 2 => 31LS; round 3 => none.
858 // Round 4 => none; round 5 => none; round 6 => none.
859 TestPriorityCookieCase(cm.get(), "180LS 1HN", 149U, 0U, 1U, 1U, 149U);
860 // Round 1 => none; round 2 => 31LS; round 3 => none.
861 // Round 4 => none; round 5 => none; round 6 => none.
862 TestPriorityCookieCase(cm.get(), "1MN 180LS", 149U, 1U, 0U, 1U, 149U);
863 // Round 1 => none; round 2 => 31LS; round 3 => none.
864 // Round 4 => none; round 5 => none; round 6 => none.
865 TestPriorityCookieCase(cm.get(), "1HN 180LS", 149U, 0U, 1U, 1U, 149U);
866
867 // Higher-priority non-secure cookies are removed before any secure cookie
868 // with greater than low-priority. Is it true? How about the quota?
869 // Round 1 => none; round 2 => none; round 3 => none.
870 // Round 4 => none; round 5 => 31MS; round 6 => none.
871 TestPriorityCookieCase(cm.get(), "180MS 1HN", 0U, 149U, 1U, 1U, 149U);
872 // Round 1 => none; round 2 => none; round 3 => none.
873 // Round 4 => none; round 5 => 31MS; round 6 => none.
874 TestPriorityCookieCase(cm.get(), "1HN 180MS", 0U, 149U, 1U, 1U, 149U);
875
876 // Pairwise:
877 // Round 1 => 31LN; round 2 => none; round 3 => none.
878 // Round 4 => none; round 5 => none; round 6 => none.
879 TestPriorityCookieCase(cm.get(), "1LS 180LN", 150U, 0U, 0U, 149U, 1U);
880 // Round 1 => 31LN; round 2 => none; round 3 => none.
881 // Round 4 => none; round 5 => none; round 6 => none.
882 TestPriorityCookieCase(cm.get(), "100LS 81LN", 150U, 0U, 0U, 50U, 100U);
883 // Round 1 => 31LN; round 2 => none; round 3 => none.
884 // Round 4 => none; round 5 => none; round 6 => none.
885 TestPriorityCookieCase(cm.get(), "150LS 31LN", 150U, 0U, 0U, 0U, 150U);
886 // Round 1 => none; round 2 => none; round 3 => none.
887 // Round 4 => 31HN; round 5 => none; round 6 => none.
888 TestPriorityCookieCase(cm.get(), "1LS 180HN", 1U, 0U, 149U, 149U, 1U);
889 // Round 1 => none; round 2 => 31LS; round 3 => none.
890 // Round 4 => none; round 5 => none; round 6 => none.
891 TestPriorityCookieCase(cm.get(), "100LS 81HN", 69U, 0U, 81U, 81U, 69U);
892 // Round 1 => none; round 2 => 31LS; round 3 => none.
893 // Round 4 => none; round 5 => none; round 6 => none.
894 TestPriorityCookieCase(cm.get(), "150LS 31HN", 119U, 0U, 31U, 31U, 119U);
895
896 // Quota calculations inside non-secure/secure blocks remain in place:
897 // Round 1 => none; round 2 => 20LS; round 3 => none.
898 // Round 4 => 11HN; round 5 => none; round 6 => none.
899 TestPriorityCookieCase(cm.get(), "50HN 50LS 81HS", 30U, 0U, 120U, 39U,
900 111U);
901 // Round 1 => none; round 2 => none; round 3 => 31MN.
902 // Round 4 => none; round 5 => none; round 6 => none.
903 TestPriorityCookieCase(cm.get(), "11MS 10HN 10LS 90MN 60HN", 10U, 70U, 70U,
904 129U, 21U);
905 // Round 1 => 31LN; round 2 => none; round 3 => none.
906 // Round 4 => none; round 5 => none; round 6 => none.
907 TestPriorityCookieCase(cm.get(), "40LS 40LN 101HS", 49U, 0U, 101U, 9U,
908 141U);
909
910 // Multiple GC rounds end up with consistent behavior:
911 // GC is started as soon as there are 181 cookies in the store.
912 // On each major round it tries to preserve the quota for each priority.
913 // It is not aware about more cookies going in.
914 // 1 GC notices there are 181 cookies - 100HS 81LN 0MN
915 // Round 1 => 31LN; round 2 => none; round 3 => none.
916 // Round 4 => none; round 5 => none; round 6 => none.
917 // 2 GC notices there are 181 cookies - 100HS 69LN 12MN
918 // Round 1 => 31LN; round 2 => none; round 3 => none.
919 // Round 4 => none; round 5 => none; round 6 => none.
920 // 3 GC notices there are 181 cookies - 100HS 38LN 43MN
921 // Round 1 => 8LN; round 2 => none; round 3 => none.
922 // Round 4 => none; round 5 => none; round 6 => 23HS.
923 // 4 GC notcies there are 181 cookies - 77HS 30LN 74MN
924 // Round 1 => none; round 2 => none; round 3 => 24MN.
925 // Round 4 => none; round 5 => none; round 6 => 7HS.
926 TestPriorityCookieCase(cm.get(), "100HS 100LN 100MN", 30U, 76U, 70U, 106U,
927 70U);
928 }
929
930 // Function for creating a CM with a number of cookies in it,
931 // no store (and hence no ability to affect access time).
CreateMonsterForGC(int num_cookies)932 std::unique_ptr<CookieMonster> CreateMonsterForGC(int num_cookies) {
933 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
934 base::Time creation_time = base::Time::Now();
935 for (int i = 0; i < num_cookies; i++) {
936 std::unique_ptr<CanonicalCookie> cc(
937 CanonicalCookie::CreateUnsafeCookieForTesting(
938 "a", "1", base::StringPrintf("h%05d.izzle", i), /*path=*/"/",
939 creation_time, /*=expiration_time=*/base::Time(),
940 /*last_access=*/creation_time, /*last_update=*/creation_time,
941 /*secure=*/true,
942 /*httponly=*/false, CookieSameSite::NO_RESTRICTION,
943 COOKIE_PRIORITY_DEFAULT));
944 GURL source_url = cookie_util::SimulatedCookieSource(*cc, "https");
945 cm->SetCanonicalCookieAsync(std::move(cc), source_url,
946 CookieOptions::MakeAllInclusive(),
947 CookieStore::SetCookiesCallback());
948 }
949 return cm;
950 }
951
IsCookieInList(const CanonicalCookie & cookie,const CookieList & list)952 bool IsCookieInList(const CanonicalCookie& cookie, const CookieList& list) {
953 for (const auto& c : list) {
954 if (c.Name() == cookie.Name() && c.Value() == cookie.Value() &&
955 c.Domain() == cookie.Domain() && c.Path() == cookie.Path() &&
956 c.CreationDate() == cookie.CreationDate() &&
957 c.ExpiryDate() == cookie.ExpiryDate() &&
958 c.LastAccessDate() == cookie.LastAccessDate() &&
959 c.LastUpdateDate() == cookie.LastUpdateDate() &&
960 c.SecureAttribute() == cookie.SecureAttribute() &&
961 c.IsHttpOnly() == cookie.IsHttpOnly() &&
962 c.Priority() == cookie.Priority()) {
963 return true;
964 }
965 }
966
967 return false;
968 }
969 RecordingNetLogObserver net_log_;
970 };
971
972 using CookieMonsterTest = CookieMonsterTestBase<CookieMonsterTestTraits>;
973
974 class CookieMonsterTestGarbageCollectionObc
975 : public CookieMonsterTest,
976 public testing::WithParamInterface<std::tuple<bool, bool>> {
977 public:
CookieMonsterTestGarbageCollectionObc()978 CookieMonsterTestGarbageCollectionObc() {
979 scoped_feature_list_.InitWithFeatureStates(
980 {{net::features::kEnableSchemeBoundCookies, IsSchemeBoundEnabled()},
981 {net::features::kEnablePortBoundCookies, IsPortBoundEnabled()}});
982 }
983
IsSchemeBoundEnabled() const984 bool IsSchemeBoundEnabled() const { return std::get<0>(GetParam()); }
985
IsPortBoundEnabled() const986 bool IsPortBoundEnabled() const { return std::get<1>(GetParam()); }
987
988 private:
989 base::test::ScopedFeatureList scoped_feature_list_;
990 };
991
992 using CookieMonsterTestPriorityGarbageCollectionObc =
993 CookieMonsterTestGarbageCollectionObc;
994
995 struct CookiesInputInfo {
996 const GURL url;
997 const std::string name;
998 const std::string value;
999 const std::string domain;
1000 const std::string path;
1001 const base::Time expiration_time;
1002 bool secure;
1003 bool http_only;
1004 CookieSameSite same_site;
1005 CookiePriority priority;
1006 };
1007
1008 } // namespace
1009
1010 // This test suite verifies the task deferral behaviour of the CookieMonster.
1011 // Specifically, for each asynchronous method, verify that:
1012 // 1. invoking it on an uninitialized cookie store causes the store to begin
1013 // chain-loading its backing data or loading data for a specific domain key
1014 // (eTLD+1).
1015 // 2. The initial invocation does not complete until the loading completes.
1016 // 3. Invocations after the loading has completed complete immediately.
1017 class DeferredCookieTaskTest : public CookieMonsterTest {
1018 protected:
DeferredCookieTaskTest()1019 DeferredCookieTaskTest() {
1020 persistent_store_ = base::MakeRefCounted<MockPersistentCookieStore>();
1021 persistent_store_->set_store_load_commands(true);
1022 cookie_monster_ = std::make_unique<CookieMonster>(persistent_store_.get(),
1023 net::NetLog::Get());
1024 }
1025
1026 // Defines a cookie to be returned from PersistentCookieStore::Load
DeclareLoadedCookie(const GURL & url,const std::string & cookie_line,const base::Time & creation_time)1027 void DeclareLoadedCookie(const GURL& url,
1028 const std::string& cookie_line,
1029 const base::Time& creation_time) {
1030 AddCookieToList(url, cookie_line, creation_time, &loaded_cookies_);
1031 }
1032
ExecuteLoads(CookieStoreCommand::Type type)1033 void ExecuteLoads(CookieStoreCommand::Type type) {
1034 const auto& commands = persistent_store_->commands();
1035 for (size_t i = 0; i < commands.size(); ++i) {
1036 // Only the first load command will produce the cookies.
1037 if (commands[i].type == type) {
1038 persistent_store_->TakeCallbackAt(i).Run(std::move(loaded_cookies_));
1039 }
1040 }
1041 }
1042
CommandSummary(const MockPersistentCookieStore::CommandList & commands)1043 std::string CommandSummary(
1044 const MockPersistentCookieStore::CommandList& commands) {
1045 std::string out;
1046 for (const auto& command : commands) {
1047 switch (command.type) {
1048 case CookieStoreCommand::LOAD:
1049 base::StrAppend(&out, {"LOAD; "});
1050 break;
1051 case CookieStoreCommand::LOAD_COOKIES_FOR_KEY:
1052 base::StrAppend(&out, {"LOAD_FOR_KEY:", command.key, "; "});
1053 break;
1054 case CookieStoreCommand::ADD:
1055 base::StrAppend(&out, {"ADD; "});
1056 break;
1057 case CookieStoreCommand::REMOVE:
1058 base::StrAppend(&out, {"REMOVE; "});
1059 break;
1060 }
1061 }
1062 return out;
1063 }
1064
TakeCommandSummary()1065 std::string TakeCommandSummary() {
1066 return CommandSummary(persistent_store_->TakeCommands());
1067 }
1068
1069 // Holds cookies to be returned from PersistentCookieStore::Load or
1070 // PersistentCookieStore::LoadCookiesForKey.
1071 std::vector<std::unique_ptr<CanonicalCookie>> loaded_cookies_;
1072
1073 std::unique_ptr<CookieMonster> cookie_monster_;
1074 scoped_refptr<MockPersistentCookieStore> persistent_store_;
1075 };
1076
TEST_F(DeferredCookieTaskTest,DeferredGetCookieList)1077 TEST_F(DeferredCookieTaskTest, DeferredGetCookieList) {
1078 DeclareLoadedCookie(http_www_foo_.url(),
1079 "X=1; path=/" + FutureCookieExpirationString(),
1080 Time::Now() + base::Days(3));
1081
1082 GetCookieListCallback call1;
1083 cookie_monster_->GetCookieListWithOptionsAsync(
1084 http_www_foo_.url(), CookieOptions::MakeAllInclusive(),
1085 CookiePartitionKeyCollection(), call1.MakeCallback());
1086 base::RunLoop().RunUntilIdle();
1087 EXPECT_FALSE(call1.was_run());
1088
1089 // Finish the per-key load, not everything-load (which is always initiated).
1090 ExecuteLoads(CookieStoreCommand::LOAD_COOKIES_FOR_KEY);
1091 call1.WaitUntilDone();
1092 EXPECT_THAT(call1.cookies(), MatchesCookieLine("X=1"));
1093 EXPECT_EQ("LOAD; LOAD_FOR_KEY:foo.com; ", TakeCommandSummary());
1094
1095 GetCookieListCallback call2;
1096 cookie_monster_->GetCookieListWithOptionsAsync(
1097 http_www_foo_.url(), CookieOptions::MakeAllInclusive(),
1098 CookiePartitionKeyCollection(), call2.MakeCallback());
1099 // Already ready, no need for second load.
1100 EXPECT_THAT(call2.cookies(), MatchesCookieLine("X=1"));
1101 EXPECT_EQ("", TakeCommandSummary());
1102 }
1103
TEST_F(DeferredCookieTaskTest,DeferredSetCookie)1104 TEST_F(DeferredCookieTaskTest, DeferredSetCookie) {
1105 // Generate puts to store w/o needing a proper expiration.
1106 cookie_monster_->SetPersistSessionCookies(true);
1107
1108 ResultSavingCookieCallback<CookieAccessResult> call1;
1109 cookie_monster_->SetCanonicalCookieAsync(
1110 CanonicalCookie::CreateForTesting(http_www_foo_.url(), "A=B",
1111 base::Time::Now()),
1112 http_www_foo_.url(), CookieOptions::MakeAllInclusive(),
1113 call1.MakeCallback());
1114 base::RunLoop().RunUntilIdle();
1115 EXPECT_FALSE(call1.was_run());
1116
1117 ExecuteLoads(CookieStoreCommand::LOAD_COOKIES_FOR_KEY);
1118 call1.WaitUntilDone();
1119 EXPECT_TRUE(call1.result().status.IsInclude());
1120 EXPECT_EQ("LOAD; LOAD_FOR_KEY:foo.com; ADD; ", TakeCommandSummary());
1121
1122 ResultSavingCookieCallback<CookieAccessResult> call2;
1123 cookie_monster_->SetCanonicalCookieAsync(
1124 CanonicalCookie::CreateForTesting(http_www_foo_.url(), "X=Y",
1125 base::Time::Now()),
1126 http_www_foo_.url(), CookieOptions::MakeAllInclusive(),
1127 call2.MakeCallback());
1128 ASSERT_TRUE(call2.was_run());
1129 EXPECT_TRUE(call2.result().status.IsInclude());
1130 EXPECT_EQ("ADD; ", TakeCommandSummary());
1131 }
1132
TEST_F(DeferredCookieTaskTest,DeferredSetAllCookies)1133 TEST_F(DeferredCookieTaskTest, DeferredSetAllCookies) {
1134 // Generate puts to store w/o needing a proper expiration.
1135 cookie_monster_->SetPersistSessionCookies(true);
1136
1137 CookieList list;
1138 list.push_back(*CanonicalCookie::CreateUnsafeCookieForTesting(
1139 "A", "B", "." + http_www_foo_.domain(), "/", base::Time::Now(),
1140 base::Time(), base::Time(), base::Time(), false, true,
1141 CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT));
1142 list.push_back(*CanonicalCookie::CreateUnsafeCookieForTesting(
1143 "C", "D", "." + http_www_foo_.domain(), "/", base::Time::Now(),
1144 base::Time(), base::Time(), base::Time(), false, true,
1145 CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT));
1146
1147 ResultSavingCookieCallback<CookieAccessResult> call1;
1148 cookie_monster_->SetAllCookiesAsync(list, call1.MakeCallback());
1149 base::RunLoop().RunUntilIdle();
1150 EXPECT_FALSE(call1.was_run());
1151
1152 ExecuteLoads(CookieStoreCommand::LOAD);
1153 call1.WaitUntilDone();
1154 EXPECT_TRUE(call1.result().status.IsInclude());
1155 EXPECT_EQ("LOAD; ADD; ADD; ", TakeCommandSummary());
1156
1157 // 2nd set doesn't need to read from store. It erases the old cookies, though.
1158 ResultSavingCookieCallback<CookieAccessResult> call2;
1159 cookie_monster_->SetAllCookiesAsync(list, call2.MakeCallback());
1160 ASSERT_TRUE(call2.was_run());
1161 EXPECT_TRUE(call2.result().status.IsInclude());
1162 EXPECT_EQ("REMOVE; REMOVE; ADD; ADD; ", TakeCommandSummary());
1163 }
1164
TEST_F(DeferredCookieTaskTest,DeferredGetAllCookies)1165 TEST_F(DeferredCookieTaskTest, DeferredGetAllCookies) {
1166 DeclareLoadedCookie(http_www_foo_.url(),
1167 "X=1; path=/" + FutureCookieExpirationString(),
1168 Time::Now() + base::Days(3));
1169
1170 GetAllCookiesCallback call1;
1171 cookie_monster_->GetAllCookiesAsync(call1.MakeCallback());
1172 base::RunLoop().RunUntilIdle();
1173 EXPECT_FALSE(call1.was_run());
1174
1175 ExecuteLoads(CookieStoreCommand::LOAD);
1176 call1.WaitUntilDone();
1177 EXPECT_THAT(call1.cookies(), MatchesCookieLine("X=1"));
1178 EXPECT_EQ("LOAD; ", TakeCommandSummary());
1179
1180 GetAllCookiesCallback call2;
1181 cookie_monster_->GetAllCookiesAsync(call2.MakeCallback());
1182 EXPECT_TRUE(call2.was_run());
1183 EXPECT_THAT(call2.cookies(), MatchesCookieLine("X=1"));
1184 EXPECT_EQ("", TakeCommandSummary());
1185 }
1186
TEST_F(DeferredCookieTaskTest,DeferredGetAllForUrlCookies)1187 TEST_F(DeferredCookieTaskTest, DeferredGetAllForUrlCookies) {
1188 DeclareLoadedCookie(http_www_foo_.url(),
1189 "X=1; path=/" + FutureCookieExpirationString(),
1190 Time::Now() + base::Days(3));
1191
1192 GetCookieListCallback call1;
1193 cookie_monster_->GetCookieListWithOptionsAsync(
1194 http_www_foo_.url(), CookieOptions::MakeAllInclusive(),
1195 CookiePartitionKeyCollection(), call1.MakeCallback());
1196 base::RunLoop().RunUntilIdle();
1197 EXPECT_FALSE(call1.was_run());
1198
1199 ExecuteLoads(CookieStoreCommand::LOAD_COOKIES_FOR_KEY);
1200 call1.WaitUntilDone();
1201 EXPECT_THAT(call1.cookies(), MatchesCookieLine("X=1"));
1202 EXPECT_EQ("LOAD; LOAD_FOR_KEY:foo.com; ", TakeCommandSummary());
1203
1204 GetCookieListCallback call2;
1205 cookie_monster_->GetCookieListWithOptionsAsync(
1206 http_www_foo_.url(), CookieOptions::MakeAllInclusive(),
1207 CookiePartitionKeyCollection(), call2.MakeCallback());
1208 EXPECT_TRUE(call2.was_run());
1209 EXPECT_THAT(call2.cookies(), MatchesCookieLine("X=1"));
1210 EXPECT_EQ("", TakeCommandSummary());
1211 }
1212
TEST_F(DeferredCookieTaskTest,DeferredGetAllForUrlWithOptionsCookies)1213 TEST_F(DeferredCookieTaskTest, DeferredGetAllForUrlWithOptionsCookies) {
1214 DeclareLoadedCookie(http_www_foo_.url(),
1215 "X=1; path=/" + FutureCookieExpirationString(),
1216 Time::Now() + base::Days(3));
1217
1218 GetCookieListCallback call1;
1219 cookie_monster_->GetCookieListWithOptionsAsync(
1220 http_www_foo_.url(), CookieOptions::MakeAllInclusive(),
1221 CookiePartitionKeyCollection(), call1.MakeCallback());
1222 base::RunLoop().RunUntilIdle();
1223 EXPECT_FALSE(call1.was_run());
1224
1225 ExecuteLoads(CookieStoreCommand::LOAD_COOKIES_FOR_KEY);
1226 call1.WaitUntilDone();
1227 EXPECT_THAT(call1.cookies(), MatchesCookieLine("X=1"));
1228 EXPECT_EQ("LOAD; LOAD_FOR_KEY:foo.com; ", TakeCommandSummary());
1229
1230 GetCookieListCallback call2;
1231 cookie_monster_->GetCookieListWithOptionsAsync(
1232 http_www_foo_.url(), CookieOptions::MakeAllInclusive(),
1233 CookiePartitionKeyCollection(), call2.MakeCallback());
1234 EXPECT_TRUE(call2.was_run());
1235 EXPECT_THAT(call2.cookies(), MatchesCookieLine("X=1"));
1236 EXPECT_EQ("", TakeCommandSummary());
1237 }
1238
TEST_F(DeferredCookieTaskTest,DeferredDeleteAllCookies)1239 TEST_F(DeferredCookieTaskTest, DeferredDeleteAllCookies) {
1240 DeclareLoadedCookie(http_www_foo_.url(),
1241 "X=1; path=/" + FutureCookieExpirationString(),
1242 Time::Now() + base::Days(3));
1243
1244 ResultSavingCookieCallback<uint32_t> call1;
1245 cookie_monster_->DeleteAllAsync(call1.MakeCallback());
1246 base::RunLoop().RunUntilIdle();
1247 EXPECT_FALSE(call1.was_run());
1248
1249 ExecuteLoads(CookieStoreCommand::LOAD);
1250 call1.WaitUntilDone();
1251 EXPECT_EQ(1u, call1.result());
1252 EXPECT_EQ("LOAD; REMOVE; ", TakeCommandSummary());
1253
1254 ResultSavingCookieCallback<uint32_t> call2;
1255 cookie_monster_->DeleteAllAsync(call2.MakeCallback());
1256 // This needs an event loop spin since DeleteAllAsync always reports
1257 // asynchronously.
1258 call2.WaitUntilDone();
1259 EXPECT_EQ(0u, call2.result());
1260 EXPECT_EQ("", TakeCommandSummary());
1261 }
1262
TEST_F(DeferredCookieTaskTest,DeferredDeleteAllCreatedInTimeRangeCookies)1263 TEST_F(DeferredCookieTaskTest, DeferredDeleteAllCreatedInTimeRangeCookies) {
1264 const TimeRange time_range(base::Time(), base::Time::Now());
1265
1266 ResultSavingCookieCallback<uint32_t> call1;
1267 cookie_monster_->DeleteAllCreatedInTimeRangeAsync(time_range,
1268 call1.MakeCallback());
1269 base::RunLoop().RunUntilIdle();
1270 EXPECT_FALSE(call1.was_run());
1271
1272 ExecuteLoads(CookieStoreCommand::LOAD);
1273 call1.WaitUntilDone();
1274 EXPECT_EQ(0u, call1.result());
1275 EXPECT_EQ("LOAD; ", TakeCommandSummary());
1276
1277 ResultSavingCookieCallback<uint32_t> call2;
1278 cookie_monster_->DeleteAllCreatedInTimeRangeAsync(time_range,
1279 call2.MakeCallback());
1280 call2.WaitUntilDone();
1281 EXPECT_EQ(0u, call2.result());
1282 EXPECT_EQ("", TakeCommandSummary());
1283 }
1284
TEST_F(DeferredCookieTaskTest,DeferredDeleteAllWithPredicateCreatedInTimeRangeCookies)1285 TEST_F(DeferredCookieTaskTest,
1286 DeferredDeleteAllWithPredicateCreatedInTimeRangeCookies) {
1287 ResultSavingCookieCallback<uint32_t> call1;
1288 cookie_monster_->DeleteAllMatchingInfoAsync(
1289 CookieDeletionInfo(Time(), Time::Now()), call1.MakeCallback());
1290 base::RunLoop().RunUntilIdle();
1291 EXPECT_FALSE(call1.was_run());
1292
1293 ExecuteLoads(CookieStoreCommand::LOAD);
1294 call1.WaitUntilDone();
1295 EXPECT_EQ(0u, call1.result());
1296 EXPECT_EQ("LOAD; ", TakeCommandSummary());
1297
1298 ResultSavingCookieCallback<uint32_t> call2;
1299 cookie_monster_->DeleteAllMatchingInfoAsync(
1300 CookieDeletionInfo(Time(), Time::Now()), call2.MakeCallback());
1301 call2.WaitUntilDone();
1302 EXPECT_EQ(0u, call2.result());
1303 EXPECT_EQ("", TakeCommandSummary());
1304 }
1305
TEST_F(DeferredCookieTaskTest,DeferredDeleteMatchingCookies)1306 TEST_F(DeferredCookieTaskTest, DeferredDeleteMatchingCookies) {
1307 ResultSavingCookieCallback<uint32_t> call1;
1308 cookie_monster_->DeleteMatchingCookiesAsync(
1309 base::BindRepeating(
1310 [](const net::CanonicalCookie& cookie) { return true; }),
1311 call1.MakeCallback());
1312 base::RunLoop().RunUntilIdle();
1313 EXPECT_FALSE(call1.was_run());
1314
1315 ExecuteLoads(CookieStoreCommand::LOAD);
1316 call1.WaitUntilDone();
1317 EXPECT_EQ(0u, call1.result());
1318 EXPECT_EQ("LOAD; ", TakeCommandSummary());
1319
1320 ResultSavingCookieCallback<uint32_t> call2;
1321 cookie_monster_->DeleteMatchingCookiesAsync(
1322 base::BindRepeating(
1323 [](const net::CanonicalCookie& cookie) { return true; }),
1324 call2.MakeCallback());
1325 call2.WaitUntilDone();
1326 EXPECT_EQ(0u, call2.result());
1327 EXPECT_EQ("", TakeCommandSummary());
1328 }
1329
TEST_F(DeferredCookieTaskTest,DeferredDeleteCanonicalCookie)1330 TEST_F(DeferredCookieTaskTest, DeferredDeleteCanonicalCookie) {
1331 std::unique_ptr<CanonicalCookie> cookie = BuildCanonicalCookie(
1332 http_www_foo_.url(), "X=1; path=/", base::Time::Now());
1333
1334 ResultSavingCookieCallback<uint32_t> call1;
1335 cookie_monster_->DeleteCanonicalCookieAsync(*cookie, call1.MakeCallback());
1336 base::RunLoop().RunUntilIdle();
1337 EXPECT_FALSE(call1.was_run());
1338
1339 // TODO(morlovich): Fix DeleteCanonicalCookieAsync. This test should pass
1340 // when using LOAD_COOKIES_FOR_KEY instead, with that reflected in
1341 // TakeCommandSummary() as well.
1342 ExecuteLoads(CookieStoreCommand::LOAD);
1343 call1.WaitUntilDone();
1344 EXPECT_EQ(0u, call1.result());
1345 EXPECT_EQ("LOAD; ", TakeCommandSummary());
1346
1347 ResultSavingCookieCallback<uint32_t> call2;
1348 cookie_monster_->DeleteCanonicalCookieAsync(*cookie, call2.MakeCallback());
1349 call2.WaitUntilDone();
1350 EXPECT_EQ(0u, call2.result());
1351 EXPECT_EQ("", TakeCommandSummary());
1352 }
1353
TEST_F(DeferredCookieTaskTest,DeferredDeleteSessionCookies)1354 TEST_F(DeferredCookieTaskTest, DeferredDeleteSessionCookies) {
1355 ResultSavingCookieCallback<uint32_t> call1;
1356 cookie_monster_->DeleteSessionCookiesAsync(call1.MakeCallback());
1357 base::RunLoop().RunUntilIdle();
1358 EXPECT_FALSE(call1.was_run());
1359
1360 ExecuteLoads(CookieStoreCommand::LOAD);
1361 call1.WaitUntilDone();
1362 EXPECT_EQ(0u, call1.result());
1363 EXPECT_EQ("LOAD; ", TakeCommandSummary());
1364
1365 ResultSavingCookieCallback<uint32_t> call2;
1366 cookie_monster_->DeleteSessionCookiesAsync(call2.MakeCallback());
1367 call2.WaitUntilDone();
1368 EXPECT_EQ(0u, call2.result());
1369 EXPECT_EQ("", TakeCommandSummary());
1370 }
1371
1372 // Verify that a series of queued tasks are executed in order upon loading of
1373 // the backing store and that new tasks received while the queued tasks are
1374 // being dispatched go to the end of the queue.
TEST_F(DeferredCookieTaskTest,DeferredTaskOrder)1375 TEST_F(DeferredCookieTaskTest, DeferredTaskOrder) {
1376 cookie_monster_->SetPersistSessionCookies(true);
1377 DeclareLoadedCookie(http_www_foo_.url(),
1378 "X=1; path=/" + FutureCookieExpirationString(),
1379 Time::Now() + base::Days(3));
1380
1381 bool get_cookie_list_callback_was_run = false;
1382 GetCookieListCallback get_cookie_list_callback_deferred;
1383 ResultSavingCookieCallback<CookieAccessResult> set_cookies_callback;
1384 base::RunLoop run_loop;
1385 cookie_monster_->GetCookieListWithOptionsAsync(
1386 http_www_foo_.url(), CookieOptions::MakeAllInclusive(),
1387 CookiePartitionKeyCollection(),
1388 base::BindLambdaForTesting(
1389 [&](const CookieAccessResultList& cookies,
1390 const CookieAccessResultList& excluded_list) {
1391 // This should complete before the set.
1392 get_cookie_list_callback_was_run = true;
1393 EXPECT_FALSE(set_cookies_callback.was_run());
1394 EXPECT_THAT(cookies, MatchesCookieLine("X=1"));
1395 // Can't use TakeCommandSummary here since ExecuteLoads is walking
1396 // through the data it takes.
1397 EXPECT_EQ("LOAD; LOAD_FOR_KEY:foo.com; ",
1398 CommandSummary(persistent_store_->commands()));
1399
1400 // Queue up a second get. It should see the result of the set queued
1401 // before it.
1402 cookie_monster_->GetCookieListWithOptionsAsync(
1403 http_www_foo_.url(), CookieOptions::MakeAllInclusive(),
1404 CookiePartitionKeyCollection(),
1405 get_cookie_list_callback_deferred.MakeCallback());
1406
1407 run_loop.Quit();
1408 }));
1409
1410 cookie_monster_->SetCanonicalCookieAsync(
1411 CanonicalCookie::CreateForTesting(http_www_foo_.url(), "A=B",
1412 base::Time::Now()),
1413 http_www_foo_.url(), CookieOptions::MakeAllInclusive(),
1414 set_cookies_callback.MakeCallback());
1415
1416 // Nothing happened yet, before loads are done.
1417 base::RunLoop().RunUntilIdle();
1418 EXPECT_FALSE(get_cookie_list_callback_was_run);
1419 EXPECT_FALSE(set_cookies_callback.was_run());
1420
1421 ExecuteLoads(CookieStoreCommand::LOAD_COOKIES_FOR_KEY);
1422 run_loop.Run();
1423 EXPECT_EQ("LOAD; LOAD_FOR_KEY:foo.com; ADD; ", TakeCommandSummary());
1424 EXPECT_TRUE(get_cookie_list_callback_was_run);
1425 ASSERT_TRUE(set_cookies_callback.was_run());
1426 EXPECT_TRUE(set_cookies_callback.result().status.IsInclude());
1427
1428 ASSERT_TRUE(get_cookie_list_callback_deferred.was_run());
1429 EXPECT_THAT(get_cookie_list_callback_deferred.cookies(),
1430 MatchesCookieLine("A=B; X=1"));
1431 }
1432
TEST_F(CookieMonsterTest,TestCookieDeleteAll)1433 TEST_F(CookieMonsterTest, TestCookieDeleteAll) {
1434 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
1435 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
1436 CookieOptions options = CookieOptions::MakeAllInclusive();
1437
1438 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), kValidCookieLine));
1439 EXPECT_EQ("A=B", GetCookies(cm.get(), http_www_foo_.url()));
1440
1441 EXPECT_TRUE(CreateAndSetCookie(cm.get(), http_www_foo_.url(), "C=D; httponly",
1442 options));
1443 EXPECT_EQ("A=B; C=D",
1444 GetCookiesWithOptions(cm.get(), http_www_foo_.url(), options));
1445
1446 EXPECT_EQ(2u, DeleteAll(cm.get()));
1447 EXPECT_EQ("", GetCookiesWithOptions(cm.get(), http_www_foo_.url(), options));
1448 EXPECT_EQ(0u, store->commands().size());
1449
1450 // Create a persistent cookie.
1451 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(),
1452 kValidCookieLine + FutureCookieExpirationString()));
1453 ASSERT_EQ(1u, store->commands().size());
1454 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
1455
1456 EXPECT_EQ(1u, DeleteAll(cm.get())); // sync_to_store = true.
1457 ASSERT_EQ(2u, store->commands().size());
1458 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
1459
1460 EXPECT_EQ("", GetCookiesWithOptions(cm.get(), http_www_foo_.url(), options));
1461
1462 // Create a Partitioned cookie.
1463 auto cookie_partition_key =
1464 CookiePartitionKey::FromURLForTesting(GURL("https://toplevelsite.com"));
1465 EXPECT_TRUE(SetCookie(
1466 cm.get(), https_www_foo_.url(),
1467 "__Host-" + std::string(kValidCookieLine) + "; partitioned; secure",
1468 cookie_partition_key));
1469 EXPECT_EQ(1u, DeleteAll(cm.get()));
1470 EXPECT_EQ("", GetCookiesWithOptions(
1471 cm.get(), http_www_foo_.url(), options,
1472 CookiePartitionKeyCollection(cookie_partition_key)));
1473 EXPECT_EQ(2u, store->commands().size());
1474 }
1475
TEST_F(CookieMonsterTest,TestCookieDeleteAllCreatedInTimeRangeTimestamps)1476 TEST_F(CookieMonsterTest, TestCookieDeleteAllCreatedInTimeRangeTimestamps) {
1477 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
1478
1479 Time now = Time::Now();
1480
1481 // Nothing has been added so nothing should be deleted.
1482 EXPECT_EQ(0u, DeleteAllCreatedInTimeRange(
1483 cm.get(), TimeRange(now - base::Days(99), Time())));
1484
1485 // Create 5 cookies with different creation dates.
1486 EXPECT_TRUE(
1487 SetCookieWithCreationTime(cm.get(), http_www_foo_.url(), "T-0=Now", now));
1488 EXPECT_TRUE(SetCookieWithCreationTime(cm.get(), http_www_foo_.url(),
1489 "T-1=Yesterday", now - base::Days(1)));
1490 EXPECT_TRUE(SetCookieWithCreationTime(cm.get(), http_www_foo_.url(),
1491 "T-2=DayBefore", now - base::Days(2)));
1492 EXPECT_TRUE(SetCookieWithCreationTime(cm.get(), http_www_foo_.url(),
1493 "T-3=ThreeDays", now - base::Days(3)));
1494 EXPECT_TRUE(SetCookieWithCreationTime(cm.get(), http_www_foo_.url(),
1495 "T-7=LastWeek", now - base::Days(7)));
1496
1497 // Try to delete threedays and the daybefore.
1498 EXPECT_EQ(2u,
1499 DeleteAllCreatedInTimeRange(
1500 cm.get(), TimeRange(now - base::Days(3), now - base::Days(1))));
1501
1502 // Try to delete yesterday, also make sure that delete_end is not
1503 // inclusive.
1504 EXPECT_EQ(1u, DeleteAllCreatedInTimeRange(
1505 cm.get(), TimeRange(now - base::Days(2), now)));
1506
1507 // Make sure the delete_begin is inclusive.
1508 EXPECT_EQ(1u, DeleteAllCreatedInTimeRange(
1509 cm.get(), TimeRange(now - base::Days(7), now)));
1510
1511 // Delete the last (now) item.
1512 EXPECT_EQ(1u, DeleteAllCreatedInTimeRange(cm.get(), TimeRange()));
1513
1514 // Really make sure everything is gone.
1515 EXPECT_EQ(0u, DeleteAll(cm.get()));
1516
1517 // Test the same deletion process with partitioned cookies. Partitioned
1518 // cookies should behave the same way as unpartitioned cookies here, they are
1519 // just stored in a different data structure internally.
1520
1521 EXPECT_TRUE(
1522 SetCookieWithCreationTime(cm.get(), http_www_foo_.url(), "T-0=Now", now,
1523 CookiePartitionKey::FromURLForTesting(
1524 GURL("https://toplevelsite0.com"))));
1525 EXPECT_TRUE(SetCookieWithCreationTime(
1526 cm.get(), https_www_foo_.url(), "T-1=Yesterday", now - base::Days(1),
1527 CookiePartitionKey::FromURLForTesting(
1528 GURL("https://toplevelsite1.com"))));
1529 EXPECT_TRUE(SetCookieWithCreationTime(
1530 cm.get(), http_www_foo_.url(), "T-2=DayBefore", now - base::Days(2),
1531 CookiePartitionKey::FromURLForTesting(
1532 GURL("https://toplevelsite1.com"))));
1533 EXPECT_TRUE(SetCookieWithCreationTime(
1534 cm.get(), http_www_foo_.url(), "T-3=ThreeDays", now - base::Days(3),
1535 CookiePartitionKey::FromURLForTesting(
1536 GURL("https://toplevelsite2.com"))));
1537 EXPECT_TRUE(SetCookieWithCreationTime(
1538 cm.get(), http_www_foo_.url(), "T-7=LastWeek", now - base::Days(7),
1539 CookiePartitionKey::FromURLForTesting(
1540 GURL("https://toplevelsite3.com"))));
1541
1542 // Try to delete threedays and the daybefore.
1543 EXPECT_EQ(2u,
1544 DeleteAllCreatedInTimeRange(
1545 cm.get(), TimeRange(now - base::Days(3), now - base::Days(1))));
1546
1547 // Try to delete yesterday, also make sure that delete_end is not
1548 // inclusive.
1549 EXPECT_EQ(1u, DeleteAllCreatedInTimeRange(
1550 cm.get(), TimeRange(now - base::Days(2), now)));
1551
1552 // Make sure the delete_begin is inclusive.
1553 EXPECT_EQ(1u, DeleteAllCreatedInTimeRange(
1554 cm.get(), TimeRange(now - base::Days(7), now)));
1555
1556 // Delete the last (now) item.
1557 EXPECT_EQ(1u, DeleteAllCreatedInTimeRange(cm.get(), TimeRange()));
1558
1559 // Really make sure everything is gone.
1560 EXPECT_EQ(0u, DeleteAll(cm.get()));
1561 }
1562
TEST_F(CookieMonsterTest,TestCookieDeleteAllCreatedInTimeRangeTimestampsWithInfo)1563 TEST_F(CookieMonsterTest,
1564 TestCookieDeleteAllCreatedInTimeRangeTimestampsWithInfo) {
1565 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
1566
1567 Time now = Time::Now();
1568
1569 CanonicalCookie test_cookie;
1570
1571 // Nothing has been added so nothing should be deleted.
1572 EXPECT_EQ(0u,
1573 DeleteAllMatchingInfo(
1574 cm.get(), CookieDeletionInfo(now - base::Days(99), Time())));
1575
1576 // Create 5 cookies with different creation dates.
1577 EXPECT_TRUE(
1578 SetCookieWithCreationTime(cm.get(), http_www_foo_.url(), "T-0=Now", now));
1579 EXPECT_TRUE(SetCookieWithCreationTime(cm.get(), http_www_foo_.url(),
1580 "T-1=Yesterday", now - base::Days(1)));
1581 EXPECT_TRUE(SetCookieWithCreationTime(cm.get(), http_www_foo_.url(),
1582 "T-2=DayBefore", now - base::Days(2)));
1583 EXPECT_TRUE(SetCookieWithCreationTime(cm.get(), http_www_foo_.url(),
1584 "T-3=ThreeDays", now - base::Days(3)));
1585 EXPECT_TRUE(SetCookieWithCreationTime(cm.get(), http_www_foo_.url(),
1586 "T-7=LastWeek", now - base::Days(7)));
1587
1588 // Delete threedays and the daybefore.
1589 EXPECT_EQ(2u, DeleteAllMatchingInfo(cm.get(),
1590 CookieDeletionInfo(now - base::Days(3),
1591 now - base::Days(1))));
1592
1593 // Delete yesterday, also make sure that delete_end is not inclusive.
1594 EXPECT_EQ(1u, DeleteAllMatchingInfo(
1595 cm.get(), CookieDeletionInfo(now - base::Days(2), now)));
1596
1597 // Make sure the delete_begin is inclusive.
1598 EXPECT_EQ(1u, DeleteAllMatchingInfo(
1599 cm.get(), CookieDeletionInfo(now - base::Days(7), now)));
1600
1601 // Delete the last (now) item.
1602 EXPECT_EQ(1u, DeleteAllMatchingInfo(cm.get(), CookieDeletionInfo()));
1603
1604 // Really make sure everything is gone.
1605 EXPECT_EQ(0u, DeleteAll(cm.get()));
1606
1607 // Test the same deletion process with partitioned cookies. Partitioned
1608 // cookies should behave the same way as unpartitioned cookies here, they are
1609 // just stored in a different data structure internally.
1610
1611 EXPECT_TRUE(
1612 SetCookieWithCreationTime(cm.get(), http_www_foo_.url(), "T-0=Now", now,
1613 CookiePartitionKey::FromURLForTesting(
1614 GURL("https://toplevelsite0.com"))));
1615 EXPECT_TRUE(SetCookieWithCreationTime(
1616 cm.get(), https_www_foo_.url(), "T-1=Yesterday", now - base::Days(1),
1617 CookiePartitionKey::FromURLForTesting(
1618 GURL("https://toplevelsite1.com"))));
1619 EXPECT_TRUE(SetCookieWithCreationTime(
1620 cm.get(), http_www_foo_.url(), "T-2=DayBefore", now - base::Days(2),
1621 CookiePartitionKey::FromURLForTesting(
1622 GURL("https://toplevelsite1.com"))));
1623 EXPECT_TRUE(SetCookieWithCreationTime(
1624 cm.get(), http_www_foo_.url(), "T-3=ThreeDays", now - base::Days(3),
1625 CookiePartitionKey::FromURLForTesting(
1626 GURL("https://toplevelsite2.com"))));
1627 EXPECT_TRUE(SetCookieWithCreationTime(
1628 cm.get(), http_www_foo_.url(), "T-7=LastWeek", now - base::Days(7),
1629 CookiePartitionKey::FromURLForTesting(
1630 GURL("https://toplevelsite3.com"))));
1631
1632 // Delete threedays and the daybefore.
1633 EXPECT_EQ(2u, DeleteAllMatchingInfo(cm.get(),
1634 CookieDeletionInfo(now - base::Days(3),
1635 now - base::Days(1))));
1636
1637 // Delete yesterday, also make sure that delete_end is not inclusive.
1638 EXPECT_EQ(1u, DeleteAllMatchingInfo(
1639 cm.get(), CookieDeletionInfo(now - base::Days(2), now)));
1640
1641 // Make sure the delete_begin is inclusive.
1642 EXPECT_EQ(1u, DeleteAllMatchingInfo(
1643 cm.get(), CookieDeletionInfo(now - base::Days(7), now)));
1644
1645 // Delete the last (now) item.
1646 EXPECT_EQ(1u, DeleteAllMatchingInfo(cm.get(), CookieDeletionInfo()));
1647
1648 // Really make sure everything is gone.
1649 EXPECT_EQ(0u, DeleteAll(cm.get()));
1650 }
1651
TEST_F(CookieMonsterTest,TestCookieDeleteMatchingCookies)1652 TEST_F(CookieMonsterTest, TestCookieDeleteMatchingCookies) {
1653 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
1654 Time now = Time::Now();
1655
1656 // Nothing has been added so nothing should be deleted.
1657 EXPECT_EQ(0u, DeleteMatchingCookies(
1658 cm.get(),
1659 base::BindRepeating([](const net::CanonicalCookie& cookie) {
1660 return true;
1661 })));
1662
1663 // Create 5 cookies with different domains and security status.
1664 EXPECT_TRUE(SetCookieWithCreationTime(cm.get(), GURL("https://a.com"),
1665 "a1=1;Secure", now));
1666 EXPECT_TRUE(
1667 SetCookieWithCreationTime(cm.get(), GURL("https://a.com"), "a2=2", now));
1668 EXPECT_TRUE(SetCookieWithCreationTime(cm.get(), GURL("https://b.com"),
1669 "b1=1;Secure", now));
1670 EXPECT_TRUE(
1671 SetCookieWithCreationTime(cm.get(), GURL("http://b.com"), "b2=2", now));
1672 EXPECT_TRUE(SetCookieWithCreationTime(cm.get(), GURL("https://c.com"),
1673 "c1=1;Secure", now));
1674
1675 // Set a partitioned cookie.
1676 EXPECT_TRUE(SetCookieWithCreationTime(
1677 cm.get(), GURL("https://d.com"),
1678 "__Host-pc=123; path=/; secure; partitioned", now,
1679 CookiePartitionKey::FromURLForTesting(GURL("https://e.com"))));
1680
1681 // Delete http cookies.
1682 EXPECT_EQ(2u, DeleteMatchingCookies(
1683 cm.get(),
1684 base::BindRepeating([](const net::CanonicalCookie& cookie) {
1685 return !cookie.SecureAttribute();
1686 })));
1687 EXPECT_THAT(GetAllCookies(cm.get()),
1688 ElementsAre(MatchesCookieNameDomain("a1", "a.com"),
1689 MatchesCookieNameDomain("b1", "b.com"),
1690 MatchesCookieNameDomain("c1", "c.com"),
1691 MatchesCookieNameDomain("__Host-pc", "d.com")));
1692
1693 // Delete remaining cookie for a.com.
1694 EXPECT_EQ(1u, DeleteMatchingCookies(
1695 cm.get(),
1696 base::BindRepeating([](const net::CanonicalCookie& cookie) {
1697 return cookie.Domain() == "a.com";
1698 })));
1699 EXPECT_THAT(GetAllCookies(cm.get()),
1700 ElementsAre(MatchesCookieNameDomain("b1", "b.com"),
1701 MatchesCookieNameDomain("c1", "c.com"),
1702 MatchesCookieNameDomain("__Host-pc", "d.com")));
1703
1704 // Delete the partitioned cookie.
1705 EXPECT_EQ(1u, DeleteMatchingCookies(
1706 cm.get(),
1707 base::BindRepeating([](const net::CanonicalCookie& cookie) {
1708 return cookie.IsPartitioned();
1709 })));
1710
1711 // Delete the last two item.
1712 EXPECT_EQ(2u, DeleteMatchingCookies(
1713 cm.get(),
1714 base::BindRepeating([](const net::CanonicalCookie& cookie) {
1715 return true;
1716 })));
1717
1718 // Really make sure everything is gone.
1719 EXPECT_TRUE(GetAllCookies(cm.get()).empty());
1720 }
1721
1722 static const base::TimeDelta kLastAccessThreshold = base::Milliseconds(200);
1723 static const base::TimeDelta kAccessDelay =
1724 kLastAccessThreshold + base::Milliseconds(20);
1725
TEST_F(CookieMonsterTest,TestLastAccess)1726 TEST_F(CookieMonsterTest, TestLastAccess) {
1727 auto cm = std::make_unique<CookieMonster>(nullptr, kLastAccessThreshold,
1728 net::NetLog::Get());
1729
1730 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "A=B"));
1731 const Time last_access_date(GetFirstCookieAccessDate(cm.get()));
1732
1733 // Reading the cookie again immediately shouldn't update the access date,
1734 // since we're inside the threshold.
1735 EXPECT_EQ("A=B", GetCookies(cm.get(), http_www_foo_.url()));
1736 EXPECT_EQ(last_access_date, GetFirstCookieAccessDate(cm.get()));
1737
1738 // Reading after a short wait will update the access date, if the cookie
1739 // is requested with options that would update the access date. First, test
1740 // that the flag's behavior is respected.
1741 base::PlatformThread::Sleep(kAccessDelay);
1742 CookieOptions options = CookieOptions::MakeAllInclusive();
1743 options.set_do_not_update_access_time();
1744 EXPECT_EQ("A=B",
1745 GetCookiesWithOptions(cm.get(), http_www_foo_.url(), options));
1746 EXPECT_EQ(last_access_date, GetFirstCookieAccessDate(cm.get()));
1747
1748 // Getting all cookies for a URL doesn't update the accessed time either.
1749 CookieList cookies = GetAllCookiesForURL(cm.get(), http_www_foo_.url());
1750 auto it = cookies.begin();
1751 ASSERT_TRUE(it != cookies.end());
1752 EXPECT_EQ(http_www_foo_.host(), it->Domain());
1753 EXPECT_EQ("A", it->Name());
1754 EXPECT_EQ("B", it->Value());
1755 EXPECT_EQ(last_access_date, GetFirstCookieAccessDate(cm.get()));
1756 EXPECT_TRUE(++it == cookies.end());
1757
1758 // If the flag isn't set, the last accessed time should be updated.
1759 options.set_update_access_time();
1760 EXPECT_EQ("A=B",
1761 GetCookiesWithOptions(cm.get(), http_www_foo_.url(), options));
1762 EXPECT_FALSE(last_access_date == GetFirstCookieAccessDate(cm.get()));
1763 }
1764
TEST_P(CookieMonsterTestPriorityGarbageCollectionObc,TestHostGarbageCollection)1765 TEST_P(CookieMonsterTestPriorityGarbageCollectionObc,
1766 TestHostGarbageCollection) {
1767 TestHostGarbageCollectHelper();
1768 }
1769
TEST_P(CookieMonsterTestPriorityGarbageCollectionObc,TestPriorityAwareGarbageCollectionNonSecure)1770 TEST_P(CookieMonsterTestPriorityGarbageCollectionObc,
1771 TestPriorityAwareGarbageCollectionNonSecure) {
1772 TestPriorityAwareGarbageCollectHelperNonSecure();
1773 }
1774
TEST_P(CookieMonsterTestPriorityGarbageCollectionObc,TestPriorityAwareGarbageCollectionSecure)1775 TEST_P(CookieMonsterTestPriorityGarbageCollectionObc,
1776 TestPriorityAwareGarbageCollectionSecure) {
1777 TestPriorityAwareGarbageCollectHelperSecure();
1778 }
1779
TEST_P(CookieMonsterTestPriorityGarbageCollectionObc,TestPriorityAwareGarbageCollectionMixed)1780 TEST_P(CookieMonsterTestPriorityGarbageCollectionObc,
1781 TestPriorityAwareGarbageCollectionMixed) {
1782 TestPriorityAwareGarbageCollectHelperMixed();
1783 }
1784
1785 // Test that domain cookies are always deleted before host cookies for a given
1786 // {priority, secureness}. In this case, default priority and secure.
TEST_P(CookieMonsterTestGarbageCollectionObc,DomainCookiesPreferred)1787 TEST_P(CookieMonsterTestGarbageCollectionObc, DomainCookiesPreferred) {
1788 ASSERT_TRUE(cookie_util::IsOriginBoundCookiesPartiallyEnabled());
1789 // This test requires the following values.
1790 ASSERT_EQ(180U, CookieMonster::kDomainMaxCookies);
1791 ASSERT_EQ(150U, CookieMonster::kDomainMaxCookies -
1792 CookieMonster::kDomainPurgeCookies);
1793
1794 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
1795
1796 // Insert an extra host cookie so that one will need to be deleted;
1797 // demonstrating that host cookies will still be deleted if need be but they
1798 // aren't preferred.
1799 for (int i = 0; i < 151; i++) {
1800 std::string cookie = "host_" + base::NumberToString(i) + "=foo; Secure";
1801 EXPECT_TRUE(SetCookie(cm.get(), https_www_foo_.url(), cookie));
1802 }
1803
1804 // By adding the domain cookies after the host cookies they are more recently
1805 // accessed, which would normally cause these cookies to be preserved. By
1806 // showing that they're still deleted before the host cookies we can
1807 // demonstrate that domain cookies are preferred for deletion.
1808 for (int i = 0; i < 30; i++) {
1809 std::string cookie = "domain_" + base::NumberToString(i) +
1810 "=foo; Secure; Domain=" + https_www_foo_.domain();
1811 EXPECT_TRUE(SetCookie(cm.get(), https_www_foo_.url(), cookie));
1812 }
1813
1814 auto cookie_list = this->GetAllCookiesForURL(cm.get(), https_www_foo_.url());
1815
1816 int domain_count = 0;
1817 int host_count = 0;
1818 for (const auto& cookie : cookie_list) {
1819 if (cookie.IsHostCookie()) {
1820 host_count++;
1821 } else {
1822 domain_count++;
1823 }
1824 }
1825
1826 EXPECT_EQ(host_count, 150);
1827 EXPECT_EQ(domain_count, 0);
1828 }
1829
1830 // Securely set cookies should always be deleted after non-securely set cookies.
TEST_P(CookieMonsterTestGarbageCollectionObc,SecureCookiesPreferred)1831 TEST_P(CookieMonsterTestGarbageCollectionObc, SecureCookiesPreferred) {
1832 ASSERT_TRUE(cookie_util::IsOriginBoundCookiesPartiallyEnabled());
1833 // This test requires the following values.
1834 ASSERT_EQ(180U, CookieMonster::kDomainMaxCookies);
1835 ASSERT_EQ(150U, CookieMonster::kDomainMaxCookies -
1836 CookieMonster::kDomainPurgeCookies);
1837
1838 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
1839
1840 // If scheme binding is enabled then the secure url is enough, otherwise we
1841 // need to also add "Secure" to the cookie line.
1842 std::string secure_attr =
1843 cookie_util::IsSchemeBoundCookiesEnabled() ? "" : "; Secure";
1844
1845 // These cookies would normally be preferred for deletion because they're 1)
1846 // Domain cookies, and 2) they're least recently accessed. But, since they're
1847 // securely set they'll be deleted after non-secure cookies.
1848 for (int i = 0; i < 151; i++) {
1849 std::string cookie = "domain_" + base::NumberToString(i) +
1850 "=foo; Domain=" + https_www_foo_.domain() +
1851 secure_attr;
1852 EXPECT_TRUE(SetCookie(cm.get(), https_www_foo_.url(), cookie));
1853 }
1854
1855 for (int i = 0; i < 30; i++) {
1856 std::string cookie = "host_" + base::NumberToString(i) + "=foo";
1857 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), cookie));
1858 }
1859
1860 auto secure_cookie_list =
1861 this->GetAllCookiesForURL(cm.get(), https_www_foo_.url());
1862 auto insecure_cookie_list =
1863 this->GetAllCookiesForURL(cm.get(), http_www_foo_.url());
1864
1865 int domain_count = 0;
1866 int host_count = 0;
1867
1868 for (const auto& cookie : secure_cookie_list) {
1869 if (cookie.IsHostCookie()) {
1870 host_count++;
1871 } else {
1872 domain_count++;
1873 }
1874 }
1875
1876 for (const auto& cookie : insecure_cookie_list) {
1877 if (cookie.IsHostCookie()) {
1878 host_count++;
1879 } else {
1880 domain_count++;
1881 }
1882 }
1883
1884 EXPECT_EQ(host_count, 0);
1885 EXPECT_EQ(domain_count, 150);
1886 }
1887
TEST_F(CookieMonsterTest,TestPartitionedCookiesGarbageCollection_Memory)1888 TEST_F(CookieMonsterTest, TestPartitionedCookiesGarbageCollection_Memory) {
1889 // Limit should be 10 KB.
1890 DCHECK_EQ(1024u * 10u, CookieMonster::kPerPartitionDomainMaxCookieBytes);
1891
1892 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
1893 auto cookie_partition_key =
1894 CookiePartitionKey::FromURLForTesting(GURL("https://toplevelsite1.com"));
1895
1896 for (size_t i = 0; i < 41; ++i) {
1897 std::string cookie_value((10240 / 40) - (i < 10 ? 1 : 2), '0');
1898 std::string cookie =
1899 base::StrCat({base::NumberToString(i), "=", cookie_value});
1900 EXPECT_TRUE(SetCookie(cm.get(), https_www_foo_.url(),
1901 cookie + "; secure; path=/; partitioned",
1902 cookie_partition_key))
1903 << "Failed to set cookie " << i;
1904 }
1905
1906 std::string cookies =
1907 this->GetCookies(cm.get(), https_www_foo_.url(),
1908 CookiePartitionKeyCollection(cookie_partition_key));
1909
1910 EXPECT_THAT(cookies, CookieStringIs(
1911 testing::Not(testing::Contains(testing::Key("0")))));
1912 for (size_t i = 1; i < 41; ++i) {
1913 EXPECT_THAT(cookies, CookieStringIs(testing::Contains(
1914 testing::Key(base::NumberToString(i)))))
1915 << "Failed to find cookie " << i;
1916 }
1917 }
1918
TEST_F(CookieMonsterTest,TestPartitionedCookiesGarbageCollection_MaxCookies)1919 TEST_F(CookieMonsterTest, TestPartitionedCookiesGarbageCollection_MaxCookies) {
1920 // Partitioned cookies also limit domains to 180 cookies per partition.
1921 DCHECK_EQ(180u, CookieMonster::kPerPartitionDomainMaxCookies);
1922
1923 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
1924 auto cookie_partition_key =
1925 CookiePartitionKey::FromURLForTesting(GURL("https://toplevelsite.com"));
1926
1927 for (size_t i = 0; i < 181; ++i) {
1928 std::string cookie = base::StrCat({base::NumberToString(i), "=0"});
1929 EXPECT_TRUE(SetCookie(cm.get(), https_www_foo_.url(),
1930 cookie + "; secure; path=/; partitioned",
1931 cookie_partition_key))
1932 << "Failed to set cookie " << i;
1933 }
1934
1935 std::string cookies =
1936 this->GetCookies(cm.get(), https_www_foo_.url(),
1937 CookiePartitionKeyCollection(cookie_partition_key));
1938 EXPECT_THAT(cookies, CookieStringIs(
1939 testing::Not(testing::Contains(testing::Key("0")))));
1940 for (size_t i = 1; i < 181; ++i) {
1941 std::string cookie = base::StrCat({base::NumberToString(i), "=0"});
1942 EXPECT_THAT(cookies, CookieStringIs(testing::Contains(
1943 testing::Key(base::NumberToString(i)))))
1944 << "Failed to find cookie " << i;
1945 }
1946 }
1947
TEST_F(CookieMonsterTest,SetCookieableSchemes)1948 TEST_F(CookieMonsterTest, SetCookieableSchemes) {
1949 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
1950
1951 auto cm_foo = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
1952
1953 // Only cm_foo should allow foo:// cookies.
1954 std::vector<std::string> schemes;
1955 schemes.push_back("foo");
1956 ResultSavingCookieCallback<bool> cookie_scheme_callback;
1957 cm_foo->SetCookieableSchemes(schemes, cookie_scheme_callback.MakeCallback());
1958 cookie_scheme_callback.WaitUntilDone();
1959 EXPECT_TRUE(cookie_scheme_callback.result());
1960
1961 GURL foo_url("foo://host/path");
1962 GURL http_url("http://host/path");
1963
1964 base::Time now = base::Time::Now();
1965 std::optional<base::Time> server_time = std::nullopt;
1966 EXPECT_TRUE(
1967 CreateAndSetCookieReturnStatus(cm.get(), http_url, "x=1").IsInclude());
1968 EXPECT_TRUE(
1969 SetCanonicalCookieReturnAccessResult(
1970 cm.get(),
1971 CanonicalCookie::CreateForTesting(http_url, "y=1", now, server_time),
1972 http_url, false /*modify_httponly*/)
1973 .status.IsInclude());
1974
1975 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), foo_url, "x=1")
1976 .HasExactlyExclusionReasonsForTesting(
1977 {CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME}));
1978 EXPECT_TRUE(
1979 SetCanonicalCookieReturnAccessResult(
1980 cm.get(),
1981 CanonicalCookie::CreateForTesting(foo_url, "y=1", now, server_time),
1982 foo_url, false /*modify_httponly*/)
1983 .status.HasExactlyExclusionReasonsForTesting(
1984 {CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME}));
1985
1986 EXPECT_TRUE(
1987 CreateAndSetCookieReturnStatus(cm_foo.get(), foo_url, "x=1").IsInclude());
1988 EXPECT_TRUE(
1989 SetCanonicalCookieReturnAccessResult(
1990 cm_foo.get(),
1991 CanonicalCookie::CreateForTesting(foo_url, "y=1", now, server_time),
1992 foo_url, false /*modify_httponly*/)
1993 .status.IsInclude());
1994
1995 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm_foo.get(), http_url, "x=1")
1996 .HasExactlyExclusionReasonsForTesting(
1997 {CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME}));
1998 EXPECT_TRUE(
1999 SetCanonicalCookieReturnAccessResult(
2000 cm_foo.get(),
2001 CanonicalCookie::CreateForTesting(http_url, "y=1", now, server_time),
2002 http_url, false /*modify_httponly*/)
2003 .status.HasExactlyExclusionReasonsForTesting(
2004 {CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME}));
2005 }
2006
TEST_F(CookieMonsterTest,SetCookieableSchemes_StoreInitialized)2007 TEST_F(CookieMonsterTest, SetCookieableSchemes_StoreInitialized) {
2008 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
2009 // Initializes the cookie store.
2010 this->GetCookies(cm.get(), https_www_foo_.url(),
2011 CookiePartitionKeyCollection());
2012
2013 std::vector<std::string> schemes;
2014 schemes.push_back("foo");
2015 ResultSavingCookieCallback<bool> cookie_scheme_callback;
2016 cm->SetCookieableSchemes(schemes, cookie_scheme_callback.MakeCallback());
2017 cookie_scheme_callback.WaitUntilDone();
2018 EXPECT_FALSE(cookie_scheme_callback.result());
2019
2020 base::Time now = base::Time::Now();
2021 std::optional<base::Time> server_time = std::nullopt;
2022 GURL foo_url("foo://host/path");
2023 EXPECT_TRUE(
2024 SetCanonicalCookieReturnAccessResult(
2025 cm.get(),
2026 CanonicalCookie::CreateForTesting(foo_url, "y=1", now, server_time),
2027 foo_url, false /*modify_httponly*/)
2028 .status.HasExactlyExclusionReasonsForTesting(
2029 {CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME}));
2030 }
2031
TEST_F(CookieMonsterTest,GetAllCookiesForURL)2032 TEST_F(CookieMonsterTest, GetAllCookiesForURL) {
2033 auto cm = std::make_unique<CookieMonster>(nullptr, kLastAccessThreshold,
2034 net::NetLog::Get());
2035
2036 // Create an httponly cookie.
2037 CookieOptions options = CookieOptions::MakeAllInclusive();
2038
2039 EXPECT_TRUE(CreateAndSetCookie(cm.get(), http_www_foo_.url(), "A=B; httponly",
2040 options));
2041 EXPECT_TRUE(CreateAndSetCookie(cm.get(), http_www_foo_.url(),
2042 http_www_foo_.Format("C=D; domain=.%D"),
2043 options));
2044 EXPECT_TRUE(CreateAndSetCookie(
2045 cm.get(), https_www_foo_.url(),
2046 http_www_foo_.Format("E=F; domain=.%D; secure"), options));
2047
2048 EXPECT_TRUE(CreateAndSetCookie(cm.get(), http_www_bar_.url(),
2049 http_www_bar_.Format("G=H; domain=.%D"),
2050 options));
2051
2052 EXPECT_TRUE(CreateAndSetCookie(
2053 cm.get(), https_www_foo_.url(),
2054 https_www_foo_.Format("I=J; domain=.%D; secure"), options));
2055
2056 // Create partitioned cookies for the same site with some partition key.
2057 auto cookie_partition_key1 =
2058 CookiePartitionKey::FromURLForTesting(GURL("https://toplevelsite1.com"));
2059 auto cookie_partition_key2 =
2060 CookiePartitionKey::FromURLForTesting(GURL("https://toplevelsite2.com"));
2061 auto cookie_partition_key3 =
2062 CookiePartitionKey::FromURLForTesting(GURL("https://toplevelsite3.com"));
2063 EXPECT_TRUE(CreateAndSetCookie(
2064 cm.get(), https_www_bar_.url(), "__Host-K=L; secure; path=/; partitioned",
2065 options, std::nullopt, std::nullopt, cookie_partition_key1));
2066 EXPECT_TRUE(CreateAndSetCookie(
2067 cm.get(), https_www_bar_.url(), "__Host-M=N; secure; path=/; partitioned",
2068 options, std::nullopt, std::nullopt, cookie_partition_key2));
2069 EXPECT_TRUE(CreateAndSetCookie(
2070 cm.get(), https_www_bar_.url(), "__Host-O=P; secure; path=/; partitioned",
2071 options, std::nullopt, std::nullopt, cookie_partition_key3));
2072
2073 const Time last_access_date(GetFirstCookieAccessDate(cm.get()));
2074
2075 base::PlatformThread::Sleep(kAccessDelay);
2076
2077 // Check cookies for url.
2078 EXPECT_THAT(
2079 GetAllCookiesForURL(cm.get(), http_www_foo_.url()),
2080 ElementsAre(MatchesCookieNameDomain("A", http_www_foo_.host()),
2081 MatchesCookieNameDomain("C", http_www_foo_.Format(".%D"))));
2082
2083 // Check cookies for url excluding http-only cookies.
2084 CookieOptions exclude_httponly = options;
2085 exclude_httponly.set_exclude_httponly();
2086
2087 EXPECT_THAT(
2088 GetAllCookiesForURLWithOptions(cm.get(), http_www_foo_.url(),
2089 exclude_httponly),
2090 ElementsAre(MatchesCookieNameDomain("C", http_www_foo_.Format(".%D"))));
2091
2092 // Test secure cookies.
2093 EXPECT_THAT(
2094 GetAllCookiesForURL(cm.get(), https_www_foo_.url()),
2095 ElementsAre(MatchesCookieNameDomain("A", http_www_foo_.host()),
2096 MatchesCookieNameDomain("C", http_www_foo_.Format(".%D")),
2097 MatchesCookieNameDomain("E", http_www_foo_.Format(".%D")),
2098 MatchesCookieNameDomain("I", http_www_foo_.Format(".%D"))));
2099
2100 // Test reading partitioned cookies for a single partition.
2101 EXPECT_THAT(
2102 GetAllCookiesForURL(cm.get(), https_www_bar_.url(),
2103 CookiePartitionKeyCollection(cookie_partition_key1)),
2104 ElementsAre(MatchesCookieNameDomain("G", https_www_bar_.Format(".%D")),
2105 MatchesCookieNameDomain("__Host-K", https_www_bar_.host())));
2106 EXPECT_THAT(
2107 GetAllCookiesForURL(cm.get(), https_www_bar_.url(),
2108 CookiePartitionKeyCollection(cookie_partition_key2)),
2109 ElementsAre(MatchesCookieNameDomain("G", https_www_bar_.Format(".%D")),
2110 MatchesCookieNameDomain("__Host-M", https_www_bar_.host())));
2111
2112 // Test reading partitioned cookies from multiple partitions.
2113 EXPECT_THAT(
2114 GetAllCookiesForURL(cm.get(), https_www_bar_.url(),
2115 CookiePartitionKeyCollection(
2116 {cookie_partition_key1, cookie_partition_key2})),
2117 ElementsAre(MatchesCookieNameDomain("G", https_www_bar_.Format(".%D")),
2118 MatchesCookieNameDomain("__Host-K", https_www_bar_.host()),
2119 MatchesCookieNameDomain("__Host-M", https_www_bar_.host())));
2120
2121 // Test reading partitioned cookies from every partition.
2122 EXPECT_THAT(
2123 GetAllCookiesForURL(cm.get(), https_www_bar_.url(),
2124 CookiePartitionKeyCollection::ContainsAll()),
2125 ElementsAre(MatchesCookieNameDomain("G", https_www_bar_.Format(".%D")),
2126 MatchesCookieNameDomain("__Host-K", https_www_bar_.host()),
2127 MatchesCookieNameDomain("__Host-M", https_www_bar_.host()),
2128 MatchesCookieNameDomain("__Host-O", https_www_bar_.host())));
2129
2130 // Test excluding partitioned cookies.
2131 EXPECT_THAT(
2132 GetAllCookiesForURL(cm.get(), https_www_bar_.url(),
2133 CookiePartitionKeyCollection()),
2134 ElementsAre(MatchesCookieNameDomain("G", https_www_bar_.Format(".%D"))));
2135
2136 // Reading after a short wait should not update the access date.
2137 EXPECT_EQ(last_access_date, GetFirstCookieAccessDate(cm.get()));
2138 }
2139
TEST_F(CookieMonsterTest,GetExcludedCookiesForURL)2140 TEST_F(CookieMonsterTest, GetExcludedCookiesForURL) {
2141 auto cm = std::make_unique<CookieMonster>(nullptr, kLastAccessThreshold,
2142 net::NetLog::Get());
2143
2144 // Create an httponly cookie.
2145 CookieOptions options = CookieOptions::MakeAllInclusive();
2146
2147 EXPECT_TRUE(CreateAndSetCookie(cm.get(), http_www_foo_.url(), "A=B; httponly",
2148 options));
2149 EXPECT_TRUE(CreateAndSetCookie(cm.get(), http_www_foo_.url(),
2150 http_www_foo_.Format("C=D; domain=.%D"),
2151 options));
2152 EXPECT_TRUE(CreateAndSetCookie(
2153 cm.get(), https_www_foo_.url(),
2154 http_www_foo_.Format("E=F; domain=.%D; secure"), options));
2155
2156 base::PlatformThread::Sleep(kAccessDelay);
2157
2158 // Check that no cookies are sent when option is turned off
2159 CookieOptions do_not_return_excluded;
2160 do_not_return_excluded.unset_return_excluded_cookies();
2161
2162 CookieAccessResultList excluded_cookies = GetExcludedCookiesForURLWithOptions(
2163 cm.get(), http_www_foo_.url(), do_not_return_excluded);
2164 auto iter = excluded_cookies.begin();
2165
2166 EXPECT_TRUE(excluded_cookies.empty());
2167
2168 // Checking that excluded cookies get sent with their statuses with http
2169 // request.
2170 excluded_cookies = GetExcludedCookiesForURL(cm.get(), http_www_foo_.url(),
2171 CookiePartitionKeyCollection());
2172 iter = excluded_cookies.begin();
2173
2174 ASSERT_TRUE(iter != excluded_cookies.end());
2175 EXPECT_EQ(http_www_foo_.Format(".%D"), iter->cookie.Domain());
2176 EXPECT_EQ("E", iter->cookie.Name());
2177 EXPECT_TRUE(iter->access_result.status.HasExactlyExclusionReasonsForTesting(
2178 {CookieInclusionStatus::EXCLUDE_SECURE_ONLY}));
2179
2180 ASSERT_TRUE(++iter == excluded_cookies.end());
2181
2182 // Checking that excluded cookies get sent with their statuses with http-only.
2183 CookieOptions return_excluded;
2184 return_excluded.set_return_excluded_cookies();
2185 return_excluded.set_exclude_httponly();
2186 return_excluded.set_same_site_cookie_context(
2187 CookieOptions::SameSiteCookieContext(
2188 CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_STRICT));
2189
2190 excluded_cookies = GetExcludedCookiesForURLWithOptions(
2191 cm.get(), http_www_foo_.url(), return_excluded);
2192 iter = excluded_cookies.begin();
2193
2194 ASSERT_TRUE(iter != excluded_cookies.end());
2195 EXPECT_EQ(http_www_foo_.host(), iter->cookie.Domain());
2196 EXPECT_EQ("A", iter->cookie.Name());
2197 EXPECT_TRUE(iter->access_result.status.HasExactlyExclusionReasonsForTesting(
2198 {CookieInclusionStatus::EXCLUDE_HTTP_ONLY}));
2199
2200 ASSERT_TRUE(++iter != excluded_cookies.end());
2201 EXPECT_EQ(http_www_foo_.Format(".%D"), iter->cookie.Domain());
2202 EXPECT_EQ("E", iter->cookie.Name());
2203 EXPECT_TRUE(iter->access_result.status.HasExactlyExclusionReasonsForTesting(
2204 {CookieInclusionStatus::EXCLUDE_SECURE_ONLY}));
2205
2206 ASSERT_TRUE(++iter == excluded_cookies.end());
2207
2208 // Check that no excluded cookies are sent with secure request
2209 excluded_cookies = GetExcludedCookiesForURL(cm.get(), https_www_foo_.url(),
2210 CookiePartitionKeyCollection());
2211 iter = excluded_cookies.begin();
2212
2213 EXPECT_TRUE(excluded_cookies.empty());
2214 }
2215
TEST_F(CookieMonsterTest,GetAllCookiesForURLPathMatching)2216 TEST_F(CookieMonsterTest, GetAllCookiesForURLPathMatching) {
2217 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
2218
2219 CookieOptions options = CookieOptions::MakeAllInclusive();
2220
2221 EXPECT_TRUE(CreateAndSetCookie(cm.get(), www_foo_foo_.url(),
2222 "A=B; path=/foo;", options));
2223 EXPECT_TRUE(CreateAndSetCookie(cm.get(), www_foo_bar_.url(),
2224 "C=D; path=/bar;", options));
2225 EXPECT_TRUE(
2226 CreateAndSetCookie(cm.get(), http_www_foo_.url(), "E=F;", options));
2227
2228 CookieList cookies = GetAllCookiesForURL(cm.get(), www_foo_foo_.url());
2229 auto it = cookies.begin();
2230
2231 ASSERT_TRUE(it != cookies.end());
2232 EXPECT_EQ("A", it->Name());
2233 EXPECT_EQ("/foo", it->Path());
2234
2235 ASSERT_TRUE(++it != cookies.end());
2236 EXPECT_EQ("E", it->Name());
2237 EXPECT_EQ("/", it->Path());
2238
2239 ASSERT_TRUE(++it == cookies.end());
2240
2241 cookies = GetAllCookiesForURL(cm.get(), www_foo_bar_.url());
2242 it = cookies.begin();
2243
2244 ASSERT_TRUE(it != cookies.end());
2245 EXPECT_EQ("C", it->Name());
2246 EXPECT_EQ("/bar", it->Path());
2247
2248 ASSERT_TRUE(++it != cookies.end());
2249 EXPECT_EQ("E", it->Name());
2250 EXPECT_EQ("/", it->Path());
2251
2252 ASSERT_TRUE(++it == cookies.end());
2253 }
2254
TEST_F(CookieMonsterTest,GetExcludedCookiesForURLPathMatching)2255 TEST_F(CookieMonsterTest, GetExcludedCookiesForURLPathMatching) {
2256 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
2257
2258 CookieOptions options = CookieOptions::MakeAllInclusive();
2259
2260 EXPECT_TRUE(CreateAndSetCookie(cm.get(), www_foo_foo_.url(),
2261 "A=B; path=/foo;", options));
2262 EXPECT_TRUE(CreateAndSetCookie(cm.get(), www_foo_bar_.url(),
2263 "C=D; path=/bar;", options));
2264 EXPECT_TRUE(
2265 CreateAndSetCookie(cm.get(), http_www_foo_.url(), "E=F;", options));
2266
2267 CookieAccessResultList excluded_cookies = GetExcludedCookiesForURL(
2268 cm.get(), www_foo_foo_.url(), CookiePartitionKeyCollection());
2269 auto it = excluded_cookies.begin();
2270
2271 ASSERT_TRUE(it != excluded_cookies.end());
2272 EXPECT_EQ("C", it->cookie.Name());
2273 EXPECT_EQ("/bar", it->cookie.Path());
2274 EXPECT_TRUE(it->access_result.status.HasExactlyExclusionReasonsForTesting(
2275 {CookieInclusionStatus::EXCLUDE_NOT_ON_PATH}));
2276
2277 ASSERT_TRUE(++it == excluded_cookies.end());
2278
2279 excluded_cookies = GetExcludedCookiesForURL(cm.get(), www_foo_bar_.url(),
2280 CookiePartitionKeyCollection());
2281 it = excluded_cookies.begin();
2282
2283 ASSERT_TRUE(it != excluded_cookies.end());
2284 EXPECT_EQ("A", it->cookie.Name());
2285 EXPECT_EQ("/foo", it->cookie.Path());
2286 EXPECT_TRUE(it->access_result.status.HasExactlyExclusionReasonsForTesting(
2287 {CookieInclusionStatus::EXCLUDE_NOT_ON_PATH}));
2288
2289 ASSERT_TRUE(++it == excluded_cookies.end());
2290 }
2291
TEST_F(CookieMonsterTest,CookieSorting)2292 TEST_F(CookieMonsterTest, CookieSorting) {
2293 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
2294
2295 base::Time system_time = base::Time::Now();
2296 for (const char* cookie_line :
2297 {"B=B1; path=/", "B=B2; path=/foo", "B=B3; path=/foo/bar",
2298 "A=A1; path=/", "A=A2; path=/foo", "A=A3; path=/foo/bar"}) {
2299 EXPECT_TRUE(SetCookieWithSystemTime(cm.get(), http_www_foo_.url(),
2300 cookie_line, system_time));
2301 system_time += base::Milliseconds(100);
2302 }
2303
2304 // Re-set cookie which should not change sort order, as the creation date
2305 // will be retained, as per RFC 6265 5.3.11.3.
2306 EXPECT_TRUE(SetCookieWithSystemTime(cm.get(), http_www_foo_.url(),
2307 "B=B3; path=/foo/bar", system_time));
2308
2309 CookieList cookies = GetAllCookies(cm.get());
2310 ASSERT_EQ(6u, cookies.size());
2311 EXPECT_EQ("B3", cookies[0].Value());
2312 EXPECT_EQ("A3", cookies[1].Value());
2313 EXPECT_EQ("B2", cookies[2].Value());
2314 EXPECT_EQ("A2", cookies[3].Value());
2315 EXPECT_EQ("B1", cookies[4].Value());
2316 EXPECT_EQ("A1", cookies[5].Value());
2317 }
2318
TEST_F(CookieMonsterTest,InheritCreationDate)2319 TEST_F(CookieMonsterTest, InheritCreationDate) {
2320 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
2321
2322 base::Time the_not_so_distant_past(base::Time::Now() - base::Seconds(1000));
2323 EXPECT_TRUE(SetCookieWithCreationTime(cm.get(), http_www_foo_.url(),
2324 "Name=Value; path=/",
2325 the_not_so_distant_past));
2326
2327 CookieList cookies = GetAllCookies(cm.get());
2328 ASSERT_EQ(1u, cookies.size());
2329 EXPECT_EQ(the_not_so_distant_past, cookies[0].CreationDate());
2330 base::Time last_update = cookies[0].LastUpdateDate();
2331
2332 // Overwrite the cookie with the same value, and verify that the creation date
2333 // is inherited. The update date isn't inherited though.
2334 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "Name=Value; path=/"));
2335
2336 cookies = GetAllCookies(cm.get());
2337 ASSERT_EQ(1u, cookies.size());
2338 EXPECT_EQ(the_not_so_distant_past, cookies[0].CreationDate());
2339 // If this is flakey you many need to manually set the last update time.
2340 EXPECT_LT(last_update, cookies[0].LastUpdateDate());
2341 last_update = cookies[0].LastUpdateDate();
2342
2343 // New value => new creation date.
2344 EXPECT_TRUE(
2345 SetCookie(cm.get(), http_www_foo_.url(), "Name=NewValue; path=/"));
2346
2347 cookies = GetAllCookies(cm.get());
2348 ASSERT_EQ(1u, cookies.size());
2349 EXPECT_NE(the_not_so_distant_past, cookies[0].CreationDate());
2350 // If this is flakey you many need to manually set the last update time.
2351 EXPECT_LT(last_update, cookies[0].LastUpdateDate());
2352 }
2353
TEST_F(CookieMonsterTest,OverwriteSource)2354 TEST_F(CookieMonsterTest, OverwriteSource) {
2355 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
2356
2357 // Set cookie with unknown source.
2358 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "A=0", std::nullopt,
2359 CookieSourceType::kUnknown));
2360 CookieList cookies = GetAllCookies(cm.get());
2361 ASSERT_EQ(1u, cookies.size());
2362 EXPECT_EQ("0", cookies[0].Value());
2363 EXPECT_EQ(CookieSourceType::kUnknown, cookies[0].SourceType());
2364
2365 // Overwrite the cookie with the same value and an http source.
2366 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "A=0", std::nullopt,
2367 CookieSourceType::kHTTP));
2368 cookies = GetAllCookies(cm.get());
2369 ASSERT_EQ(1u, cookies.size());
2370 EXPECT_EQ("0", cookies[0].Value());
2371 EXPECT_EQ(CookieSourceType::kHTTP, cookies[0].SourceType());
2372
2373 // Overwrite the cookie with a new value and a script source.
2374 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "A=1", std::nullopt,
2375 CookieSourceType::kScript));
2376 cookies = GetAllCookies(cm.get());
2377 ASSERT_EQ(1u, cookies.size());
2378 EXPECT_EQ("1", cookies[0].Value());
2379 EXPECT_EQ(CookieSourceType::kScript, cookies[0].SourceType());
2380
2381 // Overwrite the cookie with the same value and an other source.
2382 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "A=1", std::nullopt,
2383 CookieSourceType::kOther));
2384 cookies = GetAllCookies(cm.get());
2385 ASSERT_EQ(1u, cookies.size());
2386 EXPECT_EQ("1", cookies[0].Value());
2387 EXPECT_EQ(CookieSourceType::kOther, cookies[0].SourceType());
2388 }
2389
2390 // Check that GetAllCookiesForURL() does not return expired cookies and deletes
2391 // them.
TEST_F(CookieMonsterTest,DeleteExpiredCookiesOnGet)2392 TEST_F(CookieMonsterTest, DeleteExpiredCookiesOnGet) {
2393 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
2394
2395 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "A=B;"));
2396
2397 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "C=D;"));
2398
2399 CookieList cookies = GetAllCookiesForURL(cm.get(), http_www_foo_.url());
2400 EXPECT_EQ(2u, cookies.size());
2401
2402 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(),
2403 "C=D; expires=Thu, 01-Jan-1970 00:00:00 GMT"));
2404
2405 cookies = GetAllCookiesForURL(cm.get(), http_www_foo_.url());
2406 EXPECT_EQ(1u, cookies.size());
2407
2408 // Test partitioned cookies. They should exhibit the same behavior but are
2409 // stored in a different data structure internally.
2410 auto cookie_partition_key =
2411 CookiePartitionKey::FromURLForTesting(GURL("https://toplevelsite.com"));
2412
2413 EXPECT_TRUE(SetCookie(cm.get(), https_www_bar_.url(),
2414 "__Host-A=B; secure; path=/; partitioned",
2415 cookie_partition_key));
2416 EXPECT_TRUE(SetCookie(cm.get(), https_www_bar_.url(),
2417 "__Host-C=D; secure; path=/; partitioned",
2418 cookie_partition_key));
2419
2420 cookies =
2421 GetAllCookiesForURL(cm.get(), https_www_bar_.url(),
2422 CookiePartitionKeyCollection(cookie_partition_key));
2423 EXPECT_EQ(2u, cookies.size());
2424
2425 EXPECT_TRUE(SetCookie(cm.get(), https_www_bar_.url(),
2426 "__Host-C=D; secure; path=/; partitioned; expires=Thu, "
2427 "01-Jan-1970 00:00:00 GMT",
2428 cookie_partition_key));
2429
2430 cookies =
2431 GetAllCookiesForURL(cm.get(), https_www_bar_.url(),
2432 CookiePartitionKeyCollection(cookie_partition_key));
2433 EXPECT_EQ(1u, cookies.size());
2434 }
2435
2436 // Test that cookie expiration works correctly when a cookie expires because
2437 // time elapses.
TEST_F(CookieMonsterTest,DeleteExpiredCookiesAfterTimeElapsed)2438 TEST_F(CookieMonsterTest, DeleteExpiredCookiesAfterTimeElapsed) {
2439 auto cm = std::make_unique<CookieMonster>(
2440 /*store=*/nullptr, net::NetLog::Get());
2441
2442 EXPECT_TRUE(SetCookie(cm.get(), https_www_bar_.url(),
2443 "__Host-A=B; secure; path=/",
2444 /*cookie_partition_key=*/std::nullopt));
2445 // Set a cookie with a Max-Age. Since we only parse integers for this
2446 // attribute, 1 second is the minimum allowable time.
2447 EXPECT_TRUE(SetCookie(cm.get(), https_www_bar_.url(),
2448 "__Host-C=D; secure; path=/; max-age=1",
2449 /*cookie_partition_key=*/std::nullopt));
2450
2451 CookieList cookies = GetAllCookiesForURL(cm.get(), https_www_bar_.url(),
2452 CookiePartitionKeyCollection());
2453 EXPECT_EQ(2u, cookies.size());
2454
2455 // Sleep for entire Max-Age of the second cookie.
2456 base::PlatformThread::Sleep(base::Seconds(1));
2457
2458 cookies = GetAllCookiesForURL(cm.get(), https_www_bar_.url(),
2459 CookiePartitionKeyCollection());
2460 EXPECT_EQ(1u, cookies.size());
2461 EXPECT_EQ("__Host-A", cookies[0].Name());
2462 }
2463
TEST_F(CookieMonsterTest,DeleteExpiredPartitionedCookiesAfterTimeElapsed)2464 TEST_F(CookieMonsterTest, DeleteExpiredPartitionedCookiesAfterTimeElapsed) {
2465 auto cm = std::make_unique<CookieMonster>(
2466 /*store=*/nullptr, net::NetLog::Get());
2467 auto cookie_partition_key =
2468 CookiePartitionKey::FromURLForTesting(GURL("https://toplevelsite.com"));
2469
2470 EXPECT_TRUE(SetCookie(cm.get(), https_www_bar_.url(),
2471 "__Host-A=B; secure; path=/; partitioned",
2472 cookie_partition_key));
2473 // Set a cookie with a Max-Age. Since we only parse integers for this
2474 // attribute, 1 second is the minimum allowable time.
2475 EXPECT_TRUE(SetCookie(cm.get(), https_www_bar_.url(),
2476 "__Host-C=D; secure; path=/; partitioned; max-age=1",
2477 cookie_partition_key));
2478
2479 CookieList cookies =
2480 GetAllCookiesForURL(cm.get(), https_www_bar_.url(),
2481 CookiePartitionKeyCollection(cookie_partition_key));
2482 EXPECT_EQ(2u, cookies.size());
2483
2484 // Sleep for entire Max-Age of the second cookie.
2485 base::PlatformThread::Sleep(base::Seconds(1));
2486
2487 cookies =
2488 GetAllCookiesForURL(cm.get(), https_www_bar_.url(),
2489 CookiePartitionKeyCollection(cookie_partition_key));
2490 EXPECT_EQ(1u, cookies.size());
2491 EXPECT_EQ("__Host-A", cookies[0].Name());
2492 }
2493
TEST_F(CookieMonsterTest,DeleteExpiredAfterTimeElapsed_GetAllCookies)2494 TEST_F(CookieMonsterTest, DeleteExpiredAfterTimeElapsed_GetAllCookies) {
2495 auto cm = std::make_unique<CookieMonster>(
2496 /*store=*/nullptr, net::NetLog::Get());
2497
2498 EXPECT_TRUE(SetCookie(cm.get(), https_www_bar_.url(),
2499 "__Host-A=B; secure; path=/",
2500 /*cookie_partition_key=*/std::nullopt));
2501 // Set a cookie with a Max-Age. Since we only parse integers for this
2502 // attribute, 1 second is the minimum allowable time.
2503 EXPECT_TRUE(SetCookie(cm.get(), https_www_bar_.url(),
2504 "__Host-C=D; secure; path=/; max-age=1",
2505 /*cookie_partition_key=*/std::nullopt));
2506
2507 GetAllCookiesCallback get_cookies_callback1;
2508 cm->GetAllCookiesAsync(get_cookies_callback1.MakeCallback());
2509 get_cookies_callback1.WaitUntilDone();
2510 ASSERT_EQ(2u, get_cookies_callback1.cookies().size());
2511
2512 // Sleep for entire Max-Age of the second cookie.
2513 base::PlatformThread::Sleep(base::Seconds(1));
2514
2515 GetAllCookiesCallback get_cookies_callback2;
2516 cm->GetAllCookiesAsync(get_cookies_callback2.MakeCallback());
2517 get_cookies_callback2.WaitUntilDone();
2518
2519 ASSERT_EQ(1u, get_cookies_callback2.cookies().size());
2520 EXPECT_EQ("__Host-A", get_cookies_callback2.cookies()[0].Name());
2521 }
2522
TEST_F(CookieMonsterTest,DeleteExpiredPartitionedCookiesAfterTimeElapsed_GetAllCookies)2523 TEST_F(CookieMonsterTest,
2524 DeleteExpiredPartitionedCookiesAfterTimeElapsed_GetAllCookies) {
2525 auto cm = std::make_unique<CookieMonster>(
2526 /*store=*/nullptr, net::NetLog::Get());
2527 auto cookie_partition_key =
2528 CookiePartitionKey::FromURLForTesting(GURL("https://toplevelsite.com"));
2529
2530 EXPECT_TRUE(SetCookie(cm.get(), https_www_bar_.url(),
2531 "__Host-A=B; secure; path=/; partitioned",
2532 cookie_partition_key));
2533 // Set a cookie with a Max-Age. Since we only parse integers for this
2534 // attribute, 1 second is the minimum allowable time.
2535 EXPECT_TRUE(SetCookie(cm.get(), https_www_bar_.url(),
2536 "__Host-C=D; secure; path=/; max-age=1; partitioned",
2537 cookie_partition_key));
2538
2539 GetAllCookiesCallback get_cookies_callback1;
2540 cm->GetAllCookiesAsync(get_cookies_callback1.MakeCallback());
2541 get_cookies_callback1.WaitUntilDone();
2542 ASSERT_EQ(2u, get_cookies_callback1.cookies().size());
2543
2544 // Sleep for entire Max-Age of the second cookie.
2545 base::PlatformThread::Sleep(base::Seconds(1));
2546
2547 GetAllCookiesCallback get_cookies_callback2;
2548 cm->GetAllCookiesAsync(get_cookies_callback2.MakeCallback());
2549 get_cookies_callback2.WaitUntilDone();
2550
2551 ASSERT_EQ(1u, get_cookies_callback2.cookies().size());
2552 EXPECT_EQ("__Host-A", get_cookies_callback2.cookies()[0].Name());
2553 }
2554
TEST_F(CookieMonsterTest,DeletePartitionedCookie)2555 TEST_F(CookieMonsterTest, DeletePartitionedCookie) {
2556 auto cm = std::make_unique<CookieMonster>(
2557 /*store=*/nullptr, net::NetLog::Get());
2558 auto cookie_partition_key =
2559 CookiePartitionKey::FromURLForTesting(GURL("https://toplevelsite.com"));
2560
2561 EXPECT_TRUE(SetCookie(cm.get(), https_www_bar_.url(),
2562 "__Host-A=B; secure; path=/; partitioned",
2563 cookie_partition_key));
2564 // Set another partitioned and an unpartitioned cookie and make sure they are
2565 // unaffected.
2566 EXPECT_TRUE(SetCookie(cm.get(), https_www_bar_.url(),
2567 "__Host-C=D; secure; path=/; partitioned",
2568 cookie_partition_key));
2569 EXPECT_TRUE(SetCookie(cm.get(), https_www_bar_.url(),
2570 "__Host-E=F; secure; path=/", std::nullopt));
2571
2572 auto cookie = CanonicalCookie::CreateForTesting(
2573 https_www_bar_.url(), "__Host-A=B; secure; path=/; partitioned",
2574 /*creation_time=*/Time::Now(), /*server_time=*/std::nullopt,
2575 cookie_partition_key);
2576 ASSERT_TRUE(cookie);
2577
2578 ResultSavingCookieCallback<unsigned int> delete_callback;
2579 cm->DeleteCanonicalCookieAsync(*cookie, delete_callback.MakeCallback());
2580 delete_callback.WaitUntilDone();
2581
2582 CookieList cookies =
2583 GetAllCookiesForURL(cm.get(), https_www_bar_.url(),
2584 CookiePartitionKeyCollection(cookie_partition_key));
2585 EXPECT_EQ(2u, cookies.size());
2586 EXPECT_EQ(cookies[0].Name(), "__Host-C");
2587 EXPECT_EQ(cookies[1].Name(), "__Host-E");
2588 }
2589
2590 // Tests importing from a persistent cookie store that contains duplicate
2591 // equivalent cookies. This situation should be handled by removing the
2592 // duplicate cookie (both from the in-memory cache, and from the backing store).
2593 //
2594 // This is a regression test for: http://crbug.com/17855.
TEST_F(CookieMonsterTest,DontImportDuplicateCookies)2595 TEST_F(CookieMonsterTest, DontImportDuplicateCookies) {
2596 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
2597
2598 // We will fill some initial cookies into the PersistentCookieStore,
2599 // to simulate a database with 4 duplicates. Note that we need to
2600 // be careful not to have any duplicate creation times at all (as it's a
2601 // violation of a CookieMonster invariant) even if Time::Now() doesn't
2602 // move between calls.
2603 std::vector<std::unique_ptr<CanonicalCookie>> initial_cookies;
2604
2605 // Insert 4 cookies with name "X" on path "/", with varying creation
2606 // dates. We expect only the most recent one to be preserved following
2607 // the import.
2608
2609 AddCookieToList(GURL("http://www.foo.com"),
2610 "X=1; path=/" + FutureCookieExpirationString(),
2611 Time::Now() + base::Days(3), &initial_cookies);
2612
2613 AddCookieToList(GURL("http://www.foo.com"),
2614 "X=2; path=/" + FutureCookieExpirationString(),
2615 Time::Now() + base::Days(1), &initial_cookies);
2616
2617 // ===> This one is the WINNER (biggest creation time). <====
2618 AddCookieToList(GURL("http://www.foo.com"),
2619 "X=3; path=/" + FutureCookieExpirationString(),
2620 Time::Now() + base::Days(4), &initial_cookies);
2621
2622 AddCookieToList(GURL("http://www.foo.com"),
2623 "X=4; path=/" + FutureCookieExpirationString(), Time::Now(),
2624 &initial_cookies);
2625
2626 // Insert 2 cookies with name "X" on path "/2", with varying creation
2627 // dates. We expect only the most recent one to be preserved the import.
2628
2629 // ===> This one is the WINNER (biggest creation time). <====
2630 AddCookieToList(GURL("http://www.foo.com"),
2631 "X=a1; path=/2" + FutureCookieExpirationString(),
2632 Time::Now() + base::Days(9), &initial_cookies);
2633
2634 AddCookieToList(GURL("http://www.foo.com"),
2635 "X=a2; path=/2" + FutureCookieExpirationString(),
2636 Time::Now() + base::Days(2), &initial_cookies);
2637
2638 // Insert 1 cookie with name "Y" on path "/".
2639 AddCookieToList(GURL("http://www.foo.com"),
2640 "Y=a; path=/" + FutureCookieExpirationString(),
2641 Time::Now() + base::Days(10), &initial_cookies);
2642
2643 // Inject our initial cookies into the mock PersistentCookieStore.
2644 store->SetLoadExpectation(true, std::move(initial_cookies));
2645
2646 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
2647
2648 // Verify that duplicates were not imported for path "/".
2649 // (If this had failed, GetCookies() would have also returned X=1, X=2, X=4).
2650 EXPECT_EQ("X=3; Y=a", GetCookies(cm.get(), GURL("http://www.foo.com/")));
2651
2652 // Verify that same-named cookie on a different path ("/x2") didn't get
2653 // messed up.
2654 EXPECT_EQ("X=a1; X=3; Y=a",
2655 GetCookies(cm.get(), GURL("http://www.foo.com/2/x")));
2656
2657 // Verify that the PersistentCookieStore was told to kill its 4 duplicates.
2658 ASSERT_EQ(4u, store->commands().size());
2659 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[0].type);
2660 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
2661 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[2].type);
2662 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type);
2663 }
2664
TEST_F(CookieMonsterTest,DontImportDuplicateCookies_PartitionedCookies)2665 TEST_F(CookieMonsterTest, DontImportDuplicateCookies_PartitionedCookies) {
2666 std::vector<std::unique_ptr<CanonicalCookie>> initial_cookies;
2667
2668 auto cookie_partition_key =
2669 CookiePartitionKey::FromURLForTesting(GURL("https://www.foo.com"));
2670 GURL cookie_url("https://www.bar.com");
2671
2672 // Insert 3 partitioned cookies with same name, partition key, and path.
2673
2674 // ===> This one is the WINNER (biggest creation time). <====
2675 auto cc = CanonicalCookie::CreateForTesting(
2676 cookie_url, "__Host-Z=a; Secure; Path=/; Partitioned; Max-Age=3456000",
2677 Time::Now() + base::Days(2), std::nullopt, cookie_partition_key);
2678 initial_cookies.push_back(std::move(cc));
2679
2680 cc = CanonicalCookie::CreateForTesting(
2681 cookie_url, "__Host-Z=b; Secure; Path=/; Partitioned; Max-Age=3456000",
2682 Time::Now(), std::nullopt, cookie_partition_key);
2683 initial_cookies.push_back(std::move(cc));
2684
2685 cc = CanonicalCookie::CreateForTesting(
2686 cookie_url, "__Host-Z=c; Secure; Path=/; Partitioned; Max-Age=3456000",
2687 Time::Now() + base::Days(1), std::nullopt, cookie_partition_key);
2688 initial_cookies.push_back(std::move(cc));
2689
2690 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
2691 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
2692
2693 store->SetLoadExpectation(true, std::move(initial_cookies));
2694
2695 EXPECT_EQ("__Host-Z=a",
2696 GetCookies(cm.get(), GURL("https://www.bar.com/"),
2697 CookiePartitionKeyCollection(cookie_partition_key)));
2698
2699 // Verify that the PersistentCookieStore was told to kill the 2
2700 // duplicates.
2701 ASSERT_EQ(2u, store->commands().size());
2702 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[0].type);
2703 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
2704 }
2705
2706 // Tests importing from a persistent cookie store that contains cookies
2707 // with duplicate creation times. This is OK now, but it still interacts
2708 // with the de-duplication algorithm.
2709 //
2710 // This is a regression test for: http://crbug.com/43188.
TEST_F(CookieMonsterTest,ImportDuplicateCreationTimes)2711 TEST_F(CookieMonsterTest, ImportDuplicateCreationTimes) {
2712 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
2713
2714 Time now(Time::Now());
2715 Time earlier(now - base::Days(1));
2716
2717 // Insert 8 cookies, four with the current time as creation times, and
2718 // four with the earlier time as creation times. We should only get
2719 // two cookies remaining, but which two (other than that there should
2720 // be one from each set) will be random.
2721 std::vector<std::unique_ptr<CanonicalCookie>> initial_cookies;
2722 AddCookieToList(GURL("http://www.foo.com"), "X=1; path=/", now,
2723 &initial_cookies);
2724 AddCookieToList(GURL("http://www.foo.com"), "X=2; path=/", now,
2725 &initial_cookies);
2726 AddCookieToList(GURL("http://www.foo.com"), "X=3; path=/", now,
2727 &initial_cookies);
2728 AddCookieToList(GURL("http://www.foo.com"), "X=4; path=/", now,
2729 &initial_cookies);
2730
2731 AddCookieToList(GURL("http://www.foo.com"), "Y=1; path=/", earlier,
2732 &initial_cookies);
2733 AddCookieToList(GURL("http://www.foo.com"), "Y=2; path=/", earlier,
2734 &initial_cookies);
2735 AddCookieToList(GURL("http://www.foo.com"), "Y=3; path=/", earlier,
2736 &initial_cookies);
2737 AddCookieToList(GURL("http://www.foo.com"), "Y=4; path=/", earlier,
2738 &initial_cookies);
2739
2740 // Inject our initial cookies into the mock PersistentCookieStore.
2741 store->SetLoadExpectation(true, std::move(initial_cookies));
2742
2743 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
2744
2745 CookieList list(GetAllCookies(cm.get()));
2746 EXPECT_EQ(2U, list.size());
2747 // Confirm that we have one of each.
2748 std::string name1(list[0].Name());
2749 std::string name2(list[1].Name());
2750 EXPECT_TRUE(name1 == "X" || name2 == "X");
2751 EXPECT_TRUE(name1 == "Y" || name2 == "Y");
2752 EXPECT_NE(name1, name2);
2753 }
2754
TEST_F(CookieMonsterTest,ImportDuplicateCreationTimes_PartitionedCookies)2755 TEST_F(CookieMonsterTest, ImportDuplicateCreationTimes_PartitionedCookies) {
2756 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
2757
2758 Time now(Time::Now());
2759 Time earlier(now - base::Days(1));
2760
2761 GURL cookie_url("https://www.foo.com");
2762 auto cookie_partition_key =
2763 CookiePartitionKey::FromURLForTesting(GURL("https://www.bar.com"));
2764
2765 // Insert 6 cookies, four with the current time as creation times, and
2766 // four with the earlier time as creation times. We should only get
2767 // two cookies remaining, but which two (other than that there should
2768 // be one from each set) will be random.
2769
2770 std::vector<std::unique_ptr<CanonicalCookie>> initial_cookies;
2771 auto cc = CanonicalCookie::CreateForTesting(
2772 cookie_url, "__Host-X=1; Secure; Path=/; Partitioned; Max-Age=3456000",
2773 now, std::nullopt, cookie_partition_key);
2774 initial_cookies.push_back(std::move(cc));
2775 cc = CanonicalCookie::CreateForTesting(
2776 cookie_url, "__Host-X=2; Secure; Path=/; Partitioned; Max-Age=3456000",
2777 now, std::nullopt, cookie_partition_key);
2778 initial_cookies.push_back(std::move(cc));
2779 cc = CanonicalCookie::CreateForTesting(
2780 cookie_url, "__Host-X=3; Secure; Path=/; Partitioned; Max-Age=3456000",
2781 now, std::nullopt, cookie_partition_key);
2782 initial_cookies.push_back(std::move(cc));
2783
2784 cc = CanonicalCookie::CreateForTesting(
2785 cookie_url, "__Host-Y=1; Secure; Path=/; Partitioned; Max-Age=3456000",
2786 earlier, std::nullopt, cookie_partition_key);
2787 initial_cookies.push_back(std::move(cc));
2788 cc = CanonicalCookie::CreateForTesting(
2789 cookie_url, "__Host-Y=2; Secure; Path=/; Partitioned; Max-Age=3456000",
2790 earlier, std::nullopt, cookie_partition_key);
2791 initial_cookies.push_back(std::move(cc));
2792 cc = CanonicalCookie::CreateForTesting(
2793 cookie_url, "__Host-Y=3; Secure; Path=/; Partitioned; Max-Age=3456000",
2794 earlier, std::nullopt, cookie_partition_key);
2795 initial_cookies.push_back(std::move(cc));
2796
2797 // Inject our initial cookies into the mock PersistentCookieStore.
2798 store->SetLoadExpectation(true, std::move(initial_cookies));
2799
2800 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
2801
2802 CookieList list(GetAllCookies(cm.get()));
2803 EXPECT_EQ(2U, list.size());
2804 // Confirm that we have one of each.
2805 std::string name1(list[0].Name());
2806 std::string name2(list[1].Name());
2807 EXPECT_TRUE(name1 == "__Host-X" || name2 == "__Host-X");
2808 EXPECT_TRUE(name1 == "__Host-Y" || name2 == "__Host-Y");
2809 EXPECT_NE(name1, name2);
2810 }
2811
TEST_F(CookieMonsterTest,PredicateSeesAllCookies)2812 TEST_F(CookieMonsterTest, PredicateSeesAllCookies) {
2813 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
2814
2815 const base::Time now = PopulateCmForPredicateCheck(cm.get());
2816 // We test that we can see all cookies with |delete_info|. This includes
2817 // host, http_only, host secure, and all domain cookies.
2818 CookieDeletionInfo delete_info(base::Time(), now);
2819 delete_info.value_for_testing = "A";
2820
2821 EXPECT_EQ(8u, DeleteAllMatchingInfo(cm.get(), std::move(delete_info)));
2822
2823 EXPECT_EQ("dom_2=B; dom_3=C; host_3=C",
2824 GetCookies(cm.get(), GURL(kTopLevelDomainPlus3)));
2825 EXPECT_EQ("dom_2=B; host_2=B; sec_host=B",
2826 GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure)));
2827 EXPECT_EQ("", GetCookies(cm.get(), GURL(kTopLevelDomainPlus1)));
2828 EXPECT_EQ("dom_path_2=B; host_path_2=B; dom_2=B; host_2=B; sec_host=B",
2829 GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure +
2830 std::string("/dir1/dir2/xxx"))));
2831 EXPECT_EQ("dom_2=B; host_2=B; sec_host=B; __Host-pc_2=B",
2832 GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure),
2833 CookiePartitionKeyCollection(
2834 CookiePartitionKey::FromURLForTesting(
2835 GURL(kTopLevelDomainPlus1)))));
2836 }
2837
2838 // Mainly a test of GetEffectiveDomain, or more specifically, of the
2839 // expected behavior of GetEffectiveDomain within the CookieMonster.
TEST_F(CookieMonsterTest,GetKey)2840 TEST_F(CookieMonsterTest, GetKey) {
2841 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
2842
2843 // This test is really only interesting if GetKey() actually does something.
2844 EXPECT_EQ("foo.com", cm->GetKey("www.foo.com"));
2845 EXPECT_EQ("google.izzie", cm->GetKey("www.google.izzie"));
2846 EXPECT_EQ("google.izzie", cm->GetKey(".google.izzie"));
2847 EXPECT_EQ("bbc.co.uk", cm->GetKey("bbc.co.uk"));
2848 EXPECT_EQ("bbc.co.uk", cm->GetKey("a.b.c.d.bbc.co.uk"));
2849 EXPECT_EQ("apple.com", cm->GetKey("a.b.c.d.apple.com"));
2850 EXPECT_EQ("apple.izzie", cm->GetKey("a.b.c.d.apple.izzie"));
2851
2852 // Cases where the effective domain is null, so we use the host
2853 // as the key.
2854 EXPECT_EQ("co.uk", cm->GetKey("co.uk"));
2855 const std::string extension_name("iehocdgbbocmkdidlbnnfbmbinnahbae");
2856 EXPECT_EQ(extension_name, cm->GetKey(extension_name));
2857 EXPECT_EQ("com", cm->GetKey("com"));
2858 EXPECT_EQ("hostalias", cm->GetKey("hostalias"));
2859 EXPECT_EQ("localhost", cm->GetKey("localhost"));
2860 }
2861
2862 // Test that cookies transfer from/to the backing store correctly.
2863 // TODO(crbug.com/1225444): Include partitioned cookies in this test when we
2864 // start saving them in the persistent store.
TEST_F(CookieMonsterTest,BackingStoreCommunication)2865 TEST_F(CookieMonsterTest, BackingStoreCommunication) {
2866 // Store details for cookies transforming through the backing store interface.
2867
2868 base::Time current(base::Time::Now());
2869 auto store = base::MakeRefCounted<MockSimplePersistentCookieStore>();
2870 base::Time expires(base::Time::Now() + base::Seconds(100));
2871
2872 const CookiesInputInfo input_info[] = {
2873 {GURL("https://a.b.foo.com"), "a", "1", "a.b.foo.com", "/path/to/cookie",
2874 expires, true /* secure */, false, CookieSameSite::NO_RESTRICTION,
2875 COOKIE_PRIORITY_DEFAULT},
2876 {GURL("https://www.foo.com"), "b", "2", ".foo.com", "/path/from/cookie",
2877 expires + base::Seconds(10), true, true, CookieSameSite::NO_RESTRICTION,
2878 COOKIE_PRIORITY_DEFAULT},
2879 {GURL("https://foo.com"), "c", "3", "foo.com", "/another/path/to/cookie",
2880 base::Time::Now() + base::Seconds(100), false, false,
2881 CookieSameSite::STRICT_MODE, COOKIE_PRIORITY_DEFAULT}};
2882 const int INPUT_DELETE = 1;
2883
2884 // Create new cookies and flush them to the store.
2885 {
2886 auto cmout =
2887 std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
2888 for (const auto& cookie : input_info) {
2889 EXPECT_TRUE(SetCanonicalCookie(
2890 cmout.get(),
2891 CanonicalCookie::CreateUnsafeCookieForTesting(
2892 cookie.name, cookie.value, cookie.domain, cookie.path,
2893 base::Time(), cookie.expiration_time, base::Time(), base::Time(),
2894 cookie.secure, cookie.http_only, cookie.same_site,
2895 cookie.priority),
2896 cookie.url, true /*modify_httponly*/));
2897 }
2898
2899 EXPECT_TRUE(FindAndDeleteCookie(cmout.get(),
2900 input_info[INPUT_DELETE].domain,
2901 input_info[INPUT_DELETE].name));
2902 }
2903
2904 // Create a new cookie monster and make sure that everything is correct
2905 {
2906 auto cmin =
2907 std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
2908 CookieList cookies(GetAllCookies(cmin.get()));
2909 ASSERT_EQ(2u, cookies.size());
2910 // Ordering is path length, then creation time. So second cookie
2911 // will come first, and we need to swap them.
2912 std::swap(cookies[0], cookies[1]);
2913 for (int output_index = 0; output_index < 2; output_index++) {
2914 int input_index = output_index * 2;
2915 const CookiesInputInfo* input = &input_info[input_index];
2916 const CanonicalCookie* output = &cookies[output_index];
2917
2918 EXPECT_EQ(input->name, output->Name());
2919 EXPECT_EQ(input->value, output->Value());
2920 EXPECT_EQ(input->url.host(), output->Domain());
2921 EXPECT_EQ(input->path, output->Path());
2922 EXPECT_LE(current.ToInternalValue(),
2923 output->CreationDate().ToInternalValue());
2924 EXPECT_EQ(input->secure, output->SecureAttribute());
2925 EXPECT_EQ(input->http_only, output->IsHttpOnly());
2926 EXPECT_EQ(input->same_site, output->SameSite());
2927 EXPECT_TRUE(output->IsPersistent());
2928 EXPECT_EQ(input->expiration_time.ToInternalValue(),
2929 output->ExpiryDate().ToInternalValue());
2930 }
2931 }
2932 }
2933
TEST_F(CookieMonsterTest,RestoreDifferentCookieSameCreationTime)2934 TEST_F(CookieMonsterTest, RestoreDifferentCookieSameCreationTime) {
2935 // Test that we can restore different cookies with duplicate creation times.
2936 base::Time current(base::Time::Now());
2937 scoped_refptr<MockPersistentCookieStore> store =
2938 base::MakeRefCounted<MockPersistentCookieStore>();
2939
2940 {
2941 CookieMonster cmout(store.get(), net::NetLog::Get());
2942 GURL url("http://www.example.com/");
2943 EXPECT_TRUE(
2944 SetCookieWithCreationTime(&cmout, url, "A=1; max-age=600", current));
2945 EXPECT_TRUE(
2946 SetCookieWithCreationTime(&cmout, url, "B=2; max-age=600", current));
2947 }
2948
2949 // Play back the cookies into store 2.
2950 scoped_refptr<MockPersistentCookieStore> store2 =
2951 base::MakeRefCounted<MockPersistentCookieStore>();
2952 std::vector<std::unique_ptr<CanonicalCookie>> load_expectation;
2953 EXPECT_EQ(2u, store->commands().size());
2954 for (const CookieStoreCommand& command : store->commands()) {
2955 ASSERT_EQ(command.type, CookieStoreCommand::ADD);
2956 load_expectation.push_back(
2957 std::make_unique<CanonicalCookie>(command.cookie));
2958 }
2959 store2->SetLoadExpectation(true, std::move(load_expectation));
2960
2961 // Now read them in. Should get two cookies, not one.
2962 {
2963 CookieMonster cmin(store2.get(), net::NetLog::Get());
2964 CookieList cookies(GetAllCookies(&cmin));
2965 ASSERT_EQ(2u, cookies.size());
2966 }
2967 }
2968
TEST_F(CookieMonsterTest,CookieListOrdering)2969 TEST_F(CookieMonsterTest, CookieListOrdering) {
2970 // Put a random set of cookies into a monster and make sure
2971 // they're returned in the right order.
2972 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
2973
2974 EXPECT_TRUE(
2975 SetCookie(cm.get(), GURL("http://d.c.b.a.foo.com/aa/x.html"), "c=1"));
2976 EXPECT_TRUE(SetCookie(cm.get(), GURL("http://b.a.foo.com/aa/bb/cc/x.html"),
2977 "d=1; domain=b.a.foo.com"));
2978 EXPECT_TRUE(SetCookie(cm.get(), GURL("http://b.a.foo.com/aa/bb/cc/x.html"),
2979 "a=4; domain=b.a.foo.com"));
2980 EXPECT_TRUE(SetCookie(cm.get(), GURL("http://c.b.a.foo.com/aa/bb/cc/x.html"),
2981 "e=1; domain=c.b.a.foo.com"));
2982 EXPECT_TRUE(
2983 SetCookie(cm.get(), GURL("http://d.c.b.a.foo.com/aa/bb/x.html"), "b=1"));
2984 EXPECT_TRUE(SetCookie(cm.get(), GURL("http://news.bbc.co.uk/midpath/x.html"),
2985 "g=10"));
2986 {
2987 unsigned int i = 0;
2988 CookieList cookies(GetAllCookiesForURL(
2989 cm.get(), GURL("http://d.c.b.a.foo.com/aa/bb/cc/dd")));
2990 ASSERT_EQ(5u, cookies.size());
2991 EXPECT_EQ("d", cookies[i++].Name());
2992 EXPECT_EQ("a", cookies[i++].Name());
2993 EXPECT_EQ("e", cookies[i++].Name());
2994 EXPECT_EQ("b", cookies[i++].Name());
2995 EXPECT_EQ("c", cookies[i++].Name());
2996 }
2997
2998 {
2999 unsigned int i = 0;
3000 CookieList cookies(GetAllCookies(cm.get()));
3001 ASSERT_EQ(6u, cookies.size());
3002 EXPECT_EQ("d", cookies[i++].Name());
3003 EXPECT_EQ("a", cookies[i++].Name());
3004 EXPECT_EQ("e", cookies[i++].Name());
3005 EXPECT_EQ("g", cookies[i++].Name());
3006 EXPECT_EQ("b", cookies[i++].Name());
3007 EXPECT_EQ("c", cookies[i++].Name());
3008 }
3009 }
3010
3011 // These garbage collection tests and CookieMonstertest.TestGCTimes (in
3012 // cookie_monster_perftest.cc) are somewhat complementary. These tests probe
3013 // for whether garbage collection always happens when it should (i.e. that we
3014 // actually get rid of cookies when we should). The perftest is probing for
3015 // whether garbage collection happens when it shouldn't. See comments
3016 // before that test for more details.
3017
3018 // Check to make sure that a whole lot of recent cookies doesn't get rid of
3019 // anything after garbage collection is checked for.
TEST_F(CookieMonsterTest,GarbageCollectionKeepsRecentEphemeralCookies)3020 TEST_F(CookieMonsterTest, GarbageCollectionKeepsRecentEphemeralCookies) {
3021 std::unique_ptr<CookieMonster> cm(
3022 CreateMonsterForGC(CookieMonster::kMaxCookies * 2 /* num_cookies */));
3023 EXPECT_EQ(CookieMonster::kMaxCookies * 2, GetAllCookies(cm.get()).size());
3024 // Will trigger GC.
3025 SetCookie(cm.get(), GURL("http://newdomain.com"), "b=2");
3026 EXPECT_EQ(CookieMonster::kMaxCookies * 2 + 1, GetAllCookies(cm.get()).size());
3027 }
3028
3029 // A whole lot of recent cookies; GC shouldn't happen.
TEST_F(CookieMonsterTest,GarbageCollectionKeepsRecentCookies)3030 TEST_F(CookieMonsterTest, GarbageCollectionKeepsRecentCookies) {
3031 std::unique_ptr<CookieMonster> cm = CreateMonsterFromStoreForGC(
3032 CookieMonster::kMaxCookies * 2 /* num_cookies */, 0 /* num_old_cookies */,
3033 0, 0, CookieMonster::kSafeFromGlobalPurgeDays * 2);
3034 EXPECT_EQ(CookieMonster::kMaxCookies * 2, GetAllCookies(cm.get()).size());
3035 // Will trigger GC.
3036 SetCookie(cm.get(), GURL("http://newdomain.com"), "b=2");
3037 EXPECT_EQ(CookieMonster::kMaxCookies * 2 + 1, GetAllCookies(cm.get()).size());
3038 }
3039
3040 // Test case where there are more than kMaxCookies - kPurgeCookies recent
3041 // cookies. All old cookies should be garbage collected, all recent cookies
3042 // kept.
TEST_F(CookieMonsterTest,GarbageCollectionKeepsOnlyRecentCookies)3043 TEST_F(CookieMonsterTest, GarbageCollectionKeepsOnlyRecentCookies) {
3044 std::unique_ptr<CookieMonster> cm = CreateMonsterFromStoreForGC(
3045 CookieMonster::kMaxCookies * 2 /* num_cookies */,
3046 CookieMonster::kMaxCookies / 2 /* num_old_cookies */, 0, 0,
3047 CookieMonster::kSafeFromGlobalPurgeDays * 2);
3048 EXPECT_EQ(CookieMonster::kMaxCookies * 2, GetAllCookies(cm.get()).size());
3049 // Will trigger GC.
3050 SetCookie(cm.get(), GURL("http://newdomain.com"), "b=2");
3051 EXPECT_EQ(CookieMonster::kMaxCookies * 2 - CookieMonster::kMaxCookies / 2 + 1,
3052 GetAllCookies(cm.get()).size());
3053 }
3054
3055 // Test case where there are exactly kMaxCookies - kPurgeCookies recent cookies.
3056 // All old cookies should be deleted.
TEST_F(CookieMonsterTest,GarbageCollectionExactlyAllOldCookiesDeleted)3057 TEST_F(CookieMonsterTest, GarbageCollectionExactlyAllOldCookiesDeleted) {
3058 std::unique_ptr<CookieMonster> cm = CreateMonsterFromStoreForGC(
3059 CookieMonster::kMaxCookies * 2 /* num_cookies */,
3060 CookieMonster::kMaxCookies + CookieMonster::kPurgeCookies +
3061 1 /* num_old_cookies */,
3062 0, 0, CookieMonster::kSafeFromGlobalPurgeDays * 2);
3063 EXPECT_EQ(CookieMonster::kMaxCookies * 2, GetAllCookies(cm.get()).size());
3064 // Will trigger GC.
3065 SetCookie(cm.get(), GURL("http://newdomain.com"), "b=2");
3066 EXPECT_EQ(CookieMonster::kMaxCookies - CookieMonster::kPurgeCookies,
3067 GetAllCookies(cm.get()).size());
3068 }
3069
3070 // Test case where there are less than kMaxCookies - kPurgeCookies recent
3071 // cookies. Enough old cookies should be deleted to reach kMaxCookies -
3072 // kPurgeCookies total cookies, but no more. Some old cookies should be kept.
TEST_F(CookieMonsterTest,GarbageCollectionTriggers5)3073 TEST_F(CookieMonsterTest, GarbageCollectionTriggers5) {
3074 std::unique_ptr<CookieMonster> cm = CreateMonsterFromStoreForGC(
3075 CookieMonster::kMaxCookies * 2 /* num_cookies */,
3076 CookieMonster::kMaxCookies * 3 / 2 /* num_old_cookies */, 0, 0,
3077 CookieMonster::kSafeFromGlobalPurgeDays * 2);
3078 EXPECT_EQ(CookieMonster::kMaxCookies * 2, GetAllCookies(cm.get()).size());
3079 // Will trigger GC.
3080 SetCookie(cm.get(), GURL("http://newdomain.com"), "b=2");
3081 EXPECT_EQ(CookieMonster::kMaxCookies - CookieMonster::kPurgeCookies,
3082 GetAllCookies(cm.get()).size());
3083 }
3084
3085 // Tests garbage collection when there are only secure cookies.
3086 // See https://crbug/730000
TEST_F(CookieMonsterTest,GarbageCollectWithSecureCookiesOnly)3087 TEST_F(CookieMonsterTest, GarbageCollectWithSecureCookiesOnly) {
3088 // Create a CookieMonster at its cookie limit. A bit confusing, but the second
3089 // number is a subset of the first number.
3090 std::unique_ptr<CookieMonster> cm = CreateMonsterFromStoreForGC(
3091 CookieMonster::kMaxCookies /* num_secure_cookies */,
3092 CookieMonster::kMaxCookies /* num_old_secure_cookies */,
3093 0 /* num_non_secure_cookies */, 0 /* num_old_non_secure_cookies */,
3094 CookieMonster::kSafeFromGlobalPurgeDays * 2 /* days_old */);
3095 EXPECT_EQ(CookieMonster::kMaxCookies, GetAllCookies(cm.get()).size());
3096
3097 // Trigger purge with a secure cookie (So there are still no insecure
3098 // cookies).
3099 SetCookie(cm.get(), GURL("https://newdomain.com"), "b=2; Secure");
3100 EXPECT_EQ(CookieMonster::kMaxCookies - CookieMonster::kPurgeCookies,
3101 GetAllCookies(cm.get()).size());
3102 }
3103
3104 // Tests that if the main load event happens before the loaded event for a
3105 // particular key, the tasks for that key run first.
TEST_F(CookieMonsterTest,WhileLoadingLoadCompletesBeforeKeyLoadCompletes)3106 TEST_F(CookieMonsterTest, WhileLoadingLoadCompletesBeforeKeyLoadCompletes) {
3107 const GURL kUrl = GURL(kTopLevelDomainPlus1);
3108
3109 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
3110 store->set_store_load_commands(true);
3111 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
3112
3113 auto cookie =
3114 CanonicalCookie::CreateForTesting(kUrl, "a=b", base::Time::Now());
3115 ResultSavingCookieCallback<CookieAccessResult> set_cookie_callback;
3116 cm->SetCanonicalCookieAsync(std::move(cookie), kUrl,
3117 CookieOptions::MakeAllInclusive(),
3118 set_cookie_callback.MakeCallback());
3119
3120 GetAllCookiesCallback get_cookies_callback1;
3121 cm->GetAllCookiesAsync(get_cookies_callback1.MakeCallback());
3122
3123 // Two load events should have been queued.
3124 ASSERT_EQ(2u, store->commands().size());
3125 ASSERT_EQ(CookieStoreCommand::LOAD, store->commands()[0].type);
3126 ASSERT_EQ(CookieStoreCommand::LOAD_COOKIES_FOR_KEY,
3127 store->commands()[1].type);
3128
3129 // The main load completes first (With no cookies).
3130 store->TakeCallbackAt(0).Run(std::vector<std::unique_ptr<CanonicalCookie>>());
3131
3132 // The tasks should run in order, and the get should see the cookies.
3133
3134 set_cookie_callback.WaitUntilDone();
3135 EXPECT_TRUE(set_cookie_callback.result().status.IsInclude());
3136
3137 get_cookies_callback1.WaitUntilDone();
3138 EXPECT_EQ(1u, get_cookies_callback1.cookies().size());
3139
3140 // The loaded for key event completes late, with not cookies (Since they
3141 // were already loaded).
3142 store->TakeCallbackAt(1).Run(std::vector<std::unique_ptr<CanonicalCookie>>());
3143
3144 // The just set cookie should still be in the store.
3145 GetAllCookiesCallback get_cookies_callback2;
3146 cm->GetAllCookiesAsync(get_cookies_callback2.MakeCallback());
3147 get_cookies_callback2.WaitUntilDone();
3148 EXPECT_EQ(1u, get_cookies_callback2.cookies().size());
3149 }
3150
3151 // Tests that case that DeleteAll is waiting for load to complete, and then a
3152 // get is queued. The get should wait to run until after all the cookies are
3153 // retrieved, and should return nothing, since all cookies were just deleted.
TEST_F(CookieMonsterTest,WhileLoadingDeleteAllGetForURL)3154 TEST_F(CookieMonsterTest, WhileLoadingDeleteAllGetForURL) {
3155 const GURL kUrl = GURL(kTopLevelDomainPlus1);
3156
3157 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
3158 store->set_store_load_commands(true);
3159 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
3160
3161 ResultSavingCookieCallback<uint32_t> delete_callback;
3162 cm->DeleteAllAsync(delete_callback.MakeCallback());
3163
3164 GetCookieListCallback get_cookie_list_callback;
3165 cm->GetCookieListWithOptionsAsync(kUrl, CookieOptions::MakeAllInclusive(),
3166 CookiePartitionKeyCollection(),
3167 get_cookie_list_callback.MakeCallback());
3168
3169 // Only the main load should have been queued.
3170 ASSERT_EQ(1u, store->commands().size());
3171 ASSERT_EQ(CookieStoreCommand::LOAD, store->commands()[0].type);
3172
3173 std::vector<std::unique_ptr<CanonicalCookie>> cookies;
3174 // When passed to the CookieMonster, it takes ownership of the pointed to
3175 // cookies.
3176 cookies.push_back(
3177 CanonicalCookie::CreateForTesting(kUrl, "a=b", base::Time::Now()));
3178 ASSERT_TRUE(cookies[0]);
3179 store->TakeCallbackAt(0).Run(std::move(cookies));
3180
3181 delete_callback.WaitUntilDone();
3182 EXPECT_EQ(1u, delete_callback.result());
3183
3184 get_cookie_list_callback.WaitUntilDone();
3185 EXPECT_EQ(0u, get_cookie_list_callback.cookies().size());
3186 }
3187
3188 // Tests that a set cookie call sandwiched between two get all cookies, all
3189 // before load completes, affects the first but not the second. The set should
3190 // also not trigger a LoadCookiesForKey (As that could complete only after the
3191 // main load for the store).
TEST_F(CookieMonsterTest,WhileLoadingGetAllSetGetAll)3192 TEST_F(CookieMonsterTest, WhileLoadingGetAllSetGetAll) {
3193 const GURL kUrl = GURL(kTopLevelDomainPlus1);
3194
3195 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
3196 store->set_store_load_commands(true);
3197 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
3198
3199 GetAllCookiesCallback get_cookies_callback1;
3200 cm->GetAllCookiesAsync(get_cookies_callback1.MakeCallback());
3201
3202 auto cookie =
3203 CanonicalCookie::CreateForTesting(kUrl, "a=b", base::Time::Now());
3204 ResultSavingCookieCallback<CookieAccessResult> set_cookie_callback;
3205 cm->SetCanonicalCookieAsync(std::move(cookie), kUrl,
3206 CookieOptions::MakeAllInclusive(),
3207 set_cookie_callback.MakeCallback());
3208
3209 GetAllCookiesCallback get_cookies_callback2;
3210 cm->GetAllCookiesAsync(get_cookies_callback2.MakeCallback());
3211
3212 // Only the main load should have been queued.
3213 ASSERT_EQ(1u, store->commands().size());
3214 ASSERT_EQ(CookieStoreCommand::LOAD, store->commands()[0].type);
3215
3216 // The load completes (With no cookies).
3217 store->TakeCallbackAt(0).Run(std::vector<std::unique_ptr<CanonicalCookie>>());
3218
3219 get_cookies_callback1.WaitUntilDone();
3220 EXPECT_EQ(0u, get_cookies_callback1.cookies().size());
3221
3222 set_cookie_callback.WaitUntilDone();
3223 EXPECT_TRUE(set_cookie_callback.result().status.IsInclude());
3224
3225 get_cookies_callback2.WaitUntilDone();
3226 EXPECT_EQ(1u, get_cookies_callback2.cookies().size());
3227 }
3228
3229 namespace {
3230
RunClosureOnAllCookiesReceived(base::OnceClosure closure,const CookieList & cookie_list)3231 void RunClosureOnAllCookiesReceived(base::OnceClosure closure,
3232 const CookieList& cookie_list) {
3233 std::move(closure).Run();
3234 }
3235
3236 } // namespace
3237
3238 // Tests that if a single cookie task is queued as a result of a task performed
3239 // on all cookies when loading completes, it will be run after any already
3240 // queued tasks.
TEST_F(CookieMonsterTest,CheckOrderOfCookieTaskQueueWhenLoadingCompletes)3241 TEST_F(CookieMonsterTest, CheckOrderOfCookieTaskQueueWhenLoadingCompletes) {
3242 const GURL kUrl = GURL(kTopLevelDomainPlus1);
3243
3244 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
3245 store->set_store_load_commands(true);
3246 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
3247
3248 // Get all cookies task that queues a task to set a cookie when executed.
3249 auto cookie =
3250 CanonicalCookie::CreateForTesting(kUrl, "a=b", base::Time::Now());
3251 ResultSavingCookieCallback<CookieAccessResult> set_cookie_callback;
3252 cm->GetAllCookiesAsync(base::BindOnce(
3253 &RunClosureOnAllCookiesReceived,
3254 base::BindOnce(&CookieStore::SetCanonicalCookieAsync,
3255 base::Unretained(cm.get()), std::move(cookie), kUrl,
3256 CookieOptions::MakeAllInclusive(),
3257 set_cookie_callback.MakeCallback(), std::nullopt)));
3258
3259 // Get cookie task. Queued before the delete task is executed, so should not
3260 // see the set cookie.
3261 GetAllCookiesCallback get_cookies_callback1;
3262 cm->GetAllCookiesAsync(get_cookies_callback1.MakeCallback());
3263
3264 // Only the main load should have been queued.
3265 ASSERT_EQ(1u, store->commands().size());
3266 ASSERT_EQ(CookieStoreCommand::LOAD, store->commands()[0].type);
3267
3268 // The load completes.
3269 store->TakeCallbackAt(0).Run(std::vector<std::unique_ptr<CanonicalCookie>>());
3270
3271 // The get cookies call should see no cookies set.
3272 get_cookies_callback1.WaitUntilDone();
3273 EXPECT_EQ(0u, get_cookies_callback1.cookies().size());
3274
3275 set_cookie_callback.WaitUntilDone();
3276 EXPECT_TRUE(set_cookie_callback.result().status.IsInclude());
3277
3278 // A subsequent get cookies call should see the new cookie.
3279 GetAllCookiesCallback get_cookies_callback2;
3280 cm->GetAllCookiesAsync(get_cookies_callback2.MakeCallback());
3281 get_cookies_callback2.WaitUntilDone();
3282 EXPECT_EQ(1u, get_cookies_callback2.cookies().size());
3283 }
3284
3285 // Test that FlushStore() is forwarded to the store and callbacks are posted.
TEST_F(CookieMonsterTest,FlushStore)3286 TEST_F(CookieMonsterTest, FlushStore) {
3287 auto counter = base::MakeRefCounted<CallbackCounter>();
3288 auto store = base::MakeRefCounted<FlushablePersistentStore>();
3289 auto cm = std::make_unique<CookieMonster>(store, net::NetLog::Get());
3290
3291 ASSERT_EQ(0, store->flush_count());
3292 ASSERT_EQ(0, counter->callback_count());
3293
3294 // Before initialization, FlushStore() should just run the callback.
3295 cm->FlushStore(base::BindOnce(&CallbackCounter::Callback, counter));
3296 base::RunLoop().RunUntilIdle();
3297
3298 ASSERT_EQ(0, store->flush_count());
3299 ASSERT_EQ(1, counter->callback_count());
3300
3301 // NULL callback is safe.
3302 cm->FlushStore(base::OnceClosure());
3303 base::RunLoop().RunUntilIdle();
3304
3305 ASSERT_EQ(0, store->flush_count());
3306 ASSERT_EQ(1, counter->callback_count());
3307
3308 // After initialization, FlushStore() should delegate to the store.
3309 GetAllCookies(cm.get()); // Force init.
3310 cm->FlushStore(base::BindOnce(&CallbackCounter::Callback, counter));
3311 base::RunLoop().RunUntilIdle();
3312
3313 ASSERT_EQ(1, store->flush_count());
3314 ASSERT_EQ(2, counter->callback_count());
3315
3316 // NULL callback is still safe.
3317 cm->FlushStore(base::DoNothing());
3318 base::RunLoop().RunUntilIdle();
3319
3320 ASSERT_EQ(2, store->flush_count());
3321 ASSERT_EQ(2, counter->callback_count());
3322
3323 // If there's no backing store, FlushStore() is always a safe no-op.
3324 cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
3325 GetAllCookies(cm.get()); // Force init.
3326 cm->FlushStore(base::DoNothing());
3327 base::RunLoop().RunUntilIdle();
3328
3329 ASSERT_EQ(2, counter->callback_count());
3330
3331 cm->FlushStore(base::BindOnce(&CallbackCounter::Callback, counter));
3332 base::RunLoop().RunUntilIdle();
3333
3334 ASSERT_EQ(3, counter->callback_count());
3335 }
3336
TEST_F(CookieMonsterTest,SetAllCookies)3337 TEST_F(CookieMonsterTest, SetAllCookies) {
3338 auto store = base::MakeRefCounted<FlushablePersistentStore>();
3339 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
3340 cm->SetPersistSessionCookies(true);
3341
3342 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "U=V; path=/"));
3343 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "W=X; path=/foo"));
3344 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "Y=Z; path=/"));
3345
3346 CookieList list;
3347 list.push_back(*CanonicalCookie::CreateUnsafeCookieForTesting(
3348 "A", "B", "." + http_www_foo_.url().host(), "/", base::Time::Now(),
3349 base::Time(), base::Time(), base::Time(), false, false,
3350 CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT));
3351 list.push_back(*CanonicalCookie::CreateUnsafeCookieForTesting(
3352 "C", "D", "." + http_www_foo_.url().host(), "/bar", base::Time::Now(),
3353 base::Time(), base::Time(), base::Time(), false, false,
3354 CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT));
3355 list.push_back(*CanonicalCookie::CreateUnsafeCookieForTesting(
3356 "W", "X", "." + http_www_foo_.url().host(), "/", base::Time::Now(),
3357 base::Time(), base::Time(), base::Time(), false, false,
3358 CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT));
3359 list.push_back(*CanonicalCookie::CreateUnsafeCookieForTesting(
3360 "__Host-Y", "Z", https_www_foo_.url().host(), "/", base::Time::Now(),
3361 base::Time(), base::Time(), base::Time(), true, false,
3362 CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
3363 CookiePartitionKey::FromURLForTesting(GURL("https://toplevelsite.com"))));
3364 // Expired cookie, should not be stored.
3365 list.push_back(*CanonicalCookie::CreateUnsafeCookieForTesting(
3366 "expired", "foobar", https_www_foo_.url().host(), "/",
3367 base::Time::Now() - base::Days(1), base::Time::Now() - base::Days(2),
3368 base::Time(), base::Time(), /*secure=*/true, /*httponly=*/false,
3369 CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT));
3370
3371 // SetAllCookies must not flush.
3372 ASSERT_EQ(0, store->flush_count());
3373 EXPECT_TRUE(SetAllCookies(cm.get(), list));
3374 EXPECT_EQ(0, store->flush_count());
3375
3376 CookieList cookies = GetAllCookies(cm.get());
3377 size_t expected_size = 4; // "A", "W" and "Y". "U" is gone.
3378 EXPECT_EQ(expected_size, cookies.size());
3379 auto it = cookies.begin();
3380
3381 ASSERT_TRUE(it != cookies.end());
3382 EXPECT_EQ("C", it->Name());
3383 EXPECT_EQ("D", it->Value());
3384 EXPECT_EQ("/bar", it->Path()); // The path has been updated.
3385
3386 ASSERT_TRUE(++it != cookies.end());
3387 EXPECT_EQ("A", it->Name());
3388 EXPECT_EQ("B", it->Value());
3389
3390 ASSERT_TRUE(++it != cookies.end());
3391 EXPECT_EQ("W", it->Name());
3392 EXPECT_EQ("X", it->Value());
3393
3394 ASSERT_TRUE(++it != cookies.end());
3395 EXPECT_EQ("__Host-Y", it->Name());
3396 EXPECT_EQ("Z", it->Value());
3397
3398 cm = nullptr;
3399 auto entries = net_log_.GetEntries();
3400 size_t pos = ExpectLogContainsSomewhere(
3401 entries, 0, NetLogEventType::COOKIE_STORE_ALIVE, NetLogEventPhase::BEGIN);
3402 pos = ExpectLogContainsSomewhere(
3403 entries, pos, NetLogEventType::COOKIE_STORE_SESSION_PERSISTENCE,
3404 NetLogEventPhase::NONE);
3405 pos = ExpectLogContainsSomewhere(entries, pos,
3406 NetLogEventType::COOKIE_STORE_COOKIE_ADDED,
3407 NetLogEventPhase::NONE);
3408 ExpectLogContainsSomewhere(entries, pos, NetLogEventType::COOKIE_STORE_ALIVE,
3409 NetLogEventPhase::END);
3410 }
3411
3412 // Check that DeleteAll does flush (as a quick check that flush_count() works).
TEST_F(CookieMonsterTest,DeleteAll)3413 TEST_F(CookieMonsterTest, DeleteAll) {
3414 auto store = base::MakeRefCounted<FlushablePersistentStore>();
3415 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
3416 cm->SetPersistSessionCookies(true);
3417
3418 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "X=Y; path=/"));
3419
3420 ASSERT_EQ(0, store->flush_count());
3421 EXPECT_EQ(1u, DeleteAll(cm.get()));
3422 EXPECT_EQ(1, store->flush_count());
3423
3424 cm = nullptr;
3425 auto entries = net_log_.GetEntries();
3426 size_t pos = ExpectLogContainsSomewhere(
3427 entries, 0, NetLogEventType::COOKIE_STORE_ALIVE, NetLogEventPhase::BEGIN);
3428 pos = ExpectLogContainsSomewhere(
3429 entries, pos, NetLogEventType::COOKIE_STORE_SESSION_PERSISTENCE,
3430 NetLogEventPhase::NONE);
3431 pos = ExpectLogContainsSomewhere(entries, pos,
3432 NetLogEventType::COOKIE_STORE_COOKIE_ADDED,
3433 NetLogEventPhase::NONE);
3434 pos = ExpectLogContainsSomewhere(entries, pos,
3435 NetLogEventType::COOKIE_STORE_COOKIE_DELETED,
3436 NetLogEventPhase::NONE);
3437 ExpectLogContainsSomewhere(entries, pos, NetLogEventType::COOKIE_STORE_ALIVE,
3438 NetLogEventPhase::END);
3439 }
3440
TEST_F(CookieMonsterTest,HistogramCheck)3441 TEST_F(CookieMonsterTest, HistogramCheck) {
3442 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
3443
3444 // Should match call in InitializeHistograms, but doesn't really matter
3445 // since the histogram should have been initialized by the CM construction
3446 // above.
3447 base::HistogramBase* expired_histogram = base::Histogram::FactoryGet(
3448 "Cookie.ExpirationDurationMinutesSecure", 1, 10 * 365 * 24 * 60, 50,
3449 base::Histogram::kUmaTargetedHistogramFlag);
3450
3451 std::unique_ptr<base::HistogramSamples> samples1(
3452 expired_histogram->SnapshotSamples());
3453 auto cookie = CanonicalCookie::CreateUnsafeCookieForTesting(
3454 "a", "b", "a.url", "/", base::Time(),
3455 base::Time::Now() + base::Minutes(59), base::Time(), base::Time(),
3456 /*secure=*/true,
3457 /*httponly=*/false, CookieSameSite::NO_RESTRICTION,
3458 COOKIE_PRIORITY_DEFAULT);
3459 GURL source_url = cookie_util::SimulatedCookieSource(*cookie, "https");
3460 ASSERT_TRUE(SetCanonicalCookie(cm.get(), std::move(cookie), source_url,
3461 /*modify_httponly=*/true));
3462
3463 std::unique_ptr<base::HistogramSamples> samples2(
3464 expired_histogram->SnapshotSamples());
3465 EXPECT_EQ(samples1->TotalCount() + 1, samples2->TotalCount());
3466
3467 // kValidCookieLine creates a session cookie.
3468 ASSERT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), kValidCookieLine));
3469
3470 std::unique_ptr<base::HistogramSamples> samples3(
3471 expired_histogram->SnapshotSamples());
3472 EXPECT_EQ(samples2->TotalCount(), samples3->TotalCount());
3473 }
3474
TEST_F(CookieMonsterTest,InvalidExpiryTime)3475 TEST_F(CookieMonsterTest, InvalidExpiryTime) {
3476 std::string cookie_line =
3477 std::string(kValidCookieLine) + "; expires=Blarg arg arg";
3478 std::unique_ptr<CanonicalCookie> cookie(CanonicalCookie::CreateForTesting(
3479 http_www_foo_.url(), cookie_line, Time::Now()));
3480 ASSERT_FALSE(cookie->IsPersistent());
3481 }
3482
3483 // Test that CookieMonster writes session cookies into the underlying
3484 // CookieStore if the "persist session cookies" option is on.
TEST_F(CookieMonsterTest,PersistSessionCookies)3485 TEST_F(CookieMonsterTest, PersistSessionCookies) {
3486 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
3487 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
3488 cm->SetPersistSessionCookies(true);
3489
3490 // All cookies set with SetCookie are session cookies.
3491 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "A=B"));
3492 EXPECT_EQ("A=B", GetCookies(cm.get(), http_www_foo_.url()));
3493
3494 // The cookie was written to the backing store.
3495 EXPECT_EQ(1u, store->commands().size());
3496 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
3497 EXPECT_EQ("A", store->commands()[0].cookie.Name());
3498 EXPECT_EQ("B", store->commands()[0].cookie.Value());
3499
3500 // Modify the cookie.
3501 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "A=C"));
3502 EXPECT_EQ("A=C", GetCookies(cm.get(), http_www_foo_.url()));
3503 EXPECT_EQ(3u, store->commands().size());
3504 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
3505 EXPECT_EQ("A", store->commands()[1].cookie.Name());
3506 EXPECT_EQ("B", store->commands()[1].cookie.Value());
3507 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type);
3508 EXPECT_EQ("A", store->commands()[2].cookie.Name());
3509 EXPECT_EQ("C", store->commands()[2].cookie.Value());
3510
3511 // Delete the cookie. Using .host() here since it's a host and not domain
3512 // cookie.
3513 EXPECT_TRUE(FindAndDeleteCookie(cm.get(), http_www_foo_.host(), "A"));
3514 EXPECT_EQ("", GetCookies(cm.get(), http_www_foo_.url()));
3515 ASSERT_EQ(4u, store->commands().size());
3516 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type);
3517 EXPECT_EQ("A", store->commands()[3].cookie.Name());
3518 EXPECT_EQ("C", store->commands()[3].cookie.Value());
3519 }
3520
3521 // Test the commands sent to the persistent cookie store.
TEST_F(CookieMonsterTest,PersisentCookieStorageTest)3522 TEST_F(CookieMonsterTest, PersisentCookieStorageTest) {
3523 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
3524 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
3525
3526 // Add a cookie.
3527 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(),
3528 "A=B" + FutureCookieExpirationString()));
3529 this->MatchCookieLines("A=B", GetCookies(cm.get(), http_www_foo_.url()));
3530 ASSERT_EQ(1u, store->commands().size());
3531 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
3532 // Remove it.
3533 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "A=B; max-age=0"));
3534 this->MatchCookieLines(std::string(),
3535 GetCookies(cm.get(), http_www_foo_.url()));
3536 ASSERT_EQ(2u, store->commands().size());
3537 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
3538
3539 // Add a cookie.
3540 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(),
3541 "A=B" + FutureCookieExpirationString()));
3542 this->MatchCookieLines("A=B", GetCookies(cm.get(), http_www_foo_.url()));
3543 ASSERT_EQ(3u, store->commands().size());
3544 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type);
3545 // Overwrite it.
3546 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(),
3547 "A=Foo" + FutureCookieExpirationString()));
3548 this->MatchCookieLines("A=Foo", GetCookies(cm.get(), http_www_foo_.url()));
3549 ASSERT_EQ(5u, store->commands().size());
3550 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type);
3551 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[4].type);
3552
3553 // Create some non-persistent cookies and check that they don't go to the
3554 // persistent storage.
3555 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "B=Bar"));
3556 this->MatchCookieLines("A=Foo; B=Bar",
3557 GetCookies(cm.get(), http_www_foo_.url()));
3558 EXPECT_EQ(5u, store->commands().size());
3559 }
3560
3561 // Test to assure that cookies with control characters are purged appropriately.
3562 // See http://crbug.com/238041 for background.
TEST_F(CookieMonsterTest,ControlCharacterPurge)3563 TEST_F(CookieMonsterTest, ControlCharacterPurge) {
3564 const Time now1(Time::Now());
3565 const Time now2(Time::Now() + base::Seconds(1));
3566 const Time now3(Time::Now() + base::Seconds(2));
3567 const Time now4(Time::Now() + base::Seconds(3));
3568 const Time later(now1 + base::Days(1));
3569 const GURL url("https://host/path");
3570 const std::string domain("host");
3571 const std::string path("/path");
3572
3573 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
3574
3575 std::vector<std::unique_ptr<CanonicalCookie>> initial_cookies;
3576
3577 AddCookieToList(url, "foo=bar; path=" + path, now1, &initial_cookies);
3578
3579 // We have to manually build these cookies because they contain control
3580 // characters, and our cookie line parser rejects control characters.
3581 std::unique_ptr<CanonicalCookie> cc =
3582 CanonicalCookie::CreateUnsafeCookieForTesting(
3583 "baz",
3584 "\x05"
3585 "boo",
3586 "." + domain, path, now2, later, base::Time(), base::Time(),
3587 true /* secure */, false /* httponly */,
3588 CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT);
3589 initial_cookies.push_back(std::move(cc));
3590
3591 std::unique_ptr<CanonicalCookie> cc2 =
3592 CanonicalCookie::CreateUnsafeCookieForTesting(
3593 "baz",
3594 "\x7F"
3595 "boo",
3596 "." + domain, path, now3, later, base::Time(), base::Time(),
3597 true /* secure */, false /* httponly */,
3598 CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT);
3599 initial_cookies.push_back(std::move(cc2));
3600
3601 // Partitioned cookies with control characters should not be loaded.
3602 auto cookie_partition_key =
3603 CookiePartitionKey::FromURLForTesting(GURL("https://toplevelsite.com"));
3604 std::unique_ptr<CanonicalCookie> cc3 =
3605 CanonicalCookie::CreateUnsafeCookieForTesting(
3606 "__Host-baz",
3607 "\x7F"
3608 "boo",
3609 domain, "/", now3, later, base::Time(), base::Time(),
3610 true /* secure */, false /* httponly */,
3611 CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
3612 cookie_partition_key);
3613 initial_cookies.push_back(std::move(cc3));
3614
3615 AddCookieToList(url, "hello=world; path=" + path, now4, &initial_cookies);
3616
3617 // Inject our initial cookies into the mock PersistentCookieStore.
3618 store->SetLoadExpectation(true, std::move(initial_cookies));
3619
3620 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
3621
3622 EXPECT_EQ("foo=bar; hello=world",
3623 GetCookies(cm.get(), url,
3624 CookiePartitionKeyCollection(cookie_partition_key)));
3625 }
3626
3627 // Test that cookie source schemes are histogrammed correctly.
TEST_F(CookieMonsterTest,CookieSourceHistogram)3628 TEST_F(CookieMonsterTest, CookieSourceHistogram) {
3629 base::HistogramTester histograms;
3630 const std::string cookie_source_histogram = "Cookie.CookieSourceScheme";
3631
3632 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
3633 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
3634
3635 histograms.ExpectTotalCount(cookie_source_histogram, 0);
3636
3637 // Set a secure cookie on a cryptographic scheme.
3638 EXPECT_TRUE(SetCookie(cm.get(), https_www_foo_.url(), "A=B; path=/; Secure"));
3639 histograms.ExpectTotalCount(cookie_source_histogram, 1);
3640 histograms.ExpectBucketCount(
3641 cookie_source_histogram,
3642 CookieMonster::CookieSource::kSecureCookieCryptographicScheme, 1);
3643
3644 // Set a non-secure cookie on a cryptographic scheme.
3645 EXPECT_TRUE(SetCookie(cm.get(), https_www_foo_.url(), "C=D; path=/;"));
3646 histograms.ExpectTotalCount(cookie_source_histogram, 2);
3647 histograms.ExpectBucketCount(
3648 cookie_source_histogram,
3649 CookieMonster::CookieSource::kNonsecureCookieCryptographicScheme, 1);
3650
3651 // Set a secure cookie on a non-cryptographic scheme.
3652 EXPECT_FALSE(SetCookie(cm.get(), http_www_foo_.url(), "D=E; path=/; Secure"));
3653 histograms.ExpectTotalCount(cookie_source_histogram, 2);
3654 histograms.ExpectBucketCount(
3655 cookie_source_histogram,
3656 CookieMonster::CookieSource::kSecureCookieNoncryptographicScheme, 0);
3657
3658 // Overwrite a secure cookie (set by a cryptographic scheme) on a
3659 // non-cryptographic scheme.
3660 EXPECT_FALSE(SetCookie(cm.get(), http_www_foo_.url(), "A=B; path=/; Secure"));
3661 histograms.ExpectTotalCount(cookie_source_histogram, 2);
3662 histograms.ExpectBucketCount(
3663 cookie_source_histogram,
3664 CookieMonster::CookieSource::kSecureCookieCryptographicScheme, 1);
3665 histograms.ExpectBucketCount(
3666 cookie_source_histogram,
3667 CookieMonster::CookieSource::kSecureCookieNoncryptographicScheme, 0);
3668
3669 // Test that attempting to clear a secure cookie on a http:// URL does
3670 // nothing.
3671 EXPECT_TRUE(SetCookie(cm.get(), https_www_foo_.url(), "F=G; path=/; Secure"));
3672 histograms.ExpectTotalCount(cookie_source_histogram, 3);
3673 std::string cookies1 = GetCookies(cm.get(), https_www_foo_.url());
3674 EXPECT_NE(std::string::npos, cookies1.find("F=G"));
3675 EXPECT_FALSE(SetCookie(cm.get(), http_www_foo_.url(),
3676 "F=G; path=/; Expires=Thu, 01-Jan-1970 00:00:01 GMT"));
3677 std::string cookies2 = GetCookies(cm.get(), https_www_foo_.url());
3678 EXPECT_NE(std::string::npos, cookies2.find("F=G"));
3679 histograms.ExpectTotalCount(cookie_source_histogram, 3);
3680
3681 // Set a non-secure cookie on a non-cryptographic scheme.
3682 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "H=I; path=/"));
3683 histograms.ExpectTotalCount(cookie_source_histogram, 4);
3684 histograms.ExpectBucketCount(
3685 cookie_source_histogram,
3686 CookieMonster::CookieSource::kNonsecureCookieNoncryptographicScheme, 1);
3687 }
3688
3689 // Test that inserting the first cookie for a key and deleting the last cookie
3690 // for a key correctly reflected in the Cookie.NumKeys histogram.
TEST_F(CookieMonsterTest,NumKeysHistogram)3691 TEST_F(CookieMonsterTest, NumKeysHistogram) {
3692 const char kHistogramName[] = "Cookie.NumKeys";
3693
3694 // Test loading cookies from store.
3695 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
3696 std::vector<std::unique_ptr<CanonicalCookie>> initial_cookies;
3697 initial_cookies.push_back(CanonicalCookie::CreateForTesting(
3698 GURL("http://domain1.test"), "A=1", base::Time::Now()));
3699 initial_cookies.push_back(CanonicalCookie::CreateForTesting(
3700 GURL("http://domain2.test"), "A=1", base::Time::Now()));
3701 initial_cookies.push_back(CanonicalCookie::CreateForTesting(
3702 GURL("http://sub.domain2.test"), "A=1", base::Time::Now()));
3703 initial_cookies.push_back(CanonicalCookie::CreateForTesting(
3704 GURL("http://domain3.test"), "A=1", base::Time::Now()));
3705 initial_cookies.push_back(CanonicalCookie::CreateForTesting(
3706 GURL("http://domain3.test"), "B=1", base::Time::Now()));
3707 store->SetLoadExpectation(true /* return_value */,
3708 std::move(initial_cookies));
3709 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
3710 {
3711 base::HistogramTester histogram_tester;
3712 // Access the cookies to trigger loading from the persistent store.
3713 EXPECT_EQ(5u, this->GetAllCookies(cm.get()).size());
3714 EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting());
3715 // There should be 3 keys: "domain1.test", "domain2.test", and
3716 // "domain3.test".
3717 histogram_tester.ExpectUniqueSample(kHistogramName, 3 /* sample */,
3718 1 /* count */);
3719 }
3720
3721 // Test adding cookies for already existing key.
3722 {
3723 base::HistogramTester histogram_tester;
3724 EXPECT_TRUE(CreateAndSetCookie(cm.get(), GURL("https://domain1.test"),
3725 "B=1", CookieOptions::MakeAllInclusive()));
3726 EXPECT_TRUE(CreateAndSetCookie(cm.get(), GURL("http://sub.domain1.test"),
3727 "B=1", CookieOptions::MakeAllInclusive()));
3728 EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting());
3729 histogram_tester.ExpectUniqueSample(kHistogramName, 3 /* sample */,
3730 1 /* count */);
3731 }
3732
3733 // Test adding a cookie for a new key.
3734 {
3735 base::HistogramTester histogram_tester;
3736 EXPECT_TRUE(CreateAndSetCookie(cm.get(), GURL("https://domain4.test"),
3737 "A=1", CookieOptions::MakeAllInclusive()));
3738 EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting());
3739 histogram_tester.ExpectUniqueSample(kHistogramName, 4 /* sample */,
3740 1 /* count */);
3741 }
3742
3743 // Test overwriting the only cookie for a key. (Deletes and inserts, so the
3744 // total doesn't change.)
3745 {
3746 base::HistogramTester histogram_tester;
3747 EXPECT_TRUE(CreateAndSetCookie(cm.get(), GURL("https://domain4.test"),
3748 "A=2", CookieOptions::MakeAllInclusive()));
3749 EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting());
3750 histogram_tester.ExpectUniqueSample(kHistogramName, 4 /* sample */,
3751 1 /* count */);
3752 }
3753
3754 // Test deleting cookie for a key with more than one cookie.
3755 {
3756 base::HistogramTester histogram_tester;
3757 EXPECT_TRUE(CreateAndSetCookie(cm.get(), GURL("https://domain2.test"),
3758 "A=1; Max-Age=0",
3759 CookieOptions::MakeAllInclusive()));
3760 EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting());
3761 histogram_tester.ExpectUniqueSample(kHistogramName, 4 /* sample */,
3762 1 /* count */);
3763 }
3764
3765 // Test deleting cookie for a key with only one cookie.
3766 {
3767 base::HistogramTester histogram_tester;
3768 EXPECT_TRUE(CreateAndSetCookie(cm.get(), GURL("https://domain4.test"),
3769 "A=1; Max-Age=0",
3770 CookieOptions::MakeAllInclusive()));
3771 EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting());
3772 histogram_tester.ExpectUniqueSample(kHistogramName, 3 /* sample */,
3773 1 /* count */);
3774 }
3775 }
3776
TEST_F(CookieMonsterTest,CookieCount2Histogram)3777 TEST_F(CookieMonsterTest, CookieCount2Histogram) {
3778 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
3779
3780 {
3781 base::HistogramTester histogram_tester;
3782 ASSERT_TRUE(cm->DoRecordPeriodicStatsForTesting());
3783 histogram_tester.ExpectUniqueSample("Cookie.Count2",
3784 /*sample=*/0,
3785 /*expected_bucket_count=*/1);
3786 }
3787
3788 {
3789 base::HistogramTester histogram_tester;
3790
3791 auto cookie = CanonicalCookie::CreateUnsafeCookieForTesting(
3792 "a", "b", "a.url", "/", base::Time(),
3793 base::Time::Now() + base::Minutes(59), base::Time(), base::Time(),
3794 /*secure=*/true,
3795 /*httponly=*/false, CookieSameSite::NO_RESTRICTION,
3796 COOKIE_PRIORITY_DEFAULT);
3797 GURL source_url = cookie_util::SimulatedCookieSource(*cookie, "https");
3798 ASSERT_TRUE(SetCanonicalCookie(cm.get(), std::move(cookie), source_url,
3799 /*modify_httponly=*/true));
3800
3801 ASSERT_TRUE(cm->DoRecordPeriodicStatsForTesting());
3802
3803 histogram_tester.ExpectUniqueSample("Cookie.Count2", /*sample=*/1,
3804 /*expected_bucket_count=*/1);
3805 }
3806 }
3807
TEST_F(CookieMonsterTest,CookieJarSizeHistograms)3808 TEST_F(CookieMonsterTest, CookieJarSizeHistograms) {
3809 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
3810
3811 {
3812 base::HistogramTester histogram_tester;
3813 ASSERT_TRUE(cm->DoRecordPeriodicStatsForTesting());
3814 histogram_tester.ExpectUniqueSample("Cookie.CookieJarSize",
3815 /*sample=*/0,
3816 /*expected_bucket_count=*/1);
3817 histogram_tester.ExpectUniqueSample("Cookie.AvgCookieJarSizePerKey",
3818 /*sample=*/0,
3819 /*expected_bucket_count=*/1);
3820 histogram_tester.ExpectUniqueSample("Cookie.MaxCookieJarSizePerKey",
3821 /*sample=*/0,
3822 /*expected_bucket_count=*/1);
3823 }
3824
3825 auto set_cookie =
3826 [&](const std::string& name, int cookie_value_size_kb,
3827 const std::string& domain, CookieSameSite same_site,
3828 const std::optional<CookiePartitionKey>& partition_key) {
3829 auto cc = CanonicalCookie::CreateUnsafeCookieForTesting(
3830 name, std::string(cookie_value_size_kb * 1024, '0'), domain, "/",
3831 base::Time(), base::Time::Now() + base::Minutes(59), base::Time(),
3832 base::Time(),
3833 /*secure=*/true,
3834 /*httponly=*/false, same_site, COOKIE_PRIORITY_DEFAULT,
3835 partition_key);
3836 GURL source_url = cookie_util::SimulatedCookieSource(*cc, "https");
3837 ASSERT_TRUE(SetCanonicalCookie(cm.get(), std::move(cc), source_url,
3838 /*can_modify_httponly=*/true));
3839 };
3840
3841 { // Add unpartitioned cookie.
3842 base::HistogramTester histogram_tester;
3843 set_cookie("a", 2, "a.url", CookieSameSite::NO_RESTRICTION, std::nullopt);
3844 ASSERT_TRUE(cm->DoRecordPeriodicStatsForTesting());
3845
3846 histogram_tester.ExpectUniqueSample("Cookie.CookieJarSize",
3847 /*sample=*/2,
3848 /*expected_bucket_count=*/1);
3849 histogram_tester.ExpectUniqueSample("Cookie.AvgCookieJarSizePerKey",
3850 /*sample=*/2,
3851 /*expected_bucket_count=*/1);
3852 histogram_tester.ExpectUniqueSample("Cookie.MaxCookieJarSizePerKey",
3853 /*sample=*/2,
3854 /*expected_bucket_count=*/1);
3855 }
3856
3857 { // Add partitioned cookie, should not impact the counter.
3858 base::HistogramTester histogram_tester;
3859 set_cookie("b", 3, "a.url", CookieSameSite::NO_RESTRICTION,
3860 CookiePartitionKey::FromURLForTesting(
3861 GURL("https://toplevelsite.com")));
3862 ASSERT_TRUE(cm->DoRecordPeriodicStatsForTesting());
3863
3864 histogram_tester.ExpectUniqueSample("Cookie.CookieJarSize",
3865 /*sample=*/2,
3866 /*expected_bucket_count=*/1);
3867 histogram_tester.ExpectUniqueSample("Cookie.AvgCookieJarSizePerKey",
3868 /*sample=*/2,
3869 /*expected_bucket_count=*/1);
3870 histogram_tester.ExpectUniqueSample("Cookie.MaxCookieJarSizePerKey",
3871 /*sample=*/2,
3872 /*expected_bucket_count=*/1);
3873 }
3874
3875 { // Add unpartitioned cookie from another domain. Is also SameSite=Lax to
3876 // ensure the counter includes SameSite cookies.
3877 base::HistogramTester histogram_tester;
3878 set_cookie("c", 4, "c.url", CookieSameSite::LAX_MODE, std::nullopt);
3879 ASSERT_TRUE(cm->DoRecordPeriodicStatsForTesting());
3880
3881 histogram_tester.ExpectUniqueSample("Cookie.CookieJarSize",
3882 /*sample=*/6,
3883 /*expected_bucket_count=*/1);
3884 histogram_tester.ExpectUniqueSample("Cookie.AvgCookieJarSizePerKey",
3885 /*sample=*/3,
3886 /*expected_bucket_count=*/1);
3887 histogram_tester.ExpectUniqueSample("Cookie.MaxCookieJarSizePerKey",
3888 /*sample=*/4,
3889 /*expected_bucket_count=*/1);
3890 }
3891 }
3892
TEST_F(CookieMonsterTest,PartitionedCookieHistograms)3893 TEST_F(CookieMonsterTest, PartitionedCookieHistograms) {
3894 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
3895
3896 {
3897 base::HistogramTester histogram_tester;
3898 ASSERT_TRUE(cm->DoRecordPeriodicStatsForTesting());
3899
3900 // Cookie counters.
3901 histogram_tester.ExpectUniqueSample("Cookie.PartitionedCookieCount",
3902 /*sample=*/0,
3903 /*count=*/1);
3904 histogram_tester.ExpectUniqueSample("Cookie.PartitionedCookieCount.Nonced",
3905 /*sample=*/0,
3906 /*count=*/1);
3907 histogram_tester.ExpectUniqueSample(
3908 "Cookie.PartitionedCookieCount.Unnonced", /*sample=*/0,
3909 /*count=*/1);
3910
3911 // Partitioned cookie jar size.
3912 histogram_tester.ExpectUniqueSample(
3913 "Cookie.PartitionedCookieJarSizeKibibytes",
3914 /*sample=*/0,
3915 /*count=*/1);
3916 histogram_tester.ExpectUniqueSample(
3917 "Cookie.PartitionedCookieJarSizeKibibytes.Nonced", /*sample=*/0,
3918 /*count=*/1);
3919 histogram_tester.ExpectUniqueSample(
3920 "Cookie.PartitionedCookieJarSizeKibibytes.Unnonced", /*sample=*/0,
3921 /*count=*/1);
3922
3923 // Partitioned cookie jar size per partition.
3924 histogram_tester.ExpectUniqueSample("Cookie.CookiePartitionSizeKibibytes",
3925 /*sample=*/0,
3926 /*count=*/0);
3927 }
3928
3929 { // Add unpartitioned cookie.
3930 base::HistogramTester histogram_tester;
3931 auto cookie = CanonicalCookie::CreateUnsafeCookieForTesting(
3932 "a", "b", "a.url", "/", base::Time(),
3933 base::Time::Now() + base::Minutes(59), base::Time(), base::Time(),
3934 /*secure=*/true,
3935 /*httponly=*/false, CookieSameSite::NO_RESTRICTION,
3936 COOKIE_PRIORITY_DEFAULT);
3937 GURL source_url = cookie_util::SimulatedCookieSource(*cookie, "https");
3938 ASSERT_TRUE(SetCanonicalCookie(cm.get(), std::move(cookie), source_url,
3939 /*modify_httponly=*/true));
3940 ASSERT_TRUE(cm->DoRecordPeriodicStatsForTesting());
3941
3942 // Cookie counters.
3943 histogram_tester.ExpectUniqueSample("Cookie.PartitionedCookieCount",
3944 /*sample=*/0,
3945 /*count=*/1);
3946 histogram_tester.ExpectUniqueSample("Cookie.PartitionedCookieCount.Nonced",
3947 /*sample=*/0,
3948 /*count=*/1);
3949 histogram_tester.ExpectUniqueSample(
3950 "Cookie.PartitionedCookieCount.Unnonced", /*sample=*/0,
3951 /*count=*/1);
3952 histogram_tester.ExpectUniqueSample("Cookie.Count2", /*sample=*/1,
3953 /*count=*/1);
3954
3955 // Partitioned cookie jar size.
3956 histogram_tester.ExpectUniqueSample(
3957 "Cookie.PartitionedCookieJarSizeKibibytes",
3958 /*sample=*/0,
3959 /*count=*/1);
3960 histogram_tester.ExpectUniqueSample(
3961 "Cookie.PartitionedCookieJarSizeKibibytes.Nonced", /*sample=*/0,
3962 /*count=*/1);
3963 histogram_tester.ExpectUniqueSample(
3964 "Cookie.PartitionedCookieJarSizeKibibytes.Unnonced", /*sample=*/0,
3965 /*count=*/1);
3966
3967 // Partitioned cookie jar size per partition.
3968 histogram_tester.ExpectUniqueSample("Cookie.CookiePartitionSizeKibibytes",
3969 /*sample=*/0,
3970 /*count=*/0);
3971 }
3972
3973 { // Add unnonced partitioned cookie.
3974 base::HistogramTester histogram_tester;
3975 auto cookie = CanonicalCookie::CreateUnsafeCookieForTesting(
3976 "a", std::string(2 * 1024, '0'), "a.url", "/", base::Time(),
3977 base::Time::Now() + base::Minutes(59), base::Time(), base::Time(),
3978 /*secure=*/true,
3979 /*httponly=*/false, CookieSameSite::NO_RESTRICTION,
3980 COOKIE_PRIORITY_DEFAULT,
3981 CookiePartitionKey::FromURLForTesting(GURL("https://example.com")));
3982 GURL source_url = cookie_util::SimulatedCookieSource(*cookie, "https");
3983 ASSERT_TRUE(SetCanonicalCookie(cm.get(), std::move(cookie), source_url,
3984 /*modify_httponly=*/true));
3985 ASSERT_TRUE(cm->DoRecordPeriodicStatsForTesting());
3986
3987 // Cookie counters.
3988 histogram_tester.ExpectUniqueSample("Cookie.PartitionedCookieCount",
3989 /*sample=*/1,
3990 /*count=*/1);
3991 histogram_tester.ExpectUniqueSample("Cookie.PartitionedCookieCount.Nonced",
3992 /*sample=*/0,
3993 /*count=*/1);
3994 histogram_tester.ExpectUniqueSample(
3995 "Cookie.PartitionedCookieCount.Unnonced", /*sample=*/1,
3996 /*count=*/1);
3997 histogram_tester.ExpectUniqueSample("Cookie.Count2", /*sample=*/1,
3998 /*count=*/1);
3999
4000 // Partitioned cookie jar size.
4001 histogram_tester.ExpectUniqueSample(
4002 "Cookie.PartitionedCookieJarSizeKibibytes",
4003 /*sample=*/2,
4004 /*count=*/1);
4005 histogram_tester.ExpectUniqueSample(
4006 "Cookie.PartitionedCookieJarSizeKibibytes.Nonced", /*sample=*/0,
4007 /*count=*/1);
4008 histogram_tester.ExpectUniqueSample(
4009 "Cookie.PartitionedCookieJarSizeKibibytes.Unnonced", /*sample=*/2,
4010 /*count=*/1);
4011
4012 // Partitioned cookie jar size per partition.
4013 histogram_tester.ExpectUniqueSample("Cookie.CookiePartitionSizeKibibytes",
4014 /*sample=*/2,
4015 /*count=*/1);
4016 }
4017
4018 { // Add nonced partitioned cookie.
4019 base::HistogramTester histogram_tester;
4020 auto cookie = CanonicalCookie::CreateUnsafeCookieForTesting(
4021 "a", std::string(3 * 1024, '0'), "a.url", "/", base::Time(),
4022 base::Time::Now() + base::Minutes(59), base::Time(), base::Time(),
4023 /*secure=*/true,
4024 /*httponly=*/false, CookieSameSite::NO_RESTRICTION,
4025 COOKIE_PRIORITY_DEFAULT,
4026 CookiePartitionKey::FromURLForTesting(
4027 GURL("https://example.com"),
4028 CookiePartitionKey::AncestorChainBit::kCrossSite,
4029 base::UnguessableToken::Create()));
4030 GURL source_url = cookie_util::SimulatedCookieSource(*cookie, "https");
4031 ASSERT_TRUE(SetCanonicalCookie(cm.get(), std::move(cookie), source_url,
4032 /*modify_httponly=*/true));
4033 ASSERT_TRUE(cm->DoRecordPeriodicStatsForTesting());
4034
4035 // Cookie counts.
4036 histogram_tester.ExpectUniqueSample("Cookie.PartitionedCookieCount",
4037 /*sample=*/2,
4038 /*count=*/1);
4039 histogram_tester.ExpectUniqueSample("Cookie.PartitionedCookieCount.Nonced",
4040 /*sample=*/1,
4041 /*count=*/1);
4042 histogram_tester.ExpectUniqueSample(
4043 "Cookie.PartitionedCookieCount.Unnonced", /*sample=*/1,
4044 /*count=*/1);
4045 histogram_tester.ExpectUniqueSample("Cookie.Count2", /*sample=*/1,
4046 /*count=*/1);
4047
4048 // Partitioned cookie jar size.
4049 histogram_tester.ExpectUniqueSample(
4050 "Cookie.PartitionedCookieJarSizeKibibytes",
4051 /*sample=*/5,
4052 /*count=*/1);
4053 histogram_tester.ExpectUniqueSample(
4054 "Cookie.PartitionedCookieJarSizeKibibytes.Nonced", /*sample=*/3,
4055 /*count=*/1);
4056 histogram_tester.ExpectUniqueSample(
4057 "Cookie.PartitionedCookieJarSizeKibibytes.Unnonced", /*sample=*/2,
4058 /*count=*/1);
4059
4060 // Partitioned cookie jar size per partition.
4061 histogram_tester.ExpectBucketCount("Cookie.CookiePartitionSizeKibibytes",
4062 /*sample=*/2,
4063 /*count=*/1);
4064 histogram_tester.ExpectBucketCount("Cookie.CookiePartitionSizeKibibytes",
4065 /*sample=*/3,
4066 /*count=*/1);
4067 }
4068 }
4069
TEST_F(CookieMonsterTest,MaxSameSiteNoneCookiesPerKey)4070 TEST_F(CookieMonsterTest, MaxSameSiteNoneCookiesPerKey) {
4071 const char kHistogramName[] = "Cookie.MaxSameSiteNoneCookiesPerKey";
4072
4073 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
4074 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
4075 ASSERT_EQ(0u, GetAllCookies(cm.get()).size());
4076
4077 { // Only SameSite cookies should not log a sample.
4078 base::HistogramTester histogram_tester;
4079
4080 ASSERT_TRUE(CreateAndSetCookie(cm.get(), GURL("https://domain1.test"),
4081 "A=1;SameSite=Lax",
4082 CookieOptions::MakeAllInclusive()));
4083 ASSERT_EQ(1u, GetAllCookies(cm.get()).size());
4084 ASSERT_TRUE(cm->DoRecordPeriodicStatsForTesting());
4085 histogram_tester.ExpectUniqueSample(kHistogramName, 0 /* sample */,
4086 1 /* count */);
4087 }
4088
4089 { // SameSite=None cookie should log a sample.
4090 base::HistogramTester histogram_tester;
4091
4092 ASSERT_TRUE(CreateAndSetCookie(cm.get(), GURL("https://domain1.test"),
4093 "B=2;SameSite=None;Secure",
4094 CookieOptions::MakeAllInclusive()));
4095 ASSERT_EQ(2u, GetAllCookies(cm.get()).size());
4096 ASSERT_TRUE(cm->DoRecordPeriodicStatsForTesting());
4097 histogram_tester.ExpectUniqueSample(kHistogramName, 1 /* sample */,
4098 1 /* count */);
4099 }
4100
4101 { // Should log the maximum number of SameSite=None cookies.
4102 base::HistogramTester histogram_tester;
4103
4104 ASSERT_TRUE(CreateAndSetCookie(cm.get(), GURL("https://domain2.test"),
4105 "A=1;SameSite=None;Secure",
4106 CookieOptions::MakeAllInclusive()));
4107 ASSERT_TRUE(CreateAndSetCookie(cm.get(), GURL("https://domain2.test"),
4108 "B=2;SameSite=None;Secure",
4109 CookieOptions::MakeAllInclusive()));
4110 ASSERT_TRUE(CreateAndSetCookie(cm.get(), GURL("https://domain3.test"),
4111 "A=1;SameSite=None;Secure",
4112 CookieOptions::MakeAllInclusive()));
4113 ASSERT_EQ(5u, GetAllCookies(cm.get()).size());
4114 ASSERT_TRUE(cm->DoRecordPeriodicStatsForTesting());
4115 histogram_tester.ExpectUniqueSample(kHistogramName, 2 /* sample */,
4116 1 /* count */);
4117 }
4118 }
4119
4120 // Test that localhost URLs can set and get secure cookies, even if
4121 // non-cryptographic.
TEST_F(CookieMonsterTest,SecureCookieLocalhost)4122 TEST_F(CookieMonsterTest, SecureCookieLocalhost) {
4123 auto cm = std::make_unique<CookieMonster>(nullptr, nullptr);
4124
4125 GURL insecure_localhost("http://localhost");
4126 GURL secure_localhost("https://localhost");
4127
4128 // Insecure localhost can set secure cookie, and warning is attached to
4129 // status.
4130 {
4131 auto cookie = CanonicalCookie::CreateForTesting(
4132 insecure_localhost, "from_insecure_localhost=1; Secure",
4133 base::Time::Now());
4134 ASSERT_TRUE(cookie);
4135 CookieInclusionStatus status =
4136 SetCanonicalCookieReturnAccessResult(cm.get(), std::move(cookie),
4137 insecure_localhost,
4138 true /* can_modify_httponly */)
4139 .status;
4140 EXPECT_TRUE(status.IsInclude());
4141 EXPECT_TRUE(status.HasExactlyWarningReasonsForTesting(
4142 {CookieInclusionStatus::WARN_SECURE_ACCESS_GRANTED_NON_CRYPTOGRAPHIC}));
4143 }
4144 // Secure localhost can set secure cookie, and warning is not attached to
4145 // status.
4146 {
4147 auto cookie = CanonicalCookie::CreateForTesting(
4148 secure_localhost, "from_secure_localhost=1; Secure", base::Time::Now());
4149 ASSERT_TRUE(cookie);
4150 CookieInclusionStatus status =
4151 SetCanonicalCookieReturnAccessResult(cm.get(), std::move(cookie),
4152 secure_localhost,
4153 true /* can_modify_httponly */)
4154 .status;
4155 EXPECT_EQ(CookieInclusionStatus(), status);
4156 }
4157
4158 // Insecure localhost can get secure cookies, and warning is attached to
4159 // status.
4160 {
4161 GetCookieListCallback callback;
4162 cm->GetCookieListWithOptionsAsync(
4163 insecure_localhost, CookieOptions::MakeAllInclusive(),
4164 CookiePartitionKeyCollection(), callback.MakeCallback());
4165 callback.WaitUntilDone();
4166 EXPECT_EQ(2u, callback.cookies_with_access_results().size());
4167 for (const auto& cookie_item : callback.cookies_with_access_results()) {
4168 EXPECT_TRUE(cookie_item.cookie.SecureAttribute());
4169 EXPECT_TRUE(cookie_item.access_result.status.IsInclude());
4170 EXPECT_TRUE(
4171 cookie_item.access_result.status.HasExactlyWarningReasonsForTesting(
4172 {CookieInclusionStatus::
4173 WARN_SECURE_ACCESS_GRANTED_NON_CRYPTOGRAPHIC}));
4174 }
4175 }
4176 // Secure localhost can get secure cookies, and warning is not attached to
4177 // status.
4178 {
4179 GetCookieListCallback callback;
4180 cm->GetCookieListWithOptionsAsync(
4181 secure_localhost, CookieOptions::MakeAllInclusive(),
4182 CookiePartitionKeyCollection(), callback.MakeCallback());
4183 callback.WaitUntilDone();
4184 EXPECT_EQ(2u, callback.cookies_with_access_results().size());
4185 for (const auto& cookie_item : callback.cookies_with_access_results()) {
4186 EXPECT_TRUE(cookie_item.cookie.SecureAttribute());
4187 EXPECT_EQ(CookieInclusionStatus(), cookie_item.access_result.status);
4188 }
4189 }
4190 }
4191
TEST_F(CookieMonsterTest,MaybeDeleteEquivalentCookieAndUpdateStatus)4192 TEST_F(CookieMonsterTest, MaybeDeleteEquivalentCookieAndUpdateStatus) {
4193 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
4194 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
4195
4196 // Set a secure, httponly cookie from a secure origin
4197 auto preexisting_cookie = CanonicalCookie::CreateForTesting(
4198 https_www_foo_.url(), "A=B;Secure;HttpOnly", base::Time::Now());
4199 CookieAccessResult access_result = SetCanonicalCookieReturnAccessResult(
4200 cm.get(), std::move(preexisting_cookie), https_www_foo_.url(),
4201 true /* can_modify_httponly */);
4202 ASSERT_TRUE(access_result.status.IsInclude());
4203
4204 // Set a new cookie with a different name. Should work because cookies with
4205 // different names are not considered equivalent nor "equivalent for secure
4206 // cookie matching".
4207 // Same origin:
4208 EXPECT_TRUE(SetCookie(cm.get(), https_www_foo_.url(), "B=A;"));
4209 // Different scheme, same domain:
4210 EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "C=A;"));
4211
4212 // Set a non-Secure cookie from an insecure origin that is
4213 // equivalent to the pre-existing Secure cookie.
4214 auto bad_cookie = CanonicalCookie::CreateForTesting(http_www_foo_.url(),
4215 "A=D", base::Time::Now());
4216 // Allow modifying HttpOnly, so that we don't skip preexisting cookies for
4217 // being HttpOnly.
4218 access_result = SetCanonicalCookieReturnAccessResult(
4219 cm.get(), std::move(bad_cookie), http_www_foo_.url(),
4220 true /* can_modify_httponly */);
4221 EXPECT_TRUE(access_result.status.HasExactlyExclusionReasonsForTesting(
4222 {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE}));
4223 // The preexisting cookie should still be there.
4224 EXPECT_THAT(GetCookiesWithOptions(cm.get(), https_www_foo_.url(),
4225 CookieOptions::MakeAllInclusive()),
4226 ::testing::HasSubstr("A=B"));
4227
4228 auto entries = net_log_.GetEntries();
4229 size_t skipped_secure_netlog_index = ExpectLogContainsSomewhere(
4230 entries, 0, NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_SECURE,
4231 NetLogEventPhase::NONE);
4232 EXPECT_FALSE(LogContainsEntryWithTypeAfter(
4233 entries, 0, NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_HTTPONLY));
4234 ExpectLogContainsSomewhereAfter(
4235 entries, skipped_secure_netlog_index,
4236 NetLogEventType::COOKIE_STORE_COOKIE_PRESERVED_SKIPPED_SECURE,
4237 NetLogEventPhase::NONE);
4238
4239 net_log_.Clear();
4240
4241 // Set a non-secure cookie from an insecure origin that matches the name of an
4242 // already existing cookie but is not equivalent. This should fail since it's
4243 // trying to shadow a secure cookie.
4244 bad_cookie = CanonicalCookie::CreateForTesting(
4245 http_www_foo_.url(), "A=E; path=/some/path", base::Time::Now());
4246 // Allow modifying HttpOnly, so that we don't skip preexisting cookies for
4247 // being HttpOnly.
4248 access_result = SetCanonicalCookieReturnAccessResult(
4249 cm.get(), std::move(bad_cookie), http_www_foo_.url(),
4250 true /* can_modify_httponly */);
4251 EXPECT_TRUE(access_result.status.HasExactlyExclusionReasonsForTesting(
4252 {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE}));
4253 // The preexisting cookie should still be there.
4254 EXPECT_THAT(GetCookiesWithOptions(cm.get(), https_www_foo_.url(),
4255 CookieOptions::MakeAllInclusive()),
4256 ::testing::HasSubstr("A=B"));
4257
4258 entries = net_log_.GetEntries();
4259 skipped_secure_netlog_index = ExpectLogContainsSomewhere(
4260 entries, 0, NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_SECURE,
4261 NetLogEventPhase::NONE);
4262 EXPECT_FALSE(LogContainsEntryWithTypeAfter(
4263 entries, 0, NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_HTTPONLY));
4264 // There wasn't actually a strictly equivalent cookie that we would have
4265 // deleted.
4266 EXPECT_FALSE(LogContainsEntryWithTypeAfter(
4267 entries, skipped_secure_netlog_index,
4268 NetLogEventType::COOKIE_STORE_COOKIE_PRESERVED_SKIPPED_SECURE));
4269
4270 net_log_.Clear();
4271
4272 // Test skipping equivalent cookie for HttpOnly only.
4273 bad_cookie = CanonicalCookie::CreateForTesting(
4274 https_www_foo_.url(), "A=E; Secure", base::Time::Now());
4275 access_result = SetCanonicalCookieReturnAccessResult(
4276 cm.get(), std::move(bad_cookie), https_www_foo_.url(),
4277 false /* can_modify_httponly */);
4278 EXPECT_TRUE(access_result.status.HasExactlyExclusionReasonsForTesting(
4279 {CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY}));
4280
4281 entries = net_log_.GetEntries();
4282 ExpectLogContainsSomewhere(
4283 entries, 0, NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_HTTPONLY,
4284 NetLogEventPhase::NONE);
4285 EXPECT_FALSE(LogContainsEntryWithTypeAfter(
4286 entries, 0, NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_SECURE));
4287 }
4288
TEST_F(CookieMonsterTest,MaybeDeleteEquivalentCookieAndUpdateStatus_PartitionedCookies)4289 TEST_F(CookieMonsterTest,
4290 MaybeDeleteEquivalentCookieAndUpdateStatus_PartitionedCookies) {
4291 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
4292 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
4293
4294 // Test adding two cookies with the same name, domain, and path but different
4295 // partition keys.
4296 auto cookie_partition_key1 =
4297 CookiePartitionKey::FromURLForTesting(GURL("https://toplevelsite1.com"));
4298
4299 auto preexisting_cookie = CanonicalCookie::CreateForTesting(
4300 https_www_foo_.url(), "__Host-A=B; Secure; Path=/; Partitioned; HttpOnly",
4301 base::Time::Now(), std::nullopt /* server_time */,
4302 cookie_partition_key1 /* cookie_partition_key */);
4303 CookieAccessResult access_result = SetCanonicalCookieReturnAccessResult(
4304 cm.get(), std::move(preexisting_cookie), https_www_foo_.url(),
4305 true /* can_modify_httponly */);
4306 ASSERT_TRUE(access_result.status.IsInclude());
4307
4308 // Should be able to set a cookie with a different partition key.
4309 EXPECT_TRUE(SetCookie(cm.get(), https_www_foo_.url(),
4310 "__Host-A=C; Secure; Path=/; Partitioned",
4311 CookiePartitionKey::FromURLForTesting(
4312 GURL("https://toplevelsite2.com"))));
4313
4314 // Should not overwrite HttpOnly cookie.
4315 auto bad_cookie = CanonicalCookie::CreateForTesting(
4316 https_www_foo_.url(), "__Host-A=D; Secure; Path=/; Partitioned",
4317 base::Time::Now(), std::nullopt /* server_time */, cookie_partition_key1);
4318 access_result = SetCanonicalCookieReturnAccessResult(
4319 cm.get(), std::move(bad_cookie), https_www_foo_.url(),
4320 false /* can_modify_httponly */);
4321 EXPECT_TRUE(access_result.status.HasExactlyExclusionReasonsForTesting(
4322 {CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY}));
4323 EXPECT_THAT(
4324 GetCookiesWithOptions(
4325 cm.get(), https_www_foo_.url(), CookieOptions::MakeAllInclusive(),
4326 CookiePartitionKeyCollection(cookie_partition_key1)),
4327 ::testing::HasSubstr("A=B"));
4328 }
4329
4330 // Tests whether cookies that vary based on their source scheme/port are
4331 // overwritten correctly depending on the state of the origin-bound feature
4332 // flags.
4333 class CookieMonsterTest_MaybeDeleteEquivalentCookieAndUpdateStatus
4334 : public CookieMonsterTest {
4335 public:
4336 // Creates a store, CookieMonster, and inserts a single cookie, created on an
4337 // https/443 origin.
InitializeTest()4338 void InitializeTest() {
4339 store_ = base::MakeRefCounted<MockPersistentCookieStore>();
4340 cm_ = std::make_unique<CookieMonster>(store_.get(), net::NetLog::Get());
4341
4342 auto preexisting_cookie_https = CanonicalCookie::CreateForTesting(
4343 https_www_foo_.url(), "A=PreexistingHttps443", base::Time::Now());
4344
4345 CookieAccessResult access_result = SetCanonicalCookieReturnAccessResult(
4346 cm_.get(), std::move(preexisting_cookie_https), https_www_foo_.url(),
4347 /*can_modify_httponly=*/true);
4348 ASSERT_TRUE(access_result.status.IsInclude());
4349
4350 auto preexisting_domain_cookie_https = CanonicalCookie::CreateForTesting(
4351 https_www_foo_.url(),
4352 "A=PreexistingDomainHttps443; Domain=" + https_www_foo_.domain(),
4353 base::Time::Now());
4354
4355 access_result = SetCanonicalCookieReturnAccessResult(
4356 cm_.get(), std::move(preexisting_domain_cookie_https),
4357 https_www_foo_.url(),
4358 /*can_modify_httponly=*/true);
4359 ASSERT_TRUE(access_result.status.IsInclude());
4360
4361 ASSERT_EQ(GetAllCookies(cm_.get()).size(), 2UL);
4362 }
4363
4364 // Inserts a single cookie that differs from "PreexistingHttps443" by scheme
4365 // only.
AddHttpPort443Cookie()4366 void AddHttpPort443Cookie() {
4367 GURL::Replacements replace_scheme;
4368 replace_scheme.SetSchemeStr("http");
4369 // We need to explicitly set the existing port, otherwise GURL will
4370 // implicitly take the port of the new scheme. I.e.: We'll inadvertently
4371 // change the port to 80.
4372 replace_scheme.SetPortStr("443");
4373 GURL foo_made_http = https_www_foo_.url().ReplaceComponents(replace_scheme);
4374
4375 auto differ_by_scheme_only = CanonicalCookie::CreateForTesting(
4376 foo_made_http, "A=InsertedHttp443", base::Time::Now());
4377
4378 CookieAccessResult access_result = SetCanonicalCookieReturnAccessResult(
4379 cm_.get(), std::move(differ_by_scheme_only), foo_made_http,
4380 /*can_modify_httponly=*/true);
4381 ASSERT_TRUE(access_result.status.IsInclude());
4382 }
4383
4384 // Inserts a single cookie that differs from "PreexistingHttps443" by port
4385 // only.
AddHttpsPort80Cookie()4386 void AddHttpsPort80Cookie() {
4387 GURL::Replacements replace_port;
4388 replace_port.SetPortStr("80");
4389 GURL foo_made_80 = https_www_foo_.url().ReplaceComponents(replace_port);
4390
4391 auto differ_by_port_only = CanonicalCookie::CreateForTesting(
4392 foo_made_80, "A=InsertedHttps80", base::Time::Now());
4393
4394 CookieAccessResult access_result = SetCanonicalCookieReturnAccessResult(
4395 cm_.get(), std::move(differ_by_port_only), foo_made_80,
4396 /*can_modify_httponly=*/true);
4397 ASSERT_TRUE(access_result.status.IsInclude());
4398 }
4399
4400 // Inserts a single Domain cookie that differs from
4401 // "PreexistingDomainHttps443" by port only.
AddDomainHttpsPort80Cookie()4402 void AddDomainHttpsPort80Cookie() {
4403 GURL::Replacements replace_port;
4404 replace_port.SetPortStr("80");
4405 GURL foo_made_80 = https_www_foo_.url().ReplaceComponents(replace_port);
4406
4407 auto differ_by_port_only = CanonicalCookie::CreateForTesting(
4408 foo_made_80,
4409 "A=InsertedDomainHttps80; Domain=" + https_www_foo_.domain(),
4410 base::Time::Now());
4411
4412 CookieAccessResult access_result = SetCanonicalCookieReturnAccessResult(
4413 cm_.get(), std::move(differ_by_port_only), foo_made_80,
4414 /*can_modify_httponly=*/true);
4415 ASSERT_TRUE(access_result.status.IsInclude());
4416 }
4417
4418 scoped_refptr<net::MockPersistentCookieStore> store_;
4419 std::unique_ptr<CookieMonster> cm_;
4420 base::test::ScopedFeatureList scoped_feature_list_;
4421 };
4422
4423 // Scheme binding disabled.
4424 // Port binding disabled.
4425 // Cookies that differ only in their scheme and/or port should overwrite the
4426 // preexisting cookies.
TEST_F(CookieMonsterTest_MaybeDeleteEquivalentCookieAndUpdateStatus,NoSchemeNoPort)4427 TEST_F(CookieMonsterTest_MaybeDeleteEquivalentCookieAndUpdateStatus,
4428 NoSchemeNoPort) {
4429 scoped_feature_list_.InitWithFeatures(
4430 {}, {net::features::kEnableSchemeBoundCookies,
4431 net::features::kEnablePortBoundCookies});
4432
4433 InitializeTest();
4434
4435 AddHttpPort443Cookie();
4436
4437 auto cookies = GetAllCookies(cm_.get());
4438 EXPECT_THAT(cookies,
4439 testing::UnorderedElementsAre(
4440 MatchesCookieNameValue("A", "InsertedHttp443"),
4441 MatchesCookieNameValue("A", "PreexistingDomainHttps443")));
4442
4443 AddHttpsPort80Cookie();
4444
4445 cookies = GetAllCookies(cm_.get());
4446 EXPECT_THAT(cookies,
4447 testing::UnorderedElementsAre(
4448 MatchesCookieNameValue("A", "InsertedHttps80"),
4449 MatchesCookieNameValue("A", "PreexistingDomainHttps443")));
4450
4451 AddDomainHttpsPort80Cookie();
4452
4453 cookies = GetAllCookies(cm_.get());
4454 EXPECT_THAT(cookies,
4455 testing::UnorderedElementsAre(
4456 MatchesCookieNameValue("A", "InsertedHttps80"),
4457 MatchesCookieNameValue("A", "InsertedDomainHttps80")));
4458 }
4459
4460 // Scheme binding enabled.
4461 // Port binding disabled.
4462 // Cookies that differ in scheme are separate, cookies that differ only by
4463 // port should be overwritten.
TEST_F(CookieMonsterTest_MaybeDeleteEquivalentCookieAndUpdateStatus,YesSchemeNoPort)4464 TEST_F(CookieMonsterTest_MaybeDeleteEquivalentCookieAndUpdateStatus,
4465 YesSchemeNoPort) {
4466 scoped_feature_list_.InitWithFeatures(
4467 {net::features::kEnableSchemeBoundCookies},
4468 {net::features::kEnablePortBoundCookies});
4469
4470 InitializeTest();
4471
4472 AddHttpPort443Cookie();
4473
4474 auto cookies = GetAllCookies(cm_.get());
4475 EXPECT_THAT(cookies,
4476 testing::UnorderedElementsAre(
4477 MatchesCookieNameValue("A", "PreexistingHttps443"),
4478 MatchesCookieNameValue("A", "InsertedHttp443"),
4479 MatchesCookieNameValue("A", "PreexistingDomainHttps443")));
4480
4481 AddHttpsPort80Cookie();
4482
4483 cookies = GetAllCookies(cm_.get());
4484 EXPECT_THAT(cookies,
4485 testing::UnorderedElementsAre(
4486 MatchesCookieNameValue("A", "InsertedHttp443"),
4487 MatchesCookieNameValue("A", "InsertedHttps80"),
4488 MatchesCookieNameValue("A", "PreexistingDomainHttps443")));
4489
4490 AddDomainHttpsPort80Cookie();
4491
4492 cookies = GetAllCookies(cm_.get());
4493 EXPECT_THAT(cookies,
4494 testing::UnorderedElementsAre(
4495 MatchesCookieNameValue("A", "InsertedHttp443"),
4496 MatchesCookieNameValue("A", "InsertedHttps80"),
4497 MatchesCookieNameValue("A", "InsertedDomainHttps80")));
4498 }
4499
4500 // Scheme binding disabled.
4501 // Port binding enabled.
4502 // Cookies that differ only by scheme and Domain cookies that differ only by
4503 // port should be overwritten. Host cookies that differ only by port are
4504 // separate.
TEST_F(CookieMonsterTest_MaybeDeleteEquivalentCookieAndUpdateStatus,NoSchemeYesPort)4505 TEST_F(CookieMonsterTest_MaybeDeleteEquivalentCookieAndUpdateStatus,
4506 NoSchemeYesPort) {
4507 scoped_feature_list_.InitWithFeatures(
4508 {net::features::kEnablePortBoundCookies},
4509 {net::features::kEnableSchemeBoundCookies});
4510
4511 InitializeTest();
4512
4513 AddHttpPort443Cookie();
4514
4515 auto cookies = GetAllCookies(cm_.get());
4516 EXPECT_THAT(cookies,
4517 testing::UnorderedElementsAre(
4518 MatchesCookieNameValue("A", "InsertedHttp443"),
4519 MatchesCookieNameValue("A", "PreexistingDomainHttps443")));
4520
4521 AddHttpsPort80Cookie();
4522
4523 cookies = GetAllCookies(cm_.get());
4524 EXPECT_THAT(cookies,
4525 testing::UnorderedElementsAre(
4526 MatchesCookieNameValue("A", "InsertedHttp443"),
4527 MatchesCookieNameValue("A", "InsertedHttps80"),
4528 MatchesCookieNameValue("A", "PreexistingDomainHttps443")));
4529
4530 AddDomainHttpsPort80Cookie();
4531
4532 cookies = GetAllCookies(cm_.get());
4533 EXPECT_THAT(cookies,
4534 testing::UnorderedElementsAre(
4535 MatchesCookieNameValue("A", "InsertedHttp443"),
4536 MatchesCookieNameValue("A", "InsertedHttps80"),
4537 MatchesCookieNameValue("A", "InsertedDomainHttps80")));
4538 }
4539
4540 // Scheme binding enabled.
4541 // Port binding enabled.
4542 // Cookies that differ by port or scheme are separate. Except for Domain cookies
4543 // which will be overwritten if they differ only by port.
TEST_F(CookieMonsterTest_MaybeDeleteEquivalentCookieAndUpdateStatus,YesSchemeYesPort)4544 TEST_F(CookieMonsterTest_MaybeDeleteEquivalentCookieAndUpdateStatus,
4545 YesSchemeYesPort) {
4546 scoped_feature_list_.InitWithFeatures(
4547 {net::features::kEnableSchemeBoundCookies,
4548 net::features::kEnablePortBoundCookies},
4549 {});
4550
4551 InitializeTest();
4552
4553 AddHttpPort443Cookie();
4554
4555 auto cookies = GetAllCookies(cm_.get());
4556 EXPECT_THAT(cookies,
4557 testing::UnorderedElementsAre(
4558 MatchesCookieNameValue("A", "PreexistingHttps443"),
4559 MatchesCookieNameValue("A", "InsertedHttp443"),
4560 MatchesCookieNameValue("A", "PreexistingDomainHttps443")));
4561
4562 AddHttpsPort80Cookie();
4563
4564 cookies = GetAllCookies(cm_.get());
4565 EXPECT_THAT(cookies,
4566 testing::UnorderedElementsAre(
4567 MatchesCookieNameValue("A", "PreexistingHttps443"),
4568 MatchesCookieNameValue("A", "InsertedHttp443"),
4569 MatchesCookieNameValue("A", "InsertedHttps80"),
4570 MatchesCookieNameValue("A", "PreexistingDomainHttps443")));
4571
4572 AddDomainHttpsPort80Cookie();
4573
4574 cookies = GetAllCookies(cm_.get());
4575 EXPECT_THAT(cookies,
4576 testing::UnorderedElementsAre(
4577 MatchesCookieNameValue("A", "PreexistingHttps443"),
4578 MatchesCookieNameValue("A", "InsertedHttp443"),
4579 MatchesCookieNameValue("A", "InsertedHttps80"),
4580 MatchesCookieNameValue("A", "InsertedDomainHttps80")));
4581 }
4582
4583 // Tests that only the correct set of (potentially duplicate) cookies are loaded
4584 // from the backend store depending on the state of the origin-bound feature
4585 // flags.
4586 class CookieMonsterTest_StoreLoadedCookies : public CookieMonsterTest {
4587 public:
InitializeTest()4588 void InitializeTest() {
4589 store_ = base::MakeRefCounted<MockPersistentCookieStore>();
4590 cm_ = std::make_unique<CookieMonster>(store_.get(), net::NetLog::Get());
4591
4592 base::Time most_recent_time = base::Time::Now();
4593 base::Time middle_time = most_recent_time - base::Minutes(1);
4594 base::Time least_recent_time = middle_time - base::Minutes(1);
4595
4596 auto basic_cookie = CanonicalCookie::CreateForTesting(
4597 https_www_foo_.url(), "A=basic", base::Time::Now());
4598
4599 // When there are duplicate cookies the most recent one is kept. So, this
4600 // one.
4601 basic_cookie->SetCreationDate(most_recent_time);
4602 starting_list_.push_back(std::move(basic_cookie));
4603
4604 GURL::Replacements replace_scheme;
4605 replace_scheme.SetSchemeStr("http");
4606 // We need to explicitly set the existing port, otherwise GURL will
4607 // implicitly take the port of the new scheme. I.e.: We'll inadvertently
4608 // change the port to 80.
4609 replace_scheme.SetPortStr("443");
4610 GURL foo_with_http = https_www_foo_.url().ReplaceComponents(replace_scheme);
4611
4612 auto http_cookie = CanonicalCookie::CreateForTesting(
4613 foo_with_http, "A=http", base::Time::Now());
4614
4615 http_cookie->SetCreationDate(middle_time);
4616 starting_list_.push_back(std::move(http_cookie));
4617
4618 GURL::Replacements replace_port;
4619 replace_port.SetPortStr("450");
4620 GURL foo_with_450 = https_www_foo_.url().ReplaceComponents(replace_port);
4621
4622 auto port_450_cookie = CanonicalCookie::CreateForTesting(
4623 foo_with_450, "A=port450", base::Time::Now());
4624 port_450_cookie->SetCreationDate(least_recent_time);
4625 starting_list_.push_back(std::move(port_450_cookie));
4626
4627 auto basic_domain_cookie = CanonicalCookie::CreateForTesting(
4628 https_www_foo_.url(),
4629 "A=basic_domain; Domain=" + https_www_foo_.domain(), base::Time::Now());
4630
4631 // When there are duplicate domain cookies the most recent one is kept. So,
4632 // this one.
4633 basic_domain_cookie->SetCreationDate(most_recent_time);
4634 starting_list_.push_back(std::move(basic_domain_cookie));
4635
4636 auto http_domain_cookie = CanonicalCookie::CreateForTesting(
4637 foo_with_http, "A=http_domain; Domain=" + https_www_foo_.domain(),
4638 base::Time::Now());
4639
4640 http_domain_cookie->SetCreationDate(middle_time);
4641 starting_list_.push_back(std::move(http_domain_cookie));
4642
4643 // Domain cookies don't consider the port, so this cookie should always be
4644 // considered a duplicate.
4645 auto port_450_domain_cookie = CanonicalCookie::CreateForTesting(
4646 foo_with_450, "A=port450_domain; Domain=" + https_www_foo_.domain(),
4647 base::Time::Now());
4648 port_450_domain_cookie->SetCreationDate(least_recent_time);
4649 starting_list_.push_back(std::move(port_450_domain_cookie));
4650
4651 ASSERT_EQ(starting_list_.size(), 6UL);
4652 }
4653
4654 scoped_refptr<net::MockPersistentCookieStore> store_;
4655 std::unique_ptr<CookieMonster> cm_;
4656 std::vector<std::unique_ptr<CanonicalCookie>> starting_list_;
4657 base::test::ScopedFeatureList scoped_feature_list_;
4658 };
4659
4660 // Scheme binding disabled.
4661 // Port binding disabled.
4662 // Only 2 cookies, the most recently created, should exist.
TEST_F(CookieMonsterTest_StoreLoadedCookies,NoSchemeNoPort)4663 TEST_F(CookieMonsterTest_StoreLoadedCookies, NoSchemeNoPort) {
4664 scoped_feature_list_.InitWithFeatures(
4665 {}, {net::features::kEnableSchemeBoundCookies,
4666 net::features::kEnablePortBoundCookies});
4667 InitializeTest();
4668 cm_->StoreLoadedCookies(std::move(starting_list_));
4669 auto cookies = GetAllCookies(cm_.get());
4670
4671 EXPECT_THAT(cookies, testing::UnorderedElementsAre(
4672 MatchesCookieNameValue("A", "basic"),
4673 MatchesCookieNameValue("A", "basic_domain")));
4674 }
4675
4676 // Scheme binding enabled.
4677 // Port binding disabled.
4678 // 4 Cookies should exist.
TEST_F(CookieMonsterTest_StoreLoadedCookies,YesSchemeNoPort)4679 TEST_F(CookieMonsterTest_StoreLoadedCookies, YesSchemeNoPort) {
4680 scoped_feature_list_.InitWithFeatures(
4681 {net::features::kEnableSchemeBoundCookies},
4682 {net::features::kEnablePortBoundCookies});
4683 InitializeTest();
4684 cm_->StoreLoadedCookies(std::move(starting_list_));
4685 auto cookies = GetAllCookies(cm_.get());
4686
4687 EXPECT_THAT(cookies, testing::UnorderedElementsAre(
4688 MatchesCookieNameValue("A", "basic"),
4689 MatchesCookieNameValue("A", "http"),
4690 MatchesCookieNameValue("A", "basic_domain"),
4691 MatchesCookieNameValue("A", "http_domain")));
4692 }
4693
4694 // Scheme binding disabled.
4695 // Port binding enabled.
4696 // 3 Cookies should exist.
TEST_F(CookieMonsterTest_StoreLoadedCookies,NoSchemeYesPort)4697 TEST_F(CookieMonsterTest_StoreLoadedCookies, NoSchemeYesPort) {
4698 scoped_feature_list_.InitWithFeatures(
4699 {net::features::kEnablePortBoundCookies},
4700 {net::features::kEnableSchemeBoundCookies});
4701 InitializeTest();
4702 cm_->StoreLoadedCookies(std::move(starting_list_));
4703 auto cookies = GetAllCookies(cm_.get());
4704
4705 // Domain cookies aren't bound to a port by design, so duplicates across ports
4706 // should still be removed. I.e.: "A=port450_domain"
4707 EXPECT_THAT(cookies, testing::UnorderedElementsAre(
4708 MatchesCookieNameValue("A", "basic"),
4709 MatchesCookieNameValue("A", "port450"),
4710 MatchesCookieNameValue("A", "basic_domain")));
4711 }
4712
4713 // Scheme binding enabled.
4714 // Port binding enabled.
4715 // 5 Cookies should exist.
TEST_F(CookieMonsterTest_StoreLoadedCookies,YesSchemeYesPort)4716 TEST_F(CookieMonsterTest_StoreLoadedCookies, YesSchemeYesPort) {
4717 scoped_feature_list_.InitWithFeatures(
4718 {net::features::kEnablePortBoundCookies,
4719 net::features::kEnableSchemeBoundCookies},
4720 {});
4721
4722 InitializeTest();
4723 cm_->StoreLoadedCookies(std::move(starting_list_));
4724 auto cookies = GetAllCookies(cm_.get());
4725
4726 // Domain cookies aren't bound to a port by design, so duplicates across ports
4727 // should still be removed. I.e.: "A=port450_domain"
4728 EXPECT_THAT(cookies, testing::UnorderedElementsAre(
4729 MatchesCookieNameValue("A", "basic"),
4730 MatchesCookieNameValue("A", "http"),
4731 MatchesCookieNameValue("A", "port450"),
4732 MatchesCookieNameValue("A", "basic_domain"),
4733 MatchesCookieNameValue("A", "http_domain")));
4734 }
4735
4736 // Test skipping a cookie in MaybeDeleteEquivalentCookieAndUpdateStatus for
4737 // multiple reasons (Secure and HttpOnly).
TEST_F(CookieMonsterTest,SkipDontOverwriteForMultipleReasons)4738 TEST_F(CookieMonsterTest, SkipDontOverwriteForMultipleReasons) {
4739 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
4740 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
4741
4742 // Set a secure, httponly cookie from a secure origin
4743 auto preexisting_cookie = CanonicalCookie::CreateForTesting(
4744 https_www_foo_.url(), "A=B;Secure;HttpOnly", base::Time::Now());
4745 CookieAccessResult access_result = SetCanonicalCookieReturnAccessResult(
4746 cm.get(), std::move(preexisting_cookie), https_www_foo_.url(),
4747 true /* can_modify_httponly */);
4748 ASSERT_TRUE(access_result.status.IsInclude());
4749
4750 // Attempt to set a new cookie with the same name that is not Secure or
4751 // Httponly from an insecure scheme.
4752 auto cookie = CanonicalCookie::CreateForTesting(http_www_foo_.url(), "A=B",
4753 base::Time::Now());
4754 access_result = SetCanonicalCookieReturnAccessResult(
4755 cm.get(), std::move(cookie), http_www_foo_.url(),
4756 false /* can_modify_httponly */);
4757 EXPECT_TRUE(access_result.status.HasExactlyExclusionReasonsForTesting(
4758 {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE,
4759 CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY}));
4760
4761 auto entries = net_log_.GetEntries();
4762 ExpectLogContainsSomewhere(
4763 entries, 0, NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_SECURE,
4764 NetLogEventPhase::NONE);
4765 ExpectLogContainsSomewhere(
4766 entries, 0, NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_HTTPONLY,
4767 NetLogEventPhase::NONE);
4768 }
4769
4770 // Test that when we check for equivalent cookies, we don't remove any if the
4771 // cookie should not be set.
TEST_F(CookieMonsterTest,DontDeleteEquivalentCookieIfSetIsRejected)4772 TEST_F(CookieMonsterTest, DontDeleteEquivalentCookieIfSetIsRejected) {
4773 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
4774 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
4775
4776 auto preexisting_cookie = CanonicalCookie::CreateForTesting(
4777 http_www_foo_.url(), "cookie=foo", base::Time::Now());
4778 CookieAccessResult access_result = SetCanonicalCookieReturnAccessResult(
4779 cm.get(), std::move(preexisting_cookie), http_www_foo_.url(),
4780 false /* can_modify_httponly */);
4781 ASSERT_TRUE(access_result.status.IsInclude());
4782
4783 auto bad_cookie = CanonicalCookie::CreateForTesting(
4784 http_www_foo_.url(), "cookie=bar;secure", base::Time::Now());
4785 CookieAccessResult access_result2 = SetCanonicalCookieReturnAccessResult(
4786 cm.get(), std::move(bad_cookie), http_www_foo_.url(),
4787 false /* can_modify_httponly */);
4788 EXPECT_TRUE(access_result2.status.HasExactlyExclusionReasonsForTesting(
4789 {CookieInclusionStatus::EXCLUDE_SECURE_ONLY}));
4790
4791 // Check that the original cookie is still there.
4792 EXPECT_EQ("cookie=foo", GetCookies(cm.get(), https_www_foo_.url()));
4793 }
4794
TEST_F(CookieMonsterTest,SetSecureCookies)4795 TEST_F(CookieMonsterTest, SetSecureCookies) {
4796 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
4797
4798 GURL http_url("http://www.foo.com");
4799 GURL http_superdomain_url("http://foo.com");
4800 GURL https_url("https://www.foo.com");
4801 GURL https_foo_url("https://www.foo.com/foo");
4802 GURL http_foo_url("http://www.foo.com/foo");
4803
4804 // A non-secure cookie can be created from either a URL with a secure or
4805 // insecure scheme.
4806 EXPECT_TRUE(
4807 CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C;").IsInclude());
4808 EXPECT_TRUE(
4809 CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B;").IsInclude());
4810
4811 // A secure cookie cannot be set from a URL with an insecure scheme.
4812 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=B; Secure")
4813 .HasExactlyExclusionReasonsForTesting(
4814 {CookieInclusionStatus::EXCLUDE_SECURE_ONLY}));
4815
4816 // A secure cookie can be set from a URL with a secure scheme.
4817 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure")
4818 .IsInclude());
4819
4820 // If a non-secure cookie is created from a URL with an insecure scheme, and a
4821 // secure cookie with the same name already exists, do not update the cookie.
4822 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure")
4823 .IsInclude());
4824 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C;")
4825 .HasExactlyExclusionReasonsForTesting(
4826 {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE}));
4827
4828 // If a non-secure cookie is created from a URL with an secure scheme, and a
4829 // secure cookie with the same name already exists, update the cookie.
4830 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure")
4831 .IsInclude());
4832 EXPECT_TRUE(
4833 CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=C;").IsInclude());
4834
4835 // If a non-secure cookie is created from a URL with an insecure scheme, and
4836 // a secure cookie with the same name already exists, do not update the cookie
4837 // if the new cookie's path matches the existing cookie's path.
4838 //
4839 // With an existing cookie whose path is '/', a cookie with the same name
4840 // cannot be set on the same domain, regardless of path:
4841 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure")
4842 .IsInclude());
4843 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C; path=/")
4844 .HasExactlyExclusionReasonsForTesting(
4845 {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE}));
4846 EXPECT_TRUE(
4847 CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C; path=/my/path")
4848 .HasExactlyExclusionReasonsForTesting(
4849 {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE}));
4850
4851 // But if the existing cookie has a path somewhere under the root, cookies
4852 // with the same name may be set for paths which don't overlap the existing
4853 // cookie.
4854 EXPECT_TRUE(
4855 SetCookie(cm.get(), https_url, "WITH_PATH=B; Secure; path=/my/path"));
4856 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "WITH_PATH=C")
4857 .IsInclude());
4858 EXPECT_TRUE(
4859 CreateAndSetCookieReturnStatus(cm.get(), http_url, "WITH_PATH=C; path=/")
4860 .IsInclude());
4861 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url,
4862 "WITH_PATH=C; path=/your/path")
4863 .IsInclude());
4864 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url,
4865 "WITH_PATH=C; path=/my/path")
4866 .HasExactlyExclusionReasonsForTesting(
4867 {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE}));
4868 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url,
4869 "WITH_PATH=C; path=/my/path/sub")
4870 .HasExactlyExclusionReasonsForTesting(
4871 {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE}));
4872
4873 DeleteAll(cm.get());
4874
4875 // If a secure cookie is set on top of an existing insecure cookie but with a
4876 // different path, both are retained.
4877 EXPECT_TRUE(
4878 CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=B; path=/foo")
4879 .IsInclude());
4880 EXPECT_TRUE(
4881 CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=C; Secure; path=/")
4882 .IsInclude());
4883
4884 // Querying from an insecure url gets only the insecure cookie, but querying
4885 // from a secure url returns both.
4886 EXPECT_EQ("A=B", GetCookies(cm.get(), http_foo_url));
4887 EXPECT_THAT(GetCookies(cm.get(), https_foo_url), testing::HasSubstr("A=B"));
4888 EXPECT_THAT(GetCookies(cm.get(), https_foo_url), testing::HasSubstr("A=C"));
4889
4890 // Attempting to set an insecure cookie (from an insecure scheme) that domain-
4891 // matches and path-matches the secure cookie fails i.e. the secure cookie is
4892 // left alone...
4893 EXPECT_TRUE(
4894 CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=D; path=/foo")
4895 .HasExactlyExclusionReasonsForTesting(
4896 {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE}));
4897 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=D; path=/")
4898 .HasExactlyExclusionReasonsForTesting(
4899 {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE}));
4900 EXPECT_THAT(GetCookies(cm.get(), https_foo_url), testing::HasSubstr("A=C"));
4901
4902 // ...but the original insecure cookie is still retained.
4903 EXPECT_THAT(GetCookies(cm.get(), https_foo_url), testing::HasSubstr("A=B"));
4904 EXPECT_THAT(GetCookies(cm.get(), https_foo_url),
4905 testing::Not(testing::HasSubstr("A=D")));
4906
4907 // Deleting the secure cookie leaves only the original insecure cookie.
4908 EXPECT_TRUE(CreateAndSetCookieReturnStatus(
4909 cm.get(), https_url,
4910 "A=C; path=/; Expires=Thu, 01-Jan-1970 00:00:01 GMT")
4911 .IsInclude());
4912 EXPECT_EQ("A=B", GetCookies(cm.get(), https_foo_url));
4913
4914 // If a non-secure cookie is created from a URL with an insecure scheme, and
4915 // a secure cookie with the same name already exists, if the domain strings
4916 // domain-match, do not update the cookie.
4917 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure")
4918 .IsInclude());
4919 EXPECT_TRUE(
4920 CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C; domain=foo.com")
4921 .HasExactlyExclusionReasonsForTesting(
4922 {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE}));
4923 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url,
4924 "A=C; domain=www.foo.com")
4925 .HasExactlyExclusionReasonsForTesting(
4926 {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE}));
4927
4928 // Since A=B was set above with no domain string, set a different cookie here
4929 // so the insecure examples aren't trying to overwrite the one above.
4930 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url,
4931 "B=C; Secure; domain=foo.com")
4932 .IsInclude());
4933 EXPECT_TRUE(
4934 CreateAndSetCookieReturnStatus(cm.get(), http_url, "B=D; domain=foo.com")
4935 .HasExactlyExclusionReasonsForTesting(
4936 {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE}));
4937 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "B=D")
4938 .HasExactlyExclusionReasonsForTesting(
4939 {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE}));
4940 EXPECT_TRUE(
4941 CreateAndSetCookieReturnStatus(cm.get(), http_superdomain_url, "B=D")
4942 .HasExactlyExclusionReasonsForTesting(
4943 {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE}));
4944
4945 // Verify that if an httponly version of the cookie exists, adding a Secure
4946 // version of the cookie still does not overwrite it.
4947 CookieOptions include_httponly = CookieOptions::MakeAllInclusive();
4948 EXPECT_TRUE(CreateAndSetCookie(cm.get(), https_url, "C=D; httponly",
4949 include_httponly));
4950 // Note that the lack of an explicit options object below uses the default,
4951 // which in this case includes "exclude_httponly = true".
4952 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "C=E; Secure")
4953 .HasExactlyExclusionReasonsForTesting(
4954 {CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY}));
4955
4956 auto entries = net_log_.GetEntries();
4957 ExpectLogContainsSomewhere(
4958 entries, 0, NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_HTTPONLY,
4959 NetLogEventPhase::NONE);
4960 }
4961
4962 // Tests the behavior of "Leave Secure Cookies Alone" in
4963 // MaybeDeleteEquivalentCookieAndUpdateStatus().
4964 // Check domain-match criterion: If either cookie domain matches the other,
4965 // don't set the insecure cookie.
TEST_F(CookieMonsterTest,LeaveSecureCookiesAlone_DomainMatch)4966 TEST_F(CookieMonsterTest, LeaveSecureCookiesAlone_DomainMatch) {
4967 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
4968
4969 // These domains will domain-match each other.
4970 const char* kRegistrableDomain = "foo.com";
4971 const char* kSuperdomain = "a.foo.com";
4972 const char* kDomain = "b.a.foo.com";
4973 const char* kSubdomain = "c.b.a.foo.com";
4974 // This domain does not match any, aside from the registrable domain.
4975 const char* kAnotherDomain = "z.foo.com";
4976
4977 for (const char* preexisting_cookie_host :
4978 {kRegistrableDomain, kSuperdomain, kDomain, kSubdomain}) {
4979 GURL preexisting_cookie_url(
4980 base::StrCat({url::kHttpsScheme, url::kStandardSchemeSeparator,
4981 preexisting_cookie_host}));
4982 for (const char* new_cookie_host :
4983 {kRegistrableDomain, kSuperdomain, kDomain, kSubdomain}) {
4984 GURL https_url(base::StrCat(
4985 {url::kHttpsScheme, url::kStandardSchemeSeparator, new_cookie_host}));
4986 GURL http_url(base::StrCat(
4987 {url::kHttpScheme, url::kStandardSchemeSeparator, new_cookie_host}));
4988
4989 // Preexisting Secure host and domain cookies.
4990 EXPECT_TRUE(CreateAndSetCookieReturnStatus(
4991 cm.get(), preexisting_cookie_url, "A=0; Secure")
4992 .IsInclude());
4993 EXPECT_TRUE(
4994 CreateAndSetCookieReturnStatus(
4995 cm.get(), preexisting_cookie_url,
4996 base::StrCat({"B=0; Secure; Domain=", preexisting_cookie_host}))
4997 .IsInclude());
4998
4999 // Don't set insecure cookie from an insecure URL if equivalent secure
5000 // cookie exists.
5001 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=1")
5002 .HasExactlyExclusionReasonsForTesting(
5003 {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE}))
5004 << "Insecure host cookie from " << http_url
5005 << " should not be set if equivalent secure host cookie from "
5006 << preexisting_cookie_url << " exists.";
5007 EXPECT_TRUE(CreateAndSetCookieReturnStatus(
5008 cm.get(), http_url,
5009 base::StrCat({"A=2; Domain=", new_cookie_host}))
5010 .HasExactlyExclusionReasonsForTesting(
5011 {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE}))
5012 << "Insecure domain cookie from " << http_url
5013 << " should not be set if equivalent secure host cookie from "
5014 << preexisting_cookie_url << " exists.";
5015 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "B=1")
5016 .HasExactlyExclusionReasonsForTesting(
5017 {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE}))
5018 << "Insecure host cookie from " << http_url
5019 << " should not be set if equivalent secure domain cookie from "
5020 << preexisting_cookie_url << " exists.";
5021 EXPECT_TRUE(CreateAndSetCookieReturnStatus(
5022 cm.get(), http_url,
5023 base::StrCat({"B=2; Domain=", new_cookie_host}))
5024 .HasExactlyExclusionReasonsForTesting(
5025 {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE}))
5026 << "Insecure domain cookie from " << http_url
5027 << " should not be set if equivalent secure domain cookie from "
5028 << preexisting_cookie_url << " exists.";
5029
5030 // Allow setting insecure cookie from a secure URL even if equivalent
5031 // secure cookie exists.
5032 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=3;")
5033 .IsInclude())
5034 << "Insecure host cookie from " << https_url
5035 << " can be set even if equivalent secure host cookie from "
5036 << preexisting_cookie_url << " exists.";
5037 EXPECT_TRUE(CreateAndSetCookieReturnStatus(
5038 cm.get(), https_url,
5039 base::StrCat({"A=4; Domain=", new_cookie_host}))
5040 .IsInclude())
5041 << "Insecure domain cookie from " << https_url
5042 << " can be set even if equivalent secure host cookie from "
5043 << preexisting_cookie_url << " exists.";
5044 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "B=3;")
5045 .IsInclude())
5046 << "Insecure host cookie from " << https_url
5047 << " can be set even if equivalent secure domain cookie from "
5048 << preexisting_cookie_url << " exists.";
5049 EXPECT_TRUE(CreateAndSetCookieReturnStatus(
5050 cm.get(), https_url,
5051 base::StrCat({"B=4; Domain=", new_cookie_host}))
5052 .IsInclude())
5053 << "Insecure domain cookie from " << https_url
5054 << " can be set even if equivalent secure domain cookie from "
5055 << preexisting_cookie_url << " exists.";
5056
5057 DeleteAll(cm.get());
5058 }
5059 }
5060
5061 // Test non-domain-matching case. These sets should all be allowed because the
5062 // cookie is not equivalent.
5063 GURL nonmatching_https_url(base::StrCat(
5064 {url::kHttpsScheme, url::kStandardSchemeSeparator, kAnotherDomain}));
5065
5066 for (const char* host : {kSuperdomain, kDomain, kSubdomain}) {
5067 GURL https_url(
5068 base::StrCat({url::kHttpsScheme, url::kStandardSchemeSeparator, host}));
5069 GURL http_url(
5070 base::StrCat({url::kHttpScheme, url::kStandardSchemeSeparator, host}));
5071
5072 // Preexisting Secure host and domain cookies.
5073 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), nonmatching_https_url,
5074 "A=0; Secure")
5075 .IsInclude());
5076 EXPECT_TRUE(CreateAndSetCookieReturnStatus(
5077 cm.get(), nonmatching_https_url,
5078 base::StrCat({"B=0; Secure; Domain=", kAnotherDomain}))
5079 .IsInclude());
5080
5081 // New cookie from insecure URL is set.
5082 EXPECT_TRUE(
5083 CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=1;").IsInclude())
5084 << "Insecure host cookie from " << http_url
5085 << " can be set even if equivalent secure host cookie from "
5086 << nonmatching_https_url << " exists.";
5087 EXPECT_TRUE(CreateAndSetCookieReturnStatus(
5088 cm.get(), http_url, base::StrCat({"A=2; Domain=", host}))
5089 .IsInclude())
5090 << "Insecure domain cookie from " << http_url
5091 << " can be set even if equivalent secure host cookie from "
5092 << nonmatching_https_url << " exists.";
5093 EXPECT_TRUE(
5094 CreateAndSetCookieReturnStatus(cm.get(), http_url, "B=1;").IsInclude())
5095 << "Insecure host cookie from " << http_url
5096 << " can be set even if equivalent secure domain cookie from "
5097 << nonmatching_https_url << " exists.";
5098 EXPECT_TRUE(CreateAndSetCookieReturnStatus(
5099 cm.get(), http_url, base::StrCat({"B=2; Domain=", host}))
5100 .IsInclude())
5101 << "Insecure domain cookie from " << http_url
5102 << " can be set even if equivalent secure domain cookie from "
5103 << nonmatching_https_url << " exists.";
5104
5105 // New cookie from secure URL is set.
5106 EXPECT_TRUE(
5107 CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=3;").IsInclude())
5108 << "Insecure host cookie from " << https_url
5109 << " can be set even if equivalent secure host cookie from "
5110 << nonmatching_https_url << " exists.";
5111 EXPECT_TRUE(CreateAndSetCookieReturnStatus(
5112 cm.get(), https_url, base::StrCat({"A=4; Domain=", host}))
5113 .IsInclude())
5114 << "Insecure domain cookie from " << https_url
5115 << " can be set even if equivalent secure host cookie from "
5116 << nonmatching_https_url << " exists.";
5117 EXPECT_TRUE(
5118 CreateAndSetCookieReturnStatus(cm.get(), https_url, "B=3;").IsInclude())
5119 << "Insecure host cookie from " << https_url
5120 << " can be set even if equivalent secure host cookie from "
5121 << nonmatching_https_url << " exists.";
5122 EXPECT_TRUE(CreateAndSetCookieReturnStatus(
5123 cm.get(), https_url, base::StrCat({"B=4; Domain=", host}))
5124 .IsInclude())
5125 << "Insecure domain cookie from " << https_url
5126 << " can be set even if equivalent secure host cookie from "
5127 << nonmatching_https_url << " exists.";
5128
5129 DeleteAll(cm.get());
5130 }
5131 }
5132
5133 // Tests the behavior of "Leave Secure Cookies Alone" in
5134 // MaybeDeleteEquivalentCookieAndUpdateStatus().
5135 // Check path-match criterion: If the new cookie is for the same path or a
5136 // subdirectory of the preexisting cookie's path, don't set the new cookie.
TEST_F(CookieMonsterTest,LeaveSecureCookiesAlone_PathMatch)5137 TEST_F(CookieMonsterTest, LeaveSecureCookiesAlone_PathMatch) {
5138 auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
5139
5140 // A path that is later in this list will path-match all the paths before it.
5141 const char* kPaths[] = {"/", "/1", "/1/2", "/1/2/3"};
5142 // This path does not match any, aside from the root path.
5143 const char* kOtherDirectory = "/9";
5144
5145 for (int preexisting_cookie_path_index = 0; preexisting_cookie_path_index < 4;
5146 ++preexisting_cookie_path_index) {
5147 const char* preexisting_cookie_path = kPaths[preexisting_cookie_path_index];
5148 GURL preexisting_cookie_url(
5149 base::StrCat({url::kHttpsScheme, url::kStandardSchemeSeparator,
5150 "a.foo.com", preexisting_cookie_path}));
5151 for (int new_cookie_path_index = 0; new_cookie_path_index < 4;
5152 ++new_cookie_path_index) {
5153 const char* new_cookie_path = kPaths[new_cookie_path_index];
5154 bool should_path_match =
5155 new_cookie_path_index >= preexisting_cookie_path_index;
5156 GURL https_url(
5157 base::StrCat({url::kHttpsScheme, url::kStandardSchemeSeparator,
5158 "a.foo.com", new_cookie_path}));
5159 GURL http_url(
5160 base::StrCat({url::kHttpScheme, url::kStandardSchemeSeparator,
5161 "a.foo.com", new_cookie_path}));
5162
5163 // Preexisting Secure cookie.
5164 EXPECT_TRUE(
5165 CreateAndSetCookieReturnStatus(
5166 cm.get(), preexisting_cookie_url,
5167 base::StrCat({"A=0; Secure; Path=", preexisting_cookie_path}))
5168 .IsInclude());
5169
5170 // Don't set insecure cookie from an insecure URL if equivalent secure
5171 // cookie exists.
5172 CookieInclusionStatus set = CreateAndSetCookieReturnStatus(
5173 cm.get(), http_url, base::StrCat({"A=1; Path=", new_cookie_path}));
5174 EXPECT_TRUE(should_path_match
5175 ? set.HasExactlyExclusionReasonsForTesting(
5176 {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})
5177 : set.IsInclude())
5178 << "Insecure cookie from " << http_url << " should "
5179 << (should_path_match ? "not " : "")
5180 << "be set if equivalent secure cookie from "
5181 << preexisting_cookie_url << " exists.";
5182
5183 // Allow setting insecure cookie from a secure URL even if equivalent
5184 // secure cookie exists.
5185 EXPECT_TRUE(CreateAndSetCookieReturnStatus(
5186 cm.get(), https_url,
5187 base::StrCat({"A=2; Path=", new_cookie_path}))
5188 .IsInclude())
5189 << "Insecure cookie from " << http_url
5190 << " can be set even if equivalent secure cookie from "
5191 << preexisting_cookie_url << " exists.";
5192
5193 DeleteAll(cm.get());
5194 }
5195 }
5196
5197 // Test non-matching-path case. These sets should all be allowed because the
5198 // cookie is not equivalent.
5199 GURL nonmatching_https_url(
5200 base::StrCat({url::kHttpsScheme, url::kStandardSchemeSeparator,
5201 "a.foo.com", kOtherDirectory}));
5202
5203 for (int new_cookie_path_index = 1; new_cookie_path_index < 4;
5204 ++new_cookie_path_index) {
5205 const char* new_cookie_path = kPaths[new_cookie_path_index];
5206 GURL https_url(base::StrCat(
5207 {url::kHttpsScheme, url::kStandardSchemeSeparator, new_cookie_path}));
5208 GURL http_url(base::StrCat(
5209 {url::kHttpScheme, url::kStandardSchemeSeparator, new_cookie_path}));
5210
5211 // Preexisting Secure cookie.
5212 EXPECT_TRUE(CreateAndSetCookieReturnStatus(
5213 cm.get(), nonmatching_https_url,
5214 base::StrCat({"A=0; Secure; Path=", kOtherDirectory}))
5215 .IsInclude());
5216
5217 // New cookie from insecure URL is set.
5218 EXPECT_TRUE(
5219 CreateAndSetCookieReturnStatus(
5220 cm.get(), http_url, base::StrCat({"A=1; Path=", new_cookie_path}))
5221 .IsInclude())
5222 << "Insecure cookie from " << http_url
5223 << " can be set even if equivalent secure cookie from "
5224 << nonmatching_https_url << " exists.";
5225
5226 // New cookie from secure URL is set.
5227 EXPECT_TRUE(
5228 CreateAndSetCookieReturnStatus(
5229 cm.get(), https_url, base::StrCat({"A=1; Path=", new_cookie_path}))
5230 .IsInclude())
5231 << "Insecure cookie from " << https_url
5232 << " can be set even if equivalent secure cookie from "
5233 << nonmatching_https_url << " exists.";
5234 }
5235 }
5236
5237 // Tests for behavior for strict secure cookies.
TEST_F(CookieMonsterTest,EvictSecureCookies)5238 TEST_F(CookieMonsterTest, EvictSecureCookies) {
5239 // Hard-coding limits in the test, but use DCHECK_EQ to enforce constraint.
5240 DCHECK_EQ(180U, CookieMonster::kDomainMaxCookies);
5241 DCHECK_EQ(150U, CookieMonster::kDomainMaxCookies -
5242 CookieMonster::kDomainPurgeCookies);
5243 DCHECK_EQ(3300U, CookieMonster::kMaxCookies);
5244 DCHECK_EQ(30, CookieMonster::kSafeFromGlobalPurgeDays);
5245
5246 // If secure cookies for one domain hit the per domain limit (180), a
5247 // non-secure cookie will not evict them (and, in fact, the non-secure cookie
5248 // will be removed right after creation).
5249 const CookiesEntry test1[] = {{180U, true}, {1U, false}};
5250 TestSecureCookieEviction(test1, 150U, 0U, nullptr);
5251
5252 // If non-secure cookies for one domain hit the per domain limit (180), the
5253 // creation of secure cookies will evict the non-secure cookies first, making
5254 // room for the secure cookies.
5255 const CookiesEntry test2[] = {{180U, false}, {20U, true}};
5256 TestSecureCookieEviction(test2, 20U, 149U, nullptr);
5257
5258 // If secure cookies for one domain go past the per domain limit (180), they
5259 // will be evicted as normal by the per domain purge amount (30) down to a
5260 // lower amount (150), and then will continue to create the remaining cookies
5261 // (19 more to 169).
5262 const CookiesEntry test3[] = {{200U, true}};
5263 TestSecureCookieEviction(test3, 169U, 0U, nullptr);
5264
5265 // If a non-secure cookie is created, and a number of secure cookies exceeds
5266 // the per domain limit (18), the total cookies will be evicted down to a
5267 // lower amount (150), enforcing the eviction of the non-secure cookie, and
5268 // the remaining secure cookies will be created (another 19 to 169).
5269 const CookiesEntry test4[] = {{1U, false}, {199U, true}};
5270 TestSecureCookieEviction(test4, 169U, 0U, nullptr);
5271
5272 // If an even number of non-secure and secure cookies are created below the
5273 // per-domain limit (180), all will be created and none evicted.
5274 const CookiesEntry test5[] = {{75U, false}, {75U, true}};
5275 TestSecureCookieEviction(test5, 75U, 75U, nullptr);
5276
5277 // If the same number of secure and non-secure cookies are created (50 each)
5278 // below the per domain limit (180), and then another set of secure cookies
5279 // are created to bring the total above the per-domain limit, all secure
5280 // cookies will be retained, and the non-secure cookies will be culled down
5281 // to the limit.
5282 const CookiesEntry test6[] = {{50U, true}, {50U, false}, {81U, true}};
5283 TestSecureCookieEviction(test6, 131U, 19U, nullptr);
5284
5285 // If the same number of non-secure and secure cookies are created (50 each)
5286 // below the per domain limit (180), and then another set of non-secure
5287 // cookies are created to bring the total above the per-domain limit, all
5288 // secure cookies will be retained, and the non-secure cookies will be culled
5289 // down to the limit.
5290 const CookiesEntry test7[] = {{50U, false}, {50U, true}, {81U, false}};
5291 TestSecureCookieEviction(test7, 50U, 100U, nullptr);
5292
5293 // If the same number of non-secure and secure cookies are created (50 each)
5294 // below the per domain limit (180), and then another set of non-secure
5295 // cookies are created to bring the total above the per-domain limit, all
5296 // secure cookies will be retained, and the non-secure cookies will be culled
5297 // down to the limit, then the remaining non-secure cookies will be created
5298 // (9).
5299 const CookiesEntry test8[] = {{50U, false}, {50U, true}, {90U, false}};
5300 TestSecureCookieEviction(test8, 50U, 109U, nullptr);
5301
5302 // If a number of non-secure cookies are created on other hosts (20) and are
5303 // past the global 'safe' date, and then the number of non-secure cookies for
5304 // a single domain are brought to the per-domain limit (180), followed by
5305 // another set of secure cookies on that same domain (20), all the secure
5306 // cookies for that domain should be retained, while the non-secure should be
5307 // culled down to the per-domain limit. The non-secure cookies for other
5308 // domains should remain untouched.
5309 const CookiesEntry test9[] = {{180U, false}, {20U, true}};
5310 const AltHosts test9_alt_hosts(0, 20);
5311 TestSecureCookieEviction(test9, 20U, 169U, &test9_alt_hosts);
5312
5313 // If a number of secure cookies are created on other hosts and hit the global
5314 // cookie limit (3300) and are past the global 'safe' date, and then a single
5315 // non-secure cookie is created now, the secure cookies are removed so that
5316 // the global total number of cookies is at the global purge goal (3000), but
5317 // the non-secure cookie is not evicted since it is too young.
5318 const CookiesEntry test10[] = {{1U, false}};
5319 const AltHosts test10_alt_hosts(3300, 0);
5320 TestSecureCookieEviction(test10, 2999U, 1U, &test10_alt_hosts);
5321
5322 // If a number of non-secure cookies are created on other hosts and hit the
5323 // global cookie limit (3300) and are past the global 'safe' date, and then a
5324 // single non-secure cookie is created now, the non-secure cookies are removed
5325 // so that the global total number of cookies is at the global purge goal
5326 // (3000).
5327 const CookiesEntry test11[] = {{1U, false}};
5328 const AltHosts test11_alt_hosts(0, 3300);
5329 TestSecureCookieEviction(test11, 0U, 3000U, &test11_alt_hosts);
5330
5331 // If a number of non-secure cookies are created on other hosts and hit the
5332 // global cookie limit (3300) and are past the global 'safe' date, and then a
5333 // single ecure cookie is created now, the non-secure cookies are removed so
5334 // that the global total number of cookies is at the global purge goal (3000),
5335 // but the secure cookie is not evicted.
5336 const CookiesEntry test12[] = {{1U, true}};
5337 const AltHosts test12_alt_hosts(0, 3300);
5338 TestSecureCookieEviction(test12, 1U, 2999U, &test12_alt_hosts);
5339
5340 // If a total number of secure and non-secure cookies are created on other
5341 // hosts and hit the global cookie limit (3300) and are past the global 'safe'
5342 // date, and then a single non-secure cookie is created now, the global
5343 // non-secure cookies are removed so that the global total number of cookies
5344 // is at the global purge goal (3000), but the secure cookies are not evicted.
5345 const CookiesEntry test13[] = {{1U, false}};
5346 const AltHosts test13_alt_hosts(1500, 1800);
5347 TestSecureCookieEviction(test13, 1500U, 1500, &test13_alt_hosts);
5348
5349 // If a total number of secure and non-secure cookies are created on other
5350 // hosts and hit the global cookie limit (3300) and are past the global 'safe'
5351 // date, and then a single secure cookie is created now, the global non-secure
5352 // cookies are removed so that the global total number of cookies is at the
5353 // global purge goal (3000), but the secure cookies are not evicted.
5354 const CookiesEntry test14[] = {{1U, true}};
5355 const AltHosts test14_alt_hosts(1500, 1800);
5356 TestSecureCookieEviction(test14, 1501U, 1499, &test14_alt_hosts);
5357 }
5358
5359 // Tests that strict secure cookies doesn't trip equivalent cookie checks
5360 // accidentally. Regression test for https://crbug.com/569943.
TEST_F(CookieMonsterTest,EquivalentCookies)5361 TEST_F(CookieMonsterTest, EquivalentCookies) {
5362 auto cm = std::make_unique<CookieMonster>(nullptr, nullptr);
5363 GURL http_url("http://www.foo.com");
5364 GURL http_superdomain_url("http://foo.com");
5365 GURL https_url("https://www.foo.com");
5366
5367 // Tests that non-equivalent cookies because of the path attribute can be set
5368 // successfully.
5369 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure")
5370 .IsInclude());
5371 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url,
5372 "A=C; path=/some/other/path")
5373 .IsInclude());
5374 EXPECT_FALSE(SetCookie(cm.get(), http_url, "A=D; path=/some/other/path"));
5375
5376 // Tests that non-equivalent cookies because of the domain attribute can be
5377 // set successfully.
5378 EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure")
5379 .IsInclude());
5380 EXPECT_TRUE(
5381 CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=C; domain=foo.com")
5382 .IsInclude());
5383 EXPECT_FALSE(SetCookie(cm.get(), http_url, "A=D; domain=foo.com"));
5384 }
5385
TEST_F(CookieMonsterTest,SetCanonicalCookieDoesNotBlockForLoadAll)5386 TEST_F(CookieMonsterTest, SetCanonicalCookieDoesNotBlockForLoadAll) {
5387 scoped_refptr<MockPersistentCookieStore> persistent_store =
5388 base::MakeRefCounted<MockPersistentCookieStore>();
5389 // Collect load commands so we have control over their execution.
5390 persistent_store->set_store_load_commands(true);
5391 CookieMonster cm(persistent_store.get(), nullptr);
5392
5393 // Start of a canonical cookie set.
5394 ResultSavingCookieCallback<CookieAccessResult> callback_set;
5395 GURL cookie_url("http://a.com/");
5396 cm.SetCanonicalCookieAsync(
5397 CanonicalCookie::CreateForTesting(cookie_url, "A=B", base::Time::Now()),
5398 cookie_url, CookieOptions::MakeAllInclusive(),
5399 callback_set.MakeCallback());
5400
5401 // Get cookies for a different URL.
5402 GetCookieListCallback callback_get;
5403 cm.GetCookieListWithOptionsAsync(
5404 GURL("http://b.com/"), CookieOptions::MakeAllInclusive(),
5405 CookiePartitionKeyCollection(), callback_get.MakeCallback());
5406
5407 // Now go through the store commands, and execute individual loads.
5408 const auto& commands = persistent_store->commands();
5409 for (size_t i = 0; i < commands.size(); ++i) {
5410 if (commands[i].type == CookieStoreCommand::LOAD_COOKIES_FOR_KEY)
5411 persistent_store->TakeCallbackAt(i).Run(
5412 std::vector<std::unique_ptr<CanonicalCookie>>());
5413 }
5414
5415 // This should be enough for both individual commands.
5416 callback_set.WaitUntilDone();
5417 callback_get.WaitUntilDone();
5418
5419 // Now execute full-store loads as well.
5420 for (size_t i = 0; i < commands.size(); ++i) {
5421 if (commands[i].type == CookieStoreCommand::LOAD)
5422 persistent_store->TakeCallbackAt(i).Run(
5423 std::vector<std::unique_ptr<CanonicalCookie>>());
5424 }
5425 }
5426
TEST_F(CookieMonsterTest,DeleteDuplicateCTime)5427 TEST_F(CookieMonsterTest, DeleteDuplicateCTime) {
5428 const char* const kNames[] = {"A", "B", "C"};
5429
5430 // Tests that DeleteCanonicalCookie properly distinguishes different cookies
5431 // (e.g. different name or path) with identical ctime on same domain.
5432 // This gets tested a few times with different deletion target, to make sure
5433 // that the implementation doesn't just happen to pick the right one because
5434 // of implementation details.
5435 for (const auto* name : kNames) {
5436 CookieMonster cm(nullptr, nullptr);
5437 Time now = Time::Now();
5438 GURL url("http://www.example.com");
5439
5440 for (size_t i = 0; i < std::size(kNames); ++i) {
5441 std::string cookie_string =
5442 base::StrCat({kNames[i], "=", base::NumberToString(i)});
5443 EXPECT_TRUE(SetCookieWithCreationTime(&cm, url, cookie_string, now));
5444 }
5445
5446 // Delete the run'th cookie.
5447 CookieList all_cookies = GetAllCookiesForURLWithOptions(
5448 &cm, url, CookieOptions::MakeAllInclusive());
5449 ASSERT_EQ(all_cookies.size(), std::size(kNames));
5450 for (size_t i = 0; i < std::size(kNames); ++i) {
5451 const CanonicalCookie& cookie = all_cookies[i];
5452 if (cookie.Name() == name) {
5453 EXPECT_TRUE(DeleteCanonicalCookie(&cm, cookie));
5454 }
5455 }
5456
5457 // Check that the right cookie got removed.
5458 all_cookies = GetAllCookiesForURLWithOptions(
5459 &cm, url, CookieOptions::MakeAllInclusive());
5460 ASSERT_EQ(all_cookies.size(), std::size(kNames) - 1);
5461 for (size_t i = 0; i < std::size(kNames) - 1; ++i) {
5462 const CanonicalCookie& cookie = all_cookies[i];
5463 EXPECT_NE(cookie.Name(), name);
5464 }
5465 }
5466 }
5467
TEST_F(CookieMonsterTest,DeleteCookieWithInheritedTimestamps)5468 TEST_F(CookieMonsterTest, DeleteCookieWithInheritedTimestamps) {
5469 Time t1 = Time::Now();
5470 Time t2 = t1 + base::Seconds(1);
5471 GURL url("http://www.example.com");
5472 std::string cookie_line = "foo=bar";
5473 CookieOptions options = CookieOptions::MakeAllInclusive();
5474 std::optional<base::Time> server_time = std::nullopt;
5475 std::optional<CookiePartitionKey> partition_key = std::nullopt;
5476 CookieMonster cm(nullptr, nullptr);
5477
5478 // Write a cookie created at |t1|.
5479 auto cookie = CanonicalCookie::CreateForTesting(url, cookie_line, t1,
5480 server_time, partition_key);
5481 ResultSavingCookieCallback<CookieAccessResult> set_callback_1;
5482 cm.SetCanonicalCookieAsync(std::move(cookie), url, options,
5483 set_callback_1.MakeCallback());
5484 set_callback_1.WaitUntilDone();
5485
5486 // Overwrite the cookie at |t2|.
5487 cookie = CanonicalCookie::CreateForTesting(url, cookie_line, t2, server_time,
5488 partition_key);
5489 ResultSavingCookieCallback<CookieAccessResult> set_callback_2;
5490 cm.SetCanonicalCookieAsync(std::move(cookie), url, options,
5491 set_callback_2.MakeCallback());
5492 set_callback_2.WaitUntilDone();
5493
5494 // The second cookie overwrites the first one but it will inherit the creation
5495 // timestamp |t1|. Test that deleting the new cookie still works.
5496 cookie = CanonicalCookie::CreateForTesting(url, cookie_line, t2, server_time,
5497 partition_key);
5498 ResultSavingCookieCallback<unsigned int> delete_callback;
5499 cm.DeleteCanonicalCookieAsync(*cookie, delete_callback.MakeCallback());
5500 delete_callback.WaitUntilDone();
5501 EXPECT_EQ(1U, delete_callback.result());
5502 }
5503
TEST_F(CookieMonsterTest,RejectCreatedSameSiteCookieOnSet)5504 TEST_F(CookieMonsterTest, RejectCreatedSameSiteCookieOnSet) {
5505 GURL url("http://www.example.com");
5506 std::string cookie_line = "foo=bar; SameSite=Lax";
5507
5508 CookieMonster cm(nullptr, nullptr);
5509 CookieOptions env_cross_site;
5510 env_cross_site.set_same_site_cookie_context(
5511 CookieOptions::SameSiteCookieContext(
5512 CookieOptions::SameSiteCookieContext::ContextType::CROSS_SITE));
5513
5514 CookieInclusionStatus status;
5515 // Cookie can be created successfully; SameSite is not checked on Creation.
5516 auto cookie = CanonicalCookie::CreateForTesting(
5517 url, cookie_line, base::Time::Now(),
5518 /*server_time=*/std::nullopt,
5519 /*cookie_partition_key=*/std::nullopt,
5520 /*block_truncated=*/true, CookieSourceType::kUnknown, &status);
5521 ASSERT_TRUE(cookie != nullptr);
5522 ASSERT_TRUE(status.IsInclude());
5523
5524 // ... but the environment is checked on set, so this may be rejected then.
5525 ResultSavingCookieCallback<CookieAccessResult> callback;
5526 cm.SetCanonicalCookieAsync(std::move(cookie), url, env_cross_site,
5527 callback.MakeCallback());
5528 callback.WaitUntilDone();
5529 EXPECT_TRUE(callback.result().status.HasExactlyExclusionReasonsForTesting(
5530 {CookieInclusionStatus::EXCLUDE_SAMESITE_LAX}));
5531 }
5532
TEST_F(CookieMonsterTest,RejectCreatedSecureCookieOnSet)5533 TEST_F(CookieMonsterTest, RejectCreatedSecureCookieOnSet) {
5534 GURL http_url("http://www.example.com");
5535 std::string cookie_line = "foo=bar; Secure";
5536
5537 CookieMonster cm(nullptr, nullptr);
5538 CookieInclusionStatus status;
5539 // Cookie can be created successfully from an any url. Secure is not checked
5540 // on Create.
5541 auto cookie = CanonicalCookie::CreateForTesting(
5542 http_url, cookie_line, base::Time::Now(), /*server_time=*/std::nullopt,
5543 /*cookie_partition_key=*/std::nullopt, /*block_truncated=*/true,
5544 CookieSourceType::kUnknown, &status);
5545
5546 ASSERT_TRUE(cookie != nullptr);
5547 ASSERT_TRUE(status.IsInclude());
5548
5549 // Cookie is rejected when attempting to set from a non-secure scheme.
5550 ResultSavingCookieCallback<CookieAccessResult> callback;
5551 cm.SetCanonicalCookieAsync(std::move(cookie), http_url,
5552 CookieOptions::MakeAllInclusive(),
5553 callback.MakeCallback());
5554 callback.WaitUntilDone();
5555 EXPECT_TRUE(callback.result().status.HasExactlyExclusionReasonsForTesting(
5556 {CookieInclusionStatus::EXCLUDE_SECURE_ONLY}));
5557 }
5558
TEST_F(CookieMonsterTest,RejectCreatedHttpOnlyCookieOnSet)5559 TEST_F(CookieMonsterTest, RejectCreatedHttpOnlyCookieOnSet) {
5560 GURL url("http://www.example.com");
5561 std::string cookie_line = "foo=bar; HttpOnly";
5562
5563 CookieMonster cm(nullptr, nullptr);
5564 CookieInclusionStatus status;
5565 // Cookie can be created successfully; HttpOnly is not checked on Create.
5566 auto cookie = CanonicalCookie::CreateForTesting(
5567 url, cookie_line, base::Time::Now(),
5568 /*server_time=*/std::nullopt,
5569 /*cookie_partition_key=*/std::nullopt,
5570 /*block_truncated=*/true, CookieSourceType::kUnknown, &status);
5571
5572 ASSERT_TRUE(cookie != nullptr);
5573 ASSERT_TRUE(status.IsInclude());
5574
5575 // Cookie is rejected when attempting to set with a CookieOptions that does
5576 // not allow httponly.
5577 CookieOptions options_no_httponly;
5578 options_no_httponly.set_same_site_cookie_context(
5579 CookieOptions::SameSiteCookieContext(
5580 CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_STRICT));
5581 options_no_httponly.set_exclude_httponly(); // Default, but make it explicit.
5582 ResultSavingCookieCallback<CookieAccessResult> callback;
5583 cm.SetCanonicalCookieAsync(std::move(cookie), url, options_no_httponly,
5584 callback.MakeCallback());
5585 callback.WaitUntilDone();
5586 EXPECT_TRUE(callback.result().status.HasExactlyExclusionReasonsForTesting(
5587 {CookieInclusionStatus::EXCLUDE_HTTP_ONLY}));
5588 }
5589
5590 // Test that SameSite=None requires Secure.
TEST_F(CookieMonsterTest,CookiesWithoutSameSiteMustBeSecure)5591 TEST_F(CookieMonsterTest, CookiesWithoutSameSiteMustBeSecure) {
5592 const base::TimeDelta kLongAge = kLaxAllowUnsafeMaxAge * 4;
5593 const base::TimeDelta kShortAge = kLaxAllowUnsafeMaxAge / 4;
5594
5595 struct TestCase {
5596 bool is_url_secure;
5597 std::string cookie_line;
5598 CookieInclusionStatus expected_set_cookie_result;
5599 // Only makes sense to check if result is INCLUDE:
5600 CookieEffectiveSameSite expected_effective_samesite =
5601 CookieEffectiveSameSite::NO_RESTRICTION;
5602 base::TimeDelta creation_time_delta = base::TimeDelta();
5603 } test_cases[] = {
5604 // Feature enabled:
5605 // Cookie set from a secure URL with SameSite enabled is not rejected.
5606 {true, "A=B; SameSite=Lax", CookieInclusionStatus(),
5607 CookieEffectiveSameSite::LAX_MODE},
5608 // Cookie set from a secure URL which is defaulted into Lax is not
5609 // rejected.
5610 {true, "A=B", // recently-set session cookie.
5611 CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE,
5612 kShortAge},
5613 {true, "A=B", // not-recently-set session cookie.
5614 CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE, kLongAge},
5615 // Cookie set from a secure URL with SameSite=None and Secure is set.
5616 {true, "A=B; SameSite=None; Secure", CookieInclusionStatus(),
5617 CookieEffectiveSameSite::NO_RESTRICTION},
5618 // Cookie set from a secure URL with SameSite=None but not specifying
5619 // Secure is rejected.
5620 {true, "A=B; SameSite=None",
5621 CookieInclusionStatus(
5622 CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE,
5623 CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE)},
5624 // Cookie set from an insecure URL which defaults into LAX_MODE is not
5625 // rejected.
5626 {false, "A=B", // recently-set session cookie.
5627 CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE,
5628 kShortAge},
5629 {false, "A=B", // not-recently-set session cookie.
5630 CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE, kLongAge},
5631 {false, "A=B; Max-Age=1000000", // recently-set persistent cookie.
5632 CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE,
5633 kShortAge},
5634 {false,
5635 "A=B; Max-Age=1000000", // not-recently-set persistent cookie.
5636 CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE, kLongAge},
5637 };
5638
5639 auto cm = std::make_unique<CookieMonster>(nullptr, nullptr);
5640 GURL secure_url("https://www.example1.test");
5641 GURL insecure_url("http://www.example2.test");
5642
5643 int length = sizeof(test_cases) / sizeof(test_cases[0]);
5644 for (int i = 0; i < length; ++i) {
5645 TestCase test = test_cases[i];
5646
5647 GURL url = test.is_url_secure ? secure_url : insecure_url;
5648 base::Time creation_time = base::Time::Now() - test.creation_time_delta;
5649 auto cookie =
5650 CanonicalCookie::CreateForTesting(url, test.cookie_line, creation_time);
5651 // Make a copy so we can delete it after the test.
5652 CanonicalCookie cookie_copy = *cookie;
5653 CookieAccessResult result = SetCanonicalCookieReturnAccessResult(
5654 cm.get(), std::move(cookie), url,
5655 true /* can_modify_httponly (irrelevant) */);
5656 EXPECT_EQ(test.expected_set_cookie_result, result.status)
5657 << "Test case " << i << " failed.";
5658 if (result.status.IsInclude()) {
5659 auto cookies = GetAllCookiesForURL(cm.get(), url);
5660 ASSERT_EQ(1u, cookies.size());
5661 EXPECT_EQ(test.expected_effective_samesite, result.effective_same_site)
5662 << "Test case " << i << " failed.";
5663 DeleteCanonicalCookie(cm.get(), cookie_copy);
5664 }
5665 }
5666 }
5667
5668 class CookieMonsterNotificationTest : public CookieMonsterTest {
5669 public:
CookieMonsterNotificationTest()5670 CookieMonsterNotificationTest()
5671 : test_url_("http://www.foo.com/foo"),
5672 store_(base::MakeRefCounted<MockPersistentCookieStore>()),
5673 monster_(std::make_unique<CookieMonster>(store_.get(), nullptr)) {}
5674
5675 ~CookieMonsterNotificationTest() override = default;
5676
monster()5677 CookieMonster* monster() { return monster_.get(); }
5678
5679 protected:
5680 const GURL test_url_;
5681
5682 private:
5683 scoped_refptr<MockPersistentCookieStore> store_;
5684 std::unique_ptr<CookieMonster> monster_;
5685 };
5686
RecordCookieChanges(std::vector<CanonicalCookie> * out_cookies,std::vector<CookieChangeCause> * out_causes,const CookieChangeInfo & change)5687 void RecordCookieChanges(std::vector<CanonicalCookie>* out_cookies,
5688 std::vector<CookieChangeCause>* out_causes,
5689 const CookieChangeInfo& change) {
5690 DCHECK(out_cookies);
5691 out_cookies->push_back(change.cookie);
5692 if (out_causes)
5693 out_causes->push_back(change.cause);
5694 }
5695
5696 // Tests that there are no changes emitted for cookie loading, but there are
5697 // changes emitted for other operations.
TEST_F(CookieMonsterNotificationTest,NoNotificationOnLoad)5698 TEST_F(CookieMonsterNotificationTest, NoNotificationOnLoad) {
5699 // Create a persistent store that will not synchronously satisfy the
5700 // loading requirement.
5701 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
5702 store->set_store_load_commands(true);
5703
5704 // Bind it to a CookieMonster
5705 auto monster = std::make_unique<CookieMonster>(store.get(), nullptr);
5706
5707 // Trigger load dispatch and confirm it.
5708 monster->GetAllCookiesAsync(CookieStore::GetAllCookiesCallback());
5709 ASSERT_EQ(1u, store->commands().size());
5710 EXPECT_EQ(CookieStoreCommand::LOAD, store->commands()[0].type);
5711
5712 // Attach a change subscription.
5713 std::vector<CanonicalCookie> cookies;
5714 std::vector<CookieChangeCause> causes;
5715 std::unique_ptr<CookieChangeSubscription> subscription =
5716 monster->GetChangeDispatcher().AddCallbackForAllChanges(
5717 base::BindRepeating(&RecordCookieChanges, &cookies, &causes));
5718
5719 // Set up some initial cookies, including duplicates.
5720 std::vector<std::unique_ptr<CanonicalCookie>> initial_cookies;
5721 GURL url("http://www.foo.com");
5722 initial_cookies.push_back(
5723 CanonicalCookie::CreateForTesting(url, "X=1; path=/", base::Time::Now()));
5724 initial_cookies.push_back(
5725 CanonicalCookie::CreateForTesting(url, "Y=1; path=/", base::Time::Now()));
5726 initial_cookies.push_back(CanonicalCookie::CreateForTesting(
5727 url, "Y=2; path=/", base::Time::Now() + base::Days(1)));
5728
5729 // Execute the load
5730 store->TakeCallbackAt(0).Run(std::move(initial_cookies));
5731 base::RunLoop().RunUntilIdle();
5732
5733 // We should see no insertions (because loads do not cause notifications to be
5734 // dispatched), no deletions (because overwriting a duplicate cookie on load
5735 // does not trigger a notification), and two cookies in the monster.
5736 EXPECT_EQ(0u, cookies.size());
5737 EXPECT_EQ(0u, causes.size());
5738 EXPECT_EQ(2u, this->GetAllCookies(monster.get()).size());
5739
5740 // Change the cookies again to make sure that other changes do emit
5741 // notifications.
5742 this->CreateAndSetCookie(monster.get(), url, "X=2; path=/",
5743 CookieOptions::MakeAllInclusive());
5744 this->CreateAndSetCookie(monster.get(), url, "Y=3; path=/; max-age=0",
5745 CookieOptions::MakeAllInclusive());
5746
5747 base::RunLoop().RunUntilIdle();
5748 ASSERT_EQ(3u, cookies.size());
5749 ASSERT_EQ(3u, causes.size());
5750 EXPECT_EQ("X", cookies[0].Name());
5751 EXPECT_EQ("1", cookies[0].Value());
5752 EXPECT_EQ(CookieChangeCause::OVERWRITE, causes[0]);
5753 EXPECT_EQ("X", cookies[1].Name());
5754 EXPECT_EQ("2", cookies[1].Value());
5755 EXPECT_EQ(CookieChangeCause::INSERTED, causes[1]);
5756 EXPECT_EQ("Y", cookies[2].Name());
5757 EXPECT_EQ("2", cookies[2].Value());
5758 EXPECT_EQ(CookieChangeCause::EXPIRED_OVERWRITE, causes[2]);
5759 }
5760
5761 class CookieMonsterLegacyCookieAccessTest : public CookieMonsterTest {
5762 public:
CookieMonsterLegacyCookieAccessTest()5763 CookieMonsterLegacyCookieAccessTest()
5764 : cm_(std::make_unique<CookieMonster>(nullptr /* store */,
5765 nullptr /* netlog */
5766 )) {
5767 // Need to reset first because there cannot be two TaskEnvironments at the
5768 // same time.
5769 task_environment_.reset();
5770 task_environment_ =
5771 std::make_unique<base::test::SingleThreadTaskEnvironment>(
5772 base::test::TaskEnvironment::TimeSource::MOCK_TIME);
5773
5774 std::unique_ptr<TestCookieAccessDelegate> access_delegate =
5775 std::make_unique<TestCookieAccessDelegate>();
5776 access_delegate_ = access_delegate.get();
5777 cm_->SetCookieAccessDelegate(std::move(access_delegate));
5778 }
5779
5780 ~CookieMonsterLegacyCookieAccessTest() override = default;
5781
5782 protected:
5783 const std::string kDomain = "example.test";
5784 const GURL kHttpsUrl = GURL("https://example.test");
5785 const GURL kHttpUrl = GURL("http://example.test");
5786 std::unique_ptr<CookieMonster> cm_;
5787 raw_ptr<TestCookieAccessDelegate> access_delegate_;
5788 };
5789
TEST_F(CookieMonsterLegacyCookieAccessTest,SetLegacyNoSameSiteCookie)5790 TEST_F(CookieMonsterLegacyCookieAccessTest, SetLegacyNoSameSiteCookie) {
5791 // Check that setting unspecified-SameSite cookie from cross-site context
5792 // fails if not set to Legacy semantics, but succeeds if set to legacy.
5793 EXPECT_FALSE(CreateAndSetCookie(cm_.get(), kHttpUrl, "cookie=chocolate_chip",
5794 CookieOptions()));
5795 access_delegate_->SetExpectationForCookieDomain(
5796 kDomain, CookieAccessSemantics::UNKNOWN);
5797 EXPECT_FALSE(CreateAndSetCookie(cm_.get(), kHttpUrl, "cookie=chocolate_chip",
5798 CookieOptions()));
5799 access_delegate_->SetExpectationForCookieDomain(
5800 kDomain, CookieAccessSemantics::NONLEGACY);
5801 EXPECT_FALSE(CreateAndSetCookie(cm_.get(), kHttpUrl, "cookie=chocolate_chip",
5802 CookieOptions()));
5803 access_delegate_->SetExpectationForCookieDomain(
5804 kDomain, CookieAccessSemantics::LEGACY);
5805 EXPECT_TRUE(CreateAndSetCookie(cm_.get(), kHttpUrl, "cookie=chocolate_chip",
5806 CookieOptions()));
5807 }
5808
TEST_F(CookieMonsterLegacyCookieAccessTest,GetLegacyNoSameSiteCookie)5809 TEST_F(CookieMonsterLegacyCookieAccessTest, GetLegacyNoSameSiteCookie) {
5810 // Set a cookie with no SameSite attribute.
5811 ASSERT_TRUE(CreateAndSetCookie(cm_.get(), kHttpUrl, "cookie=chocolate_chip",
5812 CookieOptions::MakeAllInclusive()));
5813
5814 // Getting the cookie fails unless semantics is legacy.
5815 access_delegate_->SetExpectationForCookieDomain(
5816 kDomain, CookieAccessSemantics::UNKNOWN);
5817 EXPECT_EQ("", GetCookiesWithOptions(cm_.get(), kHttpUrl, CookieOptions()));
5818 access_delegate_->SetExpectationForCookieDomain(
5819 kDomain, CookieAccessSemantics::NONLEGACY);
5820 EXPECT_EQ("", GetCookiesWithOptions(cm_.get(), kHttpUrl, CookieOptions()));
5821 access_delegate_->SetExpectationForCookieDomain(
5822 kDomain, CookieAccessSemantics::LEGACY);
5823 EXPECT_EQ("cookie=chocolate_chip",
5824 GetCookiesWithOptions(cm_.get(), kHttpUrl, CookieOptions()));
5825 }
5826
TEST_F(CookieMonsterLegacyCookieAccessTest,SetLegacySameSiteNoneInsecureCookie)5827 TEST_F(CookieMonsterLegacyCookieAccessTest,
5828 SetLegacySameSiteNoneInsecureCookie) {
5829 access_delegate_->SetExpectationForCookieDomain(
5830 kDomain, CookieAccessSemantics::UNKNOWN);
5831 EXPECT_FALSE(CreateAndSetCookie(cm_.get(), kHttpsUrl,
5832 "cookie=oatmeal_raisin; SameSite=None",
5833 CookieOptions()));
5834 access_delegate_->SetExpectationForCookieDomain(
5835 kDomain, CookieAccessSemantics::NONLEGACY);
5836 EXPECT_FALSE(CreateAndSetCookie(cm_.get(), kHttpsUrl,
5837 "cookie=oatmeal_raisin; SameSite=None",
5838 CookieOptions()));
5839 // Setting the access semantics to legacy allows setting the cookie.
5840 access_delegate_->SetExpectationForCookieDomain(
5841 kDomain, CookieAccessSemantics::LEGACY);
5842 EXPECT_TRUE(CreateAndSetCookie(cm_.get(), kHttpsUrl,
5843 "cookie=oatmeal_raisin; SameSite=None",
5844 CookieOptions()));
5845 EXPECT_EQ("cookie=oatmeal_raisin",
5846 GetCookiesWithOptions(cm_.get(), kHttpsUrl, CookieOptions()));
5847 }
5848
TEST_F(CookieMonsterLegacyCookieAccessTest,GetLegacySameSiteNoneInsecureCookie)5849 TEST_F(CookieMonsterLegacyCookieAccessTest,
5850 GetLegacySameSiteNoneInsecureCookie) {
5851 // Need to inject such a cookie under legacy semantics.
5852 access_delegate_->SetExpectationForCookieDomain(
5853 kDomain, CookieAccessSemantics::LEGACY);
5854 ASSERT_TRUE(CreateAndSetCookie(cm_.get(), kHttpUrl,
5855 "cookie=oatmeal_raisin; SameSite=None",
5856 CookieOptions::MakeAllInclusive()));
5857 // Getting a SameSite=None but non-Secure cookie fails unless semantics is
5858 // legacy.
5859 access_delegate_->SetExpectationForCookieDomain(
5860 kDomain, CookieAccessSemantics::UNKNOWN);
5861 EXPECT_EQ("", GetCookiesWithOptions(cm_.get(), kHttpUrl, CookieOptions()));
5862 access_delegate_->SetExpectationForCookieDomain(
5863 kDomain, CookieAccessSemantics::NONLEGACY);
5864 EXPECT_EQ("", GetCookiesWithOptions(cm_.get(), kHttpUrl, CookieOptions()));
5865 access_delegate_->SetExpectationForCookieDomain(
5866 kDomain, CookieAccessSemantics::LEGACY);
5867 EXPECT_EQ("cookie=oatmeal_raisin",
5868 GetCookiesWithOptions(cm_.get(), kHttpUrl, CookieOptions()));
5869 }
5870
TEST_F(CookieMonsterTest,IsCookieSentToSamePortThatSetIt)5871 TEST_F(CookieMonsterTest, IsCookieSentToSamePortThatSetIt) {
5872 // Note: `IsCookieSentToSamePortThatSetIt()` only uses the source_scheme if
5873 // the port is valid, specified, and doesn't match the url's port. So for test
5874 // cases where the above aren't true the value of source_scheme is irreleant.
5875
5876 // Test unspecified.
5877 ASSERT_EQ(CookieMonster::IsCookieSentToSamePortThatSetIt(
5878 GURL("https://foo.com"), url::PORT_UNSPECIFIED,
5879 CookieSourceScheme::kSecure),
5880 CookieMonster::CookieSentToSamePort::kSourcePortUnspecified);
5881
5882 // Test invalid.
5883 ASSERT_EQ(CookieMonster::IsCookieSentToSamePortThatSetIt(
5884 GURL("https://foo.com"), url::PORT_INVALID,
5885 CookieSourceScheme::kSecure),
5886 CookieMonster::CookieSentToSamePort::kInvalid);
5887
5888 // Test same.
5889 ASSERT_EQ(CookieMonster::IsCookieSentToSamePortThatSetIt(
5890 GURL("https://foo.com"), 443, CookieSourceScheme::kSecure),
5891 CookieMonster::CookieSentToSamePort::kYes);
5892
5893 ASSERT_EQ(
5894 CookieMonster::IsCookieSentToSamePortThatSetIt(
5895 GURL("https://foo.com:1234"), 1234, CookieSourceScheme::kSecure),
5896 CookieMonster::CookieSentToSamePort::kYes);
5897
5898 // Test different but default.
5899 ASSERT_EQ(CookieMonster::IsCookieSentToSamePortThatSetIt(
5900 GURL("https://foo.com"), 80, CookieSourceScheme::kNonSecure),
5901 CookieMonster::CookieSentToSamePort::kNoButDefault);
5902
5903 ASSERT_EQ(
5904 CookieMonster::IsCookieSentToSamePortThatSetIt(
5905 GURL("https://foo.com:443"), 80, CookieSourceScheme::kNonSecure),
5906 CookieMonster::CookieSentToSamePort::kNoButDefault);
5907
5908 ASSERT_EQ(CookieMonster::IsCookieSentToSamePortThatSetIt(
5909 GURL("wss://foo.com"), 80, CookieSourceScheme::kNonSecure),
5910 CookieMonster::CookieSentToSamePort::kNoButDefault);
5911
5912 ASSERT_EQ(CookieMonster::IsCookieSentToSamePortThatSetIt(
5913 GURL("http://foo.com"), 443, CookieSourceScheme::kSecure),
5914 CookieMonster::CookieSentToSamePort::kNoButDefault);
5915
5916 ASSERT_EQ(CookieMonster::IsCookieSentToSamePortThatSetIt(
5917 GURL("ws://foo.com"), 443, CookieSourceScheme::kSecure),
5918 CookieMonster::CookieSentToSamePort::kNoButDefault);
5919
5920 // Test different.
5921 ASSERT_EQ(CookieMonster::IsCookieSentToSamePortThatSetIt(
5922 GURL("http://foo.com:9000"), 85, CookieSourceScheme::kSecure),
5923 CookieMonster::CookieSentToSamePort::kNo);
5924
5925 ASSERT_EQ(CookieMonster::IsCookieSentToSamePortThatSetIt(
5926 GURL("https://foo.com"), 80, CookieSourceScheme::kSecure),
5927 CookieMonster::CookieSentToSamePort::kNo);
5928
5929 ASSERT_EQ(CookieMonster::IsCookieSentToSamePortThatSetIt(
5930 GURL("wss://foo.com"), 80, CookieSourceScheme::kSecure),
5931 CookieMonster::CookieSentToSamePort::kNo);
5932
5933 ASSERT_EQ(CookieMonster::IsCookieSentToSamePortThatSetIt(
5934 GURL("http://foo.com"), 443, CookieSourceScheme::kNonSecure),
5935 CookieMonster::CookieSentToSamePort::kNo);
5936
5937 ASSERT_EQ(CookieMonster::IsCookieSentToSamePortThatSetIt(
5938 GURL("ws://foo.com"), 443, CookieSourceScheme::kNonSecure),
5939 CookieMonster::CookieSentToSamePort::kNo);
5940
5941 ASSERT_EQ(CookieMonster::IsCookieSentToSamePortThatSetIt(
5942 GURL("http://foo.com:444"), 443, CookieSourceScheme::kSecure),
5943 CookieMonster::CookieSentToSamePort::kNo);
5944 }
5945
TEST_F(CookieMonsterTest,CookieDomainSetHistogram)5946 TEST_F(CookieMonsterTest, CookieDomainSetHistogram) {
5947 base::HistogramTester histograms;
5948 const char kHistogramName[] = "Cookie.DomainSet";
5949
5950 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
5951 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
5952
5953 histograms.ExpectTotalCount(kHistogramName, 0);
5954
5955 // Set a host only cookie (non-Domain).
5956 EXPECT_TRUE(SetCookie(cm.get(), https_www_foo_.url(), "A=B"));
5957 histograms.ExpectTotalCount(kHistogramName, 1);
5958 histograms.ExpectBucketCount(kHistogramName, false, 1);
5959
5960 // Set a domain cookie.
5961 EXPECT_TRUE(SetCookie(cm.get(), https_www_foo_.url(),
5962 "A=B; Domain=" + https_www_foo_.host()));
5963 histograms.ExpectTotalCount(kHistogramName, 2);
5964 histograms.ExpectBucketCount(kHistogramName, true, 1);
5965
5966 // Invalid cookies don't count toward the histogram.
5967 EXPECT_FALSE(
5968 SetCookie(cm.get(), https_www_foo_.url(), "A=B; Domain=other.com"));
5969 histograms.ExpectTotalCount(kHistogramName, 2);
5970 histograms.ExpectBucketCount(kHistogramName, false, 1);
5971 }
5972
TEST_F(CookieMonsterTest,CookiePortReadHistogram)5973 TEST_F(CookieMonsterTest, CookiePortReadHistogram) {
5974 base::HistogramTester histograms;
5975 const char kHistogramName[] = "Cookie.Port.Read.RemoteHost";
5976 const char kHistogramNameLocal[] = "Cookie.Port.Read.Localhost";
5977
5978 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
5979 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
5980
5981 histograms.ExpectTotalCount(kHistogramName, 0);
5982
5983 EXPECT_TRUE(SetCookie(cm.get(), GURL("https://www.foo.com"), "A=B"));
5984
5985 // May as well check that it didn't change the histogram...
5986 histograms.ExpectTotalCount(kHistogramName, 0);
5987
5988 // Now read it from some different ports. This requires some knowledge of how
5989 // `ReducePortRangeForCookieHistogram` maps ports, but that's probably fine.
5990 EXPECT_EQ(GetCookies(cm.get(), GURL("https://www.foo.com")), "A=B");
5991 // https default is 443, so check that.
5992 histograms.ExpectTotalCount(kHistogramName, 1);
5993 histograms.ExpectBucketCount(kHistogramName,
5994 ReducePortRangeForCookieHistogram(443), 1);
5995
5996 EXPECT_EQ(GetCookies(cm.get(), GURL("https://www.foo.com:82")), "A=B");
5997 histograms.ExpectTotalCount(kHistogramName, 2);
5998 histograms.ExpectBucketCount(kHistogramName,
5999 ReducePortRangeForCookieHistogram(82), 1);
6000
6001 EXPECT_EQ(GetCookies(cm.get(), GURL("https://www.foo.com:8080")), "A=B");
6002 histograms.ExpectTotalCount(kHistogramName, 3);
6003 histograms.ExpectBucketCount(kHistogramName,
6004 ReducePortRangeForCookieHistogram(8080), 1);
6005
6006 EXPECT_EQ(GetCookies(cm.get(), GURL("https://www.foo.com:1234")), "A=B");
6007 histograms.ExpectTotalCount(kHistogramName, 4);
6008 histograms.ExpectBucketCount(kHistogramName,
6009 ReducePortRangeForCookieHistogram(1234), 1);
6010
6011 // Histogram should not increment if nothing is read.
6012 EXPECT_EQ(GetCookies(cm.get(), GURL("https://www.other.com")), "");
6013 histograms.ExpectTotalCount(kHistogramName, 4);
6014
6015 // Make sure the correct histogram is chosen for localhost.
6016 EXPECT_TRUE(SetCookie(cm.get(), GURL("https://localhost"), "local=host"));
6017
6018 histograms.ExpectTotalCount(kHistogramNameLocal, 0);
6019
6020 EXPECT_EQ(GetCookies(cm.get(), GURL("https://localhost:82")), "local=host");
6021 histograms.ExpectTotalCount(kHistogramNameLocal, 1);
6022 histograms.ExpectBucketCount(kHistogramNameLocal,
6023 ReducePortRangeForCookieHistogram(82), 1);
6024 }
6025
TEST_F(CookieMonsterTest,CookiePortSetHistogram)6026 TEST_F(CookieMonsterTest, CookiePortSetHistogram) {
6027 base::HistogramTester histograms;
6028 const char kHistogramName[] = "Cookie.Port.Set.RemoteHost";
6029 const char kHistogramNameLocal[] = "Cookie.Port.Set.Localhost";
6030
6031 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
6032 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
6033
6034 histograms.ExpectTotalCount(kHistogramName, 0);
6035
6036 // Set some cookies. This requires some knowledge of how
6037 // ReducePortRangeForCookieHistogram maps ports, but that's probably fine.
6038
6039 EXPECT_TRUE(SetCookie(cm.get(), GURL("https://www.foo.com"), "A=B"));
6040 histograms.ExpectTotalCount(kHistogramName, 1);
6041 histograms.ExpectBucketCount(kHistogramName,
6042 ReducePortRangeForCookieHistogram(443), 1);
6043
6044 EXPECT_TRUE(SetCookie(cm.get(), GURL("https://www.foo.com:80"), "A=B"));
6045 histograms.ExpectTotalCount(kHistogramName, 2);
6046 histograms.ExpectBucketCount(kHistogramName,
6047 ReducePortRangeForCookieHistogram(80), 1);
6048
6049 EXPECT_TRUE(SetCookie(cm.get(), GURL("https://www.foo.com:9000"), "A=B"));
6050 histograms.ExpectTotalCount(kHistogramName, 3);
6051 histograms.ExpectBucketCount(kHistogramName,
6052 ReducePortRangeForCookieHistogram(9000), 1);
6053
6054 EXPECT_TRUE(SetCookie(cm.get(), GURL("https://www.foo.com:1234"), "A=B"));
6055 histograms.ExpectTotalCount(kHistogramName, 4);
6056 histograms.ExpectBucketCount(kHistogramName,
6057 ReducePortRangeForCookieHistogram(1234), 1);
6058
6059 // Histogram should not increment for invalid cookie.
6060 EXPECT_FALSE(SetCookie(cm.get(), GURL("https://www.foo.com"),
6061 "A=B; Domain=malformedcookie.com"));
6062 histograms.ExpectTotalCount(kHistogramName, 4);
6063
6064 // Nor should it increment for a read operation
6065 EXPECT_NE(GetCookies(cm.get(), GURL("https://www.foo.com")), "");
6066 histograms.ExpectTotalCount(kHistogramName, 4);
6067
6068 // Make sure the correct histogram is chosen for localhost.
6069 histograms.ExpectTotalCount(kHistogramNameLocal, 0);
6070
6071 EXPECT_TRUE(
6072 SetCookie(cm.get(), GURL("https://localhost:1234"), "local=host"));
6073 histograms.ExpectTotalCount(kHistogramNameLocal, 1);
6074 histograms.ExpectBucketCount(kHistogramNameLocal,
6075 ReducePortRangeForCookieHistogram(1234), 1);
6076 }
6077
TEST_F(CookieMonsterTest,CookiePortReadDiffersFromSetHistogram)6078 TEST_F(CookieMonsterTest, CookiePortReadDiffersFromSetHistogram) {
6079 base::HistogramTester histograms;
6080 const char kHistogramName[] = "Cookie.Port.ReadDiffersFromSet.RemoteHost";
6081 const char kHistogramNameLocal[] = "Cookie.Port.ReadDiffersFromSet.Localhost";
6082 const char kHistogramNameDomainSet[] =
6083 "Cookie.Port.ReadDiffersFromSet.DomainSet";
6084
6085 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
6086 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
6087
6088 histograms.ExpectTotalCount(kHistogramName, 0);
6089
6090 // Set some cookies. One with a port, one without, and one with an invalid
6091 // port.
6092 EXPECT_TRUE(SetCookie(cm.get(), GURL("https://www.foo.com/withport"),
6093 "A=B; Path=/withport")); // Port 443
6094
6095 auto unspecified_cookie = CanonicalCookie::CreateForTesting(
6096 GURL("https://www.foo.com/withoutport"), "C=D; Path=/withoutport",
6097 base::Time::Now());
6098 // Force to be unspecified.
6099 unspecified_cookie->SetSourcePort(url::PORT_UNSPECIFIED);
6100 EXPECT_TRUE(SetCanonicalCookieReturnAccessResult(
6101 cm.get(), std::move(unspecified_cookie),
6102 GURL("https://www.foo.com/withoutport"),
6103 false /*can_modify_httponly*/)
6104 .status.IsInclude());
6105
6106 auto invalid_cookie = CanonicalCookie::CreateForTesting(
6107 GURL("https://www.foo.com/invalidport"), "E=F; Path=/invalidport",
6108 base::Time::Now());
6109 // Force to be invalid.
6110 invalid_cookie->SetSourcePort(99999);
6111 EXPECT_TRUE(SetCanonicalCookieReturnAccessResult(
6112 cm.get(), std::move(invalid_cookie),
6113 GURL("https://www.foo.com/invalidport"),
6114 false /*can_modify_httponly*/)
6115 .status.IsInclude());
6116
6117 // Try same port.
6118 EXPECT_EQ(GetCookies(cm.get(), GURL("https://www.foo.com/withport")), "A=B");
6119 histograms.ExpectTotalCount(kHistogramName, 1);
6120 histograms.ExpectBucketCount(kHistogramName,
6121 CookieMonster::CookieSentToSamePort::kYes, 1);
6122
6123 // Try different port.
6124 EXPECT_EQ(GetCookies(cm.get(), GURL("https://www.foo.com:8080/withport")),
6125 "A=B");
6126 histograms.ExpectTotalCount(kHistogramName, 2);
6127 histograms.ExpectBucketCount(kHistogramName,
6128 CookieMonster::CookieSentToSamePort::kNo, 1);
6129
6130 // Try different port, but it's the default for a different scheme.
6131 EXPECT_EQ(GetCookies(cm.get(), GURL("http://www.foo.com/withport")), "A=B");
6132 histograms.ExpectTotalCount(kHistogramName, 3);
6133 histograms.ExpectBucketCount(
6134 kHistogramName, CookieMonster::CookieSentToSamePort::kNoButDefault, 1);
6135
6136 // Now try it with an unspecified port cookie.
6137 EXPECT_EQ(GetCookies(cm.get(), GURL("http://www.foo.com/withoutport")),
6138 "C=D");
6139 histograms.ExpectTotalCount(kHistogramName, 4);
6140 histograms.ExpectBucketCount(
6141 kHistogramName,
6142 CookieMonster::CookieSentToSamePort::kSourcePortUnspecified, 1);
6143
6144 // Finally try it with an invalid port cookie.
6145 EXPECT_EQ(GetCookies(cm.get(), GURL("http://www.foo.com/invalidport")),
6146 "E=F");
6147 histograms.ExpectTotalCount(kHistogramName, 5);
6148 histograms.ExpectBucketCount(
6149 kHistogramName, CookieMonster::CookieSentToSamePort::kInvalid, 1);
6150
6151 // Make sure the correct histogram is chosen for localhost.
6152 histograms.ExpectTotalCount(kHistogramNameLocal, 0);
6153 EXPECT_TRUE(SetCookie(cm.get(), GURL("https://localhost"), "local=host"));
6154
6155 EXPECT_EQ(GetCookies(cm.get(), GURL("https://localhost")), "local=host");
6156 histograms.ExpectTotalCount(kHistogramNameLocal, 1);
6157 histograms.ExpectBucketCount(kHistogramNameLocal,
6158 CookieMonster::CookieSentToSamePort::kYes, 1);
6159
6160 // Make sure the Domain set version works.
6161 EXPECT_TRUE(SetCookie(cm.get(), GURL("https://www.foo.com/withDomain"),
6162 "W=D; Domain=foo.com; Path=/withDomain"));
6163
6164 histograms.ExpectTotalCount(kHistogramNameDomainSet, 0);
6165
6166 EXPECT_EQ(GetCookies(cm.get(), GURL("https://www.foo.com/withDomain")),
6167 "W=D");
6168 histograms.ExpectTotalCount(kHistogramNameDomainSet, 1);
6169 histograms.ExpectBucketCount(kHistogramNameDomainSet,
6170 CookieMonster::CookieSentToSamePort::kYes, 1);
6171 // The RemoteHost histogram should also increase with this cookie. Domain
6172 // cookies aren't special insofar as this metric is concerned.
6173 histograms.ExpectTotalCount(kHistogramName, 6);
6174 histograms.ExpectBucketCount(kHistogramName,
6175 CookieMonster::CookieSentToSamePort::kYes, 2);
6176 }
6177
TEST_F(CookieMonsterTest,CookieSourceSchemeNameHistogram)6178 TEST_F(CookieMonsterTest, CookieSourceSchemeNameHistogram) {
6179 base::HistogramTester histograms;
6180 const char kHistogramName[] = "Cookie.CookieSourceSchemeName";
6181
6182 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
6183 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
6184
6185 histograms.ExpectTotalCount(kHistogramName, 0);
6186
6187 struct TestCase {
6188 CookieSourceSchemeName enum_value;
6189 std::string scheme;
6190 };
6191
6192 // Test the usual and a smattering of some other types including a kOther.
6193 // It doesn't matter if we add this to the scheme registry or not because we
6194 // don't actually need the whole url to parse, we just need GURL to pick up on
6195 // the scheme correctly (which it does). What the rest of the cookie code does
6196 // with the oddly formed GURL is out of scope of this test (i.e. we don't
6197 // care).
6198 const TestCase kTestCases[] = {
6199 {CookieSourceSchemeName::kHttpsScheme, url::kHttpsScheme},
6200 {CookieSourceSchemeName::kHttpScheme, url::kHttpScheme},
6201 {CookieSourceSchemeName::kWssScheme, url::kWssScheme},
6202 {CookieSourceSchemeName::kWsScheme, url::kWsScheme},
6203 {CookieSourceSchemeName::kChromeExtensionScheme, "chrome-extension"},
6204 {CookieSourceSchemeName::kFileScheme, url::kFileScheme},
6205 {CookieSourceSchemeName::kOther, "abcd1234"}};
6206
6207 // Make sure all the schemes are considered cookieable.
6208 std::vector<std::string> schemes;
6209 for (auto test_case : kTestCases) {
6210 schemes.push_back(test_case.scheme);
6211 }
6212 ResultSavingCookieCallback<bool> cookie_scheme_callback;
6213 cm->SetCookieableSchemes(schemes, cookie_scheme_callback.MakeCallback());
6214 cookie_scheme_callback.WaitUntilDone();
6215 ASSERT_TRUE(cookie_scheme_callback.result());
6216
6217 const char kUrl[] = "://www.foo.com";
6218 int count = 0;
6219
6220 // Test all the cases.
6221 for (auto test_case : kTestCases) {
6222 histograms.ExpectBucketCount(kHistogramName, test_case.enum_value, 0);
6223
6224 EXPECT_TRUE(SetCookie(cm.get(), GURL(test_case.scheme + kUrl), "A=B"));
6225
6226 histograms.ExpectBucketCount(kHistogramName, test_case.enum_value, 1);
6227 histograms.ExpectTotalCount(kHistogramName, ++count);
6228 }
6229
6230 // This metric is only for cookies that are actually set. Make sure the
6231 // histogram doesn't increment for cookies that fail to set.
6232
6233 // Try to set an invalid cookie, for instance: a non-cookieable scheme will be
6234 // rejected.
6235 EXPECT_FALSE(SetCookie(cm.get(), GURL("invalidscheme://foo.com"), "A=B"));
6236 histograms.ExpectTotalCount(kHistogramName, count);
6237 }
6238
6239 class FirstPartySetEnabledCookieMonsterTest : public CookieMonsterTest {
6240 public:
FirstPartySetEnabledCookieMonsterTest()6241 FirstPartySetEnabledCookieMonsterTest()
6242 : cm_(nullptr /* store */, nullptr /* netlog */
6243 ) {
6244 std::unique_ptr<TestCookieAccessDelegate> access_delegate =
6245 std::make_unique<TestCookieAccessDelegate>();
6246 access_delegate_ = access_delegate.get();
6247 cm_.SetCookieAccessDelegate(std::move(access_delegate));
6248 }
6249
6250 ~FirstPartySetEnabledCookieMonsterTest() override = default;
6251
cm()6252 CookieMonster* cm() { return &cm_; }
6253
6254 protected:
6255 CookieMonster cm_;
6256 raw_ptr<TestCookieAccessDelegate> access_delegate_;
6257 };
6258
TEST_F(FirstPartySetEnabledCookieMonsterTest,RecordsPeriodicFPSSizes)6259 TEST_F(FirstPartySetEnabledCookieMonsterTest, RecordsPeriodicFPSSizes) {
6260 net::SchemefulSite owner1(GURL("https://owner1.test"));
6261 net::SchemefulSite owner2(GURL("https://owner2.test"));
6262 net::SchemefulSite member1(GURL("https://member1.test"));
6263 net::SchemefulSite member2(GURL("https://member2.test"));
6264 net::SchemefulSite member3(GURL("https://member3.test"));
6265 net::SchemefulSite member4(GURL("https://member4.test"));
6266
6267 access_delegate_->SetFirstPartySets({
6268 {owner1,
6269 net::FirstPartySetEntry(owner1, net::SiteType::kPrimary, std::nullopt)},
6270 {member1, net::FirstPartySetEntry(owner1, net::SiteType::kAssociated, 0)},
6271 {member2, net::FirstPartySetEntry(owner1, net::SiteType::kAssociated, 1)},
6272 {owner2,
6273 net::FirstPartySetEntry(owner2, net::SiteType::kPrimary, std::nullopt)},
6274 {member3, net::FirstPartySetEntry(owner2, net::SiteType::kAssociated, 0)},
6275 {member4, net::FirstPartySetEntry(owner2, net::SiteType::kAssociated, 1)},
6276 });
6277
6278 ASSERT_TRUE(SetCookie(cm(), GURL("https://owner1.test"), kValidCookieLine));
6279 ASSERT_TRUE(SetCookie(cm(), GURL("https://subdomain.member1.test"),
6280 kValidCookieLine));
6281 ASSERT_TRUE(SetCookie(cm(), GURL("https://member2.test"), kValidCookieLine));
6282 ASSERT_TRUE(
6283 SetCookie(cm(), GURL("https://subdomain.owner2.test"), kValidCookieLine));
6284 ASSERT_TRUE(SetCookie(cm(), GURL("https://member3.test"), kValidCookieLine));
6285 // No cookie set for member4.test.
6286 ASSERT_TRUE(
6287 SetCookie(cm(), GURL("https://unrelated1.test"), kValidCookieLine));
6288 ASSERT_TRUE(
6289 SetCookie(cm(), GURL("https://unrelated2.test"), kValidCookieLine));
6290 ASSERT_TRUE(
6291 SetCookie(cm(), GURL("https://unrelated3.test"), kValidCookieLine));
6292
6293 base::HistogramTester histogram_tester;
6294 EXPECT_TRUE(cm()->DoRecordPeriodicStatsForTesting());
6295 EXPECT_THAT(histogram_tester.GetAllSamples("Cookie.PerFirstPartySetCount"),
6296 testing::ElementsAre( //
6297 // owner2.test & member3.test
6298 base::Bucket(2 /* min */, 1 /* samples */),
6299 // owner1.test, member1.test, & member2.test
6300 base::Bucket(3 /* min */, 1 /* samples */)));
6301 }
6302
TEST_F(CookieMonsterTest,GetAllCookiesForURLNonce)6303 TEST_F(CookieMonsterTest, GetAllCookiesForURLNonce) {
6304 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
6305 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
6306 CookieOptions options = CookieOptions::MakeAllInclusive();
6307
6308 auto anonymous_iframe_key = CookiePartitionKey::FromURLForTesting(
6309 GURL("https://anonymous-iframe.test"),
6310 CookiePartitionKey::AncestorChainBit::kCrossSite,
6311 base::UnguessableToken::Create());
6312
6313 // Define cookies from outside an anonymous iframe:
6314 EXPECT_TRUE(CreateAndSetCookie(cm.get(), https_www_foo_.url(),
6315 "A=0; Secure; HttpOnly; Path=/;", options));
6316 EXPECT_TRUE(CreateAndSetCookie(cm.get(), https_www_foo_.url(),
6317 "__Host-B=0; Secure; HttpOnly; Path=/;",
6318 options));
6319
6320 // Define cookies from inside an anonymous iframe:
6321 EXPECT_TRUE(CreateAndSetCookie(
6322 cm.get(), https_www_foo_.url(),
6323 "__Host-B=1; Secure; HttpOnly; Path=/; Partitioned", options,
6324 std::nullopt, std::nullopt, anonymous_iframe_key));
6325 EXPECT_TRUE(CreateAndSetCookie(
6326 cm.get(), https_www_foo_.url(),
6327 "__Host-C=0; Secure; HttpOnly; Path=/; Partitioned", options,
6328 std::nullopt, std::nullopt, anonymous_iframe_key));
6329
6330 // Check cookies from outside the anonymous iframe:
6331 EXPECT_THAT(GetAllCookiesForURL(cm.get(), https_www_foo_.url()),
6332 ElementsAre(MatchesCookieNameValue("A", "0"),
6333 MatchesCookieNameValue("__Host-B", "0")));
6334
6335 // Check cookies from inside the anonymous iframe:
6336 EXPECT_THAT(
6337 GetAllCookiesForURL(cm.get(), https_www_foo_.url(),
6338 CookiePartitionKeyCollection(anonymous_iframe_key)),
6339 ElementsAre(MatchesCookieNameValue("__Host-B", "1"),
6340 MatchesCookieNameValue("__Host-C", "0")));
6341 }
6342
TEST_F(CookieMonsterTest,SiteHasCookieInOtherPartition)6343 TEST_F(CookieMonsterTest, SiteHasCookieInOtherPartition) {
6344 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
6345 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
6346 CookieOptions options = CookieOptions::MakeAllInclusive();
6347
6348 GURL url("https://subdomain.example.com/");
6349 net::SchemefulSite site(url);
6350 auto partition_key =
6351 CookiePartitionKey::FromURLForTesting(GURL("https://toplevelsite.com"));
6352
6353 // At first it should return nullopt...
6354 EXPECT_FALSE(cm->SiteHasCookieInOtherPartition(site, partition_key));
6355
6356 // ...until we load cookies for that domain.
6357 GetAllCookiesForURL(cm.get(), url,
6358 CookiePartitionKeyCollection::ContainsAll());
6359 EXPECT_THAT(cm->SiteHasCookieInOtherPartition(site, partition_key),
6360 testing::Optional(false));
6361
6362 // Set partitioned cookie.
6363 EXPECT_TRUE(CreateAndSetCookie(
6364 cm.get(), url, "foo=bar; Secure; SameSite=None; Partitioned", options,
6365 std::nullopt, std::nullopt, partition_key));
6366
6367 // Should return false with that cookie's partition key.
6368 EXPECT_THAT(cm->SiteHasCookieInOtherPartition(site, partition_key),
6369 testing::Optional(false));
6370
6371 auto other_partition_key = CookiePartitionKey::FromURLForTesting(
6372 GURL("https://nottoplevelsite.com"));
6373
6374 // Should return true with another partition key.
6375 EXPECT_THAT(cm->SiteHasCookieInOtherPartition(site, other_partition_key),
6376 testing::Optional(true));
6377
6378 // Set a nonced partitioned cookie with a different partition key.
6379 EXPECT_TRUE(CreateAndSetCookie(
6380 cm.get(), url, "foo=bar; Secure; SameSite=None; Partitioned", options,
6381 std::nullopt, std::nullopt,
6382 CookiePartitionKey::FromURLForTesting(
6383 GURL("https://nottoplevelsite.com"),
6384 CookiePartitionKey::AncestorChainBit::kCrossSite,
6385 base::UnguessableToken::Create())));
6386
6387 // Should still return false with the original partition key.
6388 EXPECT_THAT(cm->SiteHasCookieInOtherPartition(site, partition_key),
6389 testing::Optional(false));
6390
6391 // Set unpartitioned cookie.
6392 EXPECT_TRUE(CreateAndSetCookie(cm.get(), url,
6393 "bar=baz; Secure; SameSite=None;", options,
6394 std::nullopt, std::nullopt));
6395
6396 // Should still return false with the original cookie's partition key. This
6397 // method only considers partitioned cookies.
6398 EXPECT_THAT(cm->SiteHasCookieInOtherPartition(site, partition_key),
6399 testing::Optional(false));
6400
6401 // Should return nullopt when the partition key is nullopt.
6402 EXPECT_FALSE(
6403 cm->SiteHasCookieInOtherPartition(site, /*partition_key=*/std::nullopt));
6404 }
6405
6406 // Test that domain cookies which shadow origin cookies are excluded when scheme
6407 // binding is enabled.
TEST_F(CookieMonsterTest,FilterCookiesWithOptionsExcludeShadowingDomains)6408 TEST_F(CookieMonsterTest, FilterCookiesWithOptionsExcludeShadowingDomains) {
6409 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
6410 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
6411 base::Time creation_time = base::Time::Now();
6412 std::optional<base::Time> server_time = std::nullopt;
6413 CookieOptions options = CookieOptions::MakeAllInclusive();
6414 options.set_return_excluded_cookies();
6415
6416 auto CookieListsMatch = [](const CookieAccessResultList& actual,
6417 const CookieList& expected) {
6418 if (actual.size() != expected.size()) {
6419 return false;
6420 }
6421
6422 for (size_t i = 0; i < actual.size(); i++) {
6423 if (!actual[i].cookie.IsEquivalent(expected[i])) {
6424 return false;
6425 }
6426 }
6427
6428 return true;
6429 };
6430
6431 // We only exclude shadowing domain cookies when scheme binding is enabled.
6432 base::test::ScopedFeatureList scoped_feature_list;
6433 scoped_feature_list.InitWithFeatures(
6434 {net::features::kEnableSchemeBoundCookies},
6435 {net::features::kEnablePortBoundCookies});
6436
6437 std::vector<CanonicalCookie*> cookie_ptrs;
6438 CookieAccessResultList included;
6439 CookieAccessResultList excluded;
6440
6441 auto reset = [&cookie_ptrs, &included, &excluded]() {
6442 cookie_ptrs.clear();
6443 included.clear();
6444 excluded.clear();
6445 };
6446
6447 auto origin_cookie1 = CanonicalCookie::CreateForTesting(
6448 https_www_foo_.url(), "foo1=origin", creation_time, server_time);
6449 auto origin_cookie2 = CanonicalCookie::CreateForTesting(
6450 https_www_foo_.url(), "foo2=origin", creation_time, server_time);
6451
6452 auto domain_cookie1 = CanonicalCookie::CreateForTesting(
6453 https_www_foo_.url(), "foo1=domain; Domain=" + https_www_foo_.domain(),
6454 creation_time, server_time);
6455
6456 // Shadowing domain cookie after the origin cookie.
6457 cookie_ptrs = {origin_cookie1.get(), origin_cookie2.get(),
6458 domain_cookie1.get()};
6459 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6460 &included, &excluded);
6461 EXPECT_TRUE(CookieListsMatch(included, {*origin_cookie1, *origin_cookie2}));
6462 EXPECT_TRUE(CookieListsMatch(excluded, {*domain_cookie1}));
6463 reset();
6464
6465 // Shadowing domain cookie before the origin cookie.
6466 cookie_ptrs = {domain_cookie1.get(), origin_cookie2.get(),
6467 origin_cookie1.get()};
6468 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6469 &included, &excluded);
6470 EXPECT_TRUE(CookieListsMatch(included, {*origin_cookie2, *origin_cookie1}));
6471 EXPECT_TRUE(CookieListsMatch(excluded, {*domain_cookie1}));
6472 reset();
6473
6474 auto domain_cookie2 = CanonicalCookie::CreateForTesting(
6475 https_www_foo_.url(), "foo2=domain; Domain=" + https_www_foo_.domain(),
6476 creation_time, server_time);
6477
6478 // Multiple different shadowing domain cookies.
6479 cookie_ptrs = {domain_cookie1.get(), origin_cookie2.get(),
6480 origin_cookie1.get(), domain_cookie2.get()};
6481 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6482 &included, &excluded);
6483 EXPECT_TRUE(CookieListsMatch(included, {*origin_cookie2, *origin_cookie1}));
6484 EXPECT_TRUE(CookieListsMatch(excluded, {*domain_cookie1, *domain_cookie2}));
6485 reset();
6486
6487 auto domain_cookie3 = CanonicalCookie::CreateForTesting(
6488 https_www_foo_.url(), "foo3=domain; Domain=" + https_www_foo_.domain(),
6489 creation_time, server_time);
6490
6491 // Non-shadowing domain cookie should be included.
6492 cookie_ptrs = {domain_cookie1.get(), origin_cookie2.get(),
6493 origin_cookie1.get(), domain_cookie2.get(),
6494 domain_cookie3.get()};
6495 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6496 &included, &excluded);
6497 EXPECT_TRUE(CookieListsMatch(
6498 included, {*origin_cookie2, *origin_cookie1, *domain_cookie3}));
6499 EXPECT_TRUE(CookieListsMatch(excluded, {*domain_cookie1, *domain_cookie2}));
6500 reset();
6501
6502 auto sub_domain_cookie1 = CanonicalCookie::CreateForTesting(
6503 https_www_foo_.url(), "foo1=subdomain; Domain=" + https_www_foo_.host(),
6504 creation_time, server_time);
6505
6506 // If there are multiple domain cookies that shadow the same cookie, they
6507 // should all be excluded.
6508 cookie_ptrs = {domain_cookie1.get(), origin_cookie2.get(),
6509 origin_cookie1.get(), sub_domain_cookie1.get()};
6510 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6511 &included, &excluded);
6512 EXPECT_TRUE(CookieListsMatch(included, {*origin_cookie2, *origin_cookie1}));
6513 EXPECT_TRUE(
6514 CookieListsMatch(excluded, {*domain_cookie1, *sub_domain_cookie1}));
6515 reset();
6516
6517 // Domain cookies may shadow each other.
6518 cookie_ptrs = {domain_cookie1.get(), sub_domain_cookie1.get()};
6519 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6520 &included, &excluded);
6521 EXPECT_TRUE(
6522 CookieListsMatch(included, {*domain_cookie1, *sub_domain_cookie1}));
6523 EXPECT_TRUE(CookieListsMatch(excluded, {}));
6524 reset();
6525
6526 auto path_origin_cookie1 = CanonicalCookie::CreateForTesting(
6527 https_www_foo_.url(), "foo1=pathorigin; Path=/bar", creation_time,
6528 server_time);
6529
6530 // Origin cookies on different paths may not be shadowed, even if the
6531 // origin cookie wouldn't be included on this request.
6532 cookie_ptrs = {path_origin_cookie1.get(), domain_cookie1.get()};
6533 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6534 &included, &excluded);
6535 EXPECT_TRUE(CookieListsMatch(included, {}));
6536 EXPECT_TRUE(
6537 CookieListsMatch(excluded, {*path_origin_cookie1, *domain_cookie1}));
6538 reset();
6539
6540 auto insecure_origin_cookie1 = CanonicalCookie::CreateForTesting(
6541 http_www_foo_.url(), "foo1=insecureorigin", creation_time, server_time);
6542 EXPECT_EQ(insecure_origin_cookie1->SourceScheme(),
6543 CookieSourceScheme::kNonSecure);
6544
6545 // Origin cookies that are excluded due to scheme binding don't affect domain
6546 // cookies.
6547 cookie_ptrs = {insecure_origin_cookie1.get(), domain_cookie1.get()};
6548 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6549 &included, &excluded);
6550 EXPECT_TRUE(CookieListsMatch(included, {*domain_cookie1}));
6551 EXPECT_TRUE(CookieListsMatch(excluded, {*insecure_origin_cookie1}));
6552 EXPECT_TRUE(
6553 excluded[0].access_result.status.HasExactlyExclusionReasonsForTesting(
6554 {CookieInclusionStatus::EXCLUDE_SCHEME_MISMATCH}));
6555 reset();
6556
6557 auto insecure_domain_cookie1 = CanonicalCookie::CreateForTesting(
6558 http_www_foo_.url(),
6559 "foo1=insecuredomain; Domain=" + http_www_foo_.domain(), creation_time,
6560 server_time);
6561
6562 // Domain cookies that are excluded due to scheme binding shouldn't also be
6563 // exclude because of shadowing.
6564 cookie_ptrs = {origin_cookie1.get(), insecure_domain_cookie1.get()};
6565 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6566 &included, &excluded);
6567 EXPECT_TRUE(CookieListsMatch(included, {*origin_cookie1}));
6568 EXPECT_TRUE(CookieListsMatch(excluded, {*insecure_domain_cookie1}));
6569 EXPECT_TRUE(
6570 excluded[0].access_result.status.HasExactlyExclusionReasonsForTesting(
6571 {CookieInclusionStatus::EXCLUDE_SCHEME_MISMATCH}));
6572 reset();
6573
6574 // If both domain and origin cookie are excluded due to scheme binding then
6575 // domain cookie shouldn't get shadowing exclusion.
6576 cookie_ptrs = {insecure_origin_cookie1.get(), insecure_domain_cookie1.get()};
6577 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6578 &included, &excluded);
6579 EXPECT_TRUE(CookieListsMatch(included, {}));
6580 EXPECT_TRUE(CookieListsMatch(
6581 excluded, {*insecure_origin_cookie1, *insecure_domain_cookie1}));
6582 EXPECT_TRUE(
6583 excluded[1].access_result.status.HasExactlyExclusionReasonsForTesting(
6584 {CookieInclusionStatus::EXCLUDE_SCHEME_MISMATCH}));
6585 reset();
6586
6587 cm->SetCookieAccessDelegate(std::make_unique<TestCookieAccessDelegate>());
6588
6589 CookieURLHelper http_www_trustworthy =
6590 CookieURLHelper("http://www.trustworthysitefortestdelegate.example");
6591 CookieURLHelper https_www_trustworthy =
6592 CookieURLHelper("https://www.trustworthysitefortestdelegate.example");
6593
6594 auto trust_origin_cookie1 = CanonicalCookie::CreateForTesting(
6595 http_www_trustworthy.url(), "foo1=trustorigin", creation_time,
6596 server_time);
6597
6598 auto secure_trust_domain_cookie1 = CanonicalCookie::CreateForTesting(
6599 https_www_trustworthy.url(),
6600 "foo1=securetrustdomain; Domain=" + https_www_trustworthy.domain(),
6601 creation_time, server_time);
6602 auto secure_trust_domain_cookie2 = CanonicalCookie::CreateForTesting(
6603 https_www_trustworthy.url(),
6604 "foo2=securetrustdomain; Domain=" + https_www_trustworthy.domain(),
6605 creation_time, server_time);
6606
6607 // Securely set domain cookies are excluded when shadowing trustworthy-ly set
6608 // origin cookies.
6609 cookie_ptrs = {trust_origin_cookie1.get(), secure_trust_domain_cookie1.get(),
6610 secure_trust_domain_cookie2.get()};
6611 cm->FilterCookiesWithOptions(http_www_trustworthy.url(), options,
6612 &cookie_ptrs, &included, &excluded);
6613 EXPECT_TRUE(CookieListsMatch(
6614 included, {*trust_origin_cookie1, *secure_trust_domain_cookie2}));
6615 EXPECT_TRUE(CookieListsMatch(excluded, {*secure_trust_domain_cookie1}));
6616 reset();
6617
6618 auto trust_domain_cookie1 = CanonicalCookie::CreateForTesting(
6619 http_www_trustworthy.url(),
6620 "foo1=trustdomain; Domain=" + http_www_trustworthy.domain(),
6621 creation_time, server_time);
6622 auto trust_domain_cookie2 = CanonicalCookie::CreateForTesting(
6623 http_www_trustworthy.url(),
6624 "foo2=trustdomain; Domain=" + http_www_trustworthy.domain(),
6625 creation_time, server_time);
6626 auto secure_trust_origin_cookie1 = CanonicalCookie::CreateForTesting(
6627 https_www_trustworthy.url(), "foo1=securetrustorigin", creation_time,
6628 server_time);
6629
6630 // Trustworthy-ly set domain cookies are excluded when shadowing securely set
6631 // origin cookies.
6632 cookie_ptrs = {secure_trust_origin_cookie1.get(), trust_domain_cookie1.get(),
6633 trust_domain_cookie2.get()};
6634 cm->FilterCookiesWithOptions(http_www_trustworthy.url(), options,
6635 &cookie_ptrs, &included, &excluded);
6636 EXPECT_TRUE(CookieListsMatch(
6637 included, {*secure_trust_origin_cookie1, *trust_domain_cookie2}));
6638 EXPECT_TRUE(CookieListsMatch(excluded, {*trust_domain_cookie1}));
6639 reset();
6640
6641 auto port_origin_cookie1 = CanonicalCookie::CreateForTesting(
6642 https_www_foo_.url(), "foo1=differentportorigin", creation_time,
6643 server_time);
6644 port_origin_cookie1->SetSourcePort(123);
6645
6646 // Origin cookies that have warnings due to port binding don't affect domain
6647 // cookies.
6648 cookie_ptrs = {port_origin_cookie1.get(), domain_cookie1.get()};
6649 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6650 &included, &excluded);
6651 EXPECT_TRUE(
6652 CookieListsMatch(included, {*port_origin_cookie1, *domain_cookie1}));
6653 EXPECT_TRUE(included[0].access_result.status.HasWarningReason(
6654 CookieInclusionStatus::WARN_PORT_MISMATCH));
6655 reset();
6656
6657 auto port_insecure_origin_cookie1 =
6658 std::make_unique<CanonicalCookie>(*insecure_origin_cookie1);
6659 port_insecure_origin_cookie1->SetSourcePort(123);
6660
6661 // Origin cookies that have excluded due to scheme binding and have a port
6662 // binding warning don't affect domain cookies.
6663 cookie_ptrs = {port_insecure_origin_cookie1.get(), domain_cookie1.get()};
6664 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6665 &included, &excluded);
6666 EXPECT_TRUE(CookieListsMatch(included, {*domain_cookie1}));
6667 EXPECT_TRUE(
6668 excluded[0].access_result.status.HasExactlyWarningReasonsForTesting(
6669 {CookieInclusionStatus::WARN_PORT_MISMATCH}));
6670 EXPECT_TRUE(
6671 excluded[0].access_result.status.HasExactlyExclusionReasonsForTesting(
6672 {CookieInclusionStatus::EXCLUDE_SCHEME_MISMATCH}));
6673 reset();
6674
6675 // Enable port binding to test with port exclusions.
6676 scoped_feature_list.Reset();
6677 scoped_feature_list.InitWithFeatures(
6678 {net::features::kEnableSchemeBoundCookies,
6679 net::features::kEnablePortBoundCookies},
6680 {});
6681
6682 // Origin cookies that are excluded due to port binding don't affect domain
6683 // cookies.
6684 cookie_ptrs = {port_origin_cookie1.get(), domain_cookie1.get()};
6685 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6686 &included, &excluded);
6687 EXPECT_TRUE(CookieListsMatch(included, {*domain_cookie1}));
6688 EXPECT_TRUE(CookieListsMatch(excluded, {*port_origin_cookie1}));
6689 EXPECT_TRUE(
6690 excluded[0].access_result.status.HasExactlyExclusionReasonsForTesting(
6691 {CookieInclusionStatus::EXCLUDE_PORT_MISMATCH}));
6692 reset();
6693
6694 // Origin cookies that are excluded due to scheme and port binding don't
6695 // affect domain cookies.
6696 cookie_ptrs = {port_insecure_origin_cookie1.get(), domain_cookie1.get()};
6697 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6698 &included, &excluded);
6699 EXPECT_TRUE(CookieListsMatch(included, {*domain_cookie1}));
6700 EXPECT_TRUE(CookieListsMatch(excluded, {*port_insecure_origin_cookie1}));
6701 EXPECT_TRUE(
6702 excluded[0].access_result.status.HasExactlyExclusionReasonsForTesting(
6703 {CookieInclusionStatus::EXCLUDE_SCHEME_MISMATCH,
6704 CookieInclusionStatus::EXCLUDE_PORT_MISMATCH}));
6705 reset();
6706 }
6707
6708 // Test that domain cookies which shadow origin cookies have warnings when
6709 // scheme binding is disabled.
TEST_F(CookieMonsterTest,FilterCookiesWithOptionsWarnShadowingDomains)6710 TEST_F(CookieMonsterTest, FilterCookiesWithOptionsWarnShadowingDomains) {
6711 auto store = base::MakeRefCounted<MockPersistentCookieStore>();
6712 auto cm = std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
6713 base::Time creation_time = base::Time::Now();
6714 std::optional<base::Time> server_time = std::nullopt;
6715 CookieOptions options = CookieOptions::MakeAllInclusive();
6716 options.set_return_excluded_cookies();
6717
6718 auto CookieListsMatch = [](const CookieAccessResultList& actual,
6719 const std::vector<CanonicalCookie*>& expected) {
6720 if (actual.size() != expected.size()) {
6721 return false;
6722 }
6723
6724 for (size_t i = 0; i < actual.size(); i++) {
6725 if (!actual[i].cookie.IsEquivalent(*expected[i])) {
6726 return false;
6727 }
6728 }
6729
6730 return true;
6731 };
6732
6733 // Confirms that of all the cookies in `actual` only the ones also in
6734 // `expected` have WARN_SHADOWING_DOMAIN.
6735 auto DomainCookiesHaveWarnings =
6736 [](const CookieAccessResultList& actual,
6737 const std::vector<CanonicalCookie>& expected) {
6738 std::map<CanonicalCookie, CookieInclusionStatus> cookie_result_map;
6739 for (const auto& cookie_result : actual) {
6740 cookie_result_map.insert(
6741 {cookie_result.cookie, cookie_result.access_result.status});
6742 }
6743
6744 for (const auto& cookie : expected) {
6745 // This is a touch hacky but will always work because if the
6746 // cookie_result_map doesn't contain `cookie` it'll create a default
6747 // entry with an empty status which will always fail the check. I.e.:
6748 // return false.
6749 if (!cookie_result_map[cookie].HasWarningReason(
6750 CookieInclusionStatus::WARN_SHADOWING_DOMAIN)) {
6751 return false;
6752 }
6753
6754 // Remove cookies that were part of `expected`.
6755 cookie_result_map.erase(cookie);
6756 }
6757
6758 // If any of the remaining cookies have the warning, return false.
6759 for (const auto& item : cookie_result_map) {
6760 if (item.second.HasWarningReason(
6761 CookieInclusionStatus::WARN_SHADOWING_DOMAIN)) {
6762 return false;
6763 }
6764 }
6765
6766 return true;
6767 };
6768
6769 // We only apply warnings to shadowing domain cookies when scheme binding is
6770 // disabled.
6771 base::test::ScopedFeatureList scoped_feature_list;
6772 scoped_feature_list.InitWithFeatures(
6773 {}, {net::features::kEnableSchemeBoundCookies,
6774 net::features::kEnablePortBoundCookies});
6775
6776 std::vector<CanonicalCookie*> cookie_ptrs;
6777 CookieAccessResultList included;
6778 CookieAccessResultList excluded;
6779
6780 auto reset = [&cookie_ptrs, &included, &excluded]() {
6781 cookie_ptrs.clear();
6782 included.clear();
6783 excluded.clear();
6784 };
6785
6786 auto origin_cookie1 = CanonicalCookie::CreateForTesting(
6787 https_www_foo_.url(), "foo1=origin", creation_time, server_time);
6788 auto origin_cookie2 = CanonicalCookie::CreateForTesting(
6789 https_www_foo_.url(), "foo2=origin", creation_time, server_time);
6790
6791 auto domain_cookie1 = CanonicalCookie::CreateForTesting(
6792 https_www_foo_.url(), "foo1=domain; Domain=" + https_www_foo_.domain(),
6793 creation_time, server_time);
6794
6795 // Shadowing domain cookie after the origin cookie.
6796 cookie_ptrs = {origin_cookie1.get(), origin_cookie2.get(),
6797 domain_cookie1.get()};
6798 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6799 &included, &excluded);
6800 EXPECT_TRUE(CookieListsMatch(included, cookie_ptrs));
6801 EXPECT_TRUE(DomainCookiesHaveWarnings(included, {*domain_cookie1}));
6802 reset();
6803
6804 // Shadowing domain cookie before the origin cookie.
6805 cookie_ptrs = {domain_cookie1.get(), origin_cookie2.get(),
6806 origin_cookie1.get()};
6807 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6808 &included, &excluded);
6809 EXPECT_TRUE(CookieListsMatch(included, cookie_ptrs));
6810 EXPECT_TRUE(DomainCookiesHaveWarnings(included, {*domain_cookie1}));
6811 reset();
6812
6813 auto domain_cookie2 = CanonicalCookie::CreateForTesting(
6814 https_www_foo_.url(), "foo2=domain; Domain=" + https_www_foo_.domain(),
6815 creation_time, server_time);
6816
6817 // Multiple different shadowing domain cookies.
6818 cookie_ptrs = {domain_cookie1.get(), origin_cookie2.get(),
6819 origin_cookie1.get(), domain_cookie2.get()};
6820 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6821 &included, &excluded);
6822 EXPECT_TRUE(CookieListsMatch(included, cookie_ptrs));
6823 EXPECT_TRUE(
6824 DomainCookiesHaveWarnings(included, {*domain_cookie1, *domain_cookie2}));
6825 reset();
6826
6827 auto domain_cookie3 = CanonicalCookie::CreateForTesting(
6828 https_www_foo_.url(), "foo3=domain; Domain=" + https_www_foo_.domain(),
6829 creation_time, server_time);
6830
6831 // Non-shadowing domain cookie shouldn't have a warning.
6832 cookie_ptrs = {domain_cookie1.get(), origin_cookie2.get(),
6833 origin_cookie1.get(), domain_cookie2.get(),
6834 domain_cookie3.get()};
6835 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6836 &included, &excluded);
6837 EXPECT_TRUE(CookieListsMatch(included, cookie_ptrs));
6838 EXPECT_TRUE(
6839 DomainCookiesHaveWarnings(included, {*domain_cookie1, *domain_cookie2}));
6840 reset();
6841
6842 auto sub_domain_cookie1 = CanonicalCookie::CreateForTesting(
6843 https_www_foo_.url(), "foo1=subdomain; Domain=" + https_www_foo_.host(),
6844 creation_time, server_time);
6845
6846 // If there are multiple domain cookies that shadow the same cookie, they
6847 // should all have a warning.
6848 cookie_ptrs = {domain_cookie1.get(), origin_cookie2.get(),
6849 origin_cookie1.get(), sub_domain_cookie1.get()};
6850 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6851 &included, &excluded);
6852 EXPECT_TRUE(CookieListsMatch(included, cookie_ptrs));
6853 EXPECT_TRUE(DomainCookiesHaveWarnings(
6854 included, {*domain_cookie1, *sub_domain_cookie1}));
6855 reset();
6856
6857 // Domain cookies may shadow each other.
6858 cookie_ptrs = {domain_cookie1.get(), sub_domain_cookie1.get()};
6859 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6860 &included, &excluded);
6861 EXPECT_TRUE(CookieListsMatch(included, cookie_ptrs));
6862 EXPECT_TRUE(DomainCookiesHaveWarnings(included, {}));
6863 reset();
6864
6865 auto path_origin_cookie1 = CanonicalCookie::CreateForTesting(
6866 https_www_foo_.url(), "foo1=pathorigin; Path=/bar", creation_time,
6867 server_time);
6868
6869 // Origin cookies on different paths may not be shadowed, even if the
6870 // origin cookie wouldn't be included on this request.
6871 cookie_ptrs = {path_origin_cookie1.get(), domain_cookie1.get()};
6872 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6873 &included, &excluded);
6874 EXPECT_TRUE(CookieListsMatch(included, {domain_cookie1.get()}));
6875 EXPECT_TRUE(DomainCookiesHaveWarnings(included, {*domain_cookie1}));
6876 reset();
6877
6878 auto insecure_origin_cookie1 = CanonicalCookie::CreateForTesting(
6879 http_www_foo_.url(), "foo1=insecureorigin", creation_time, server_time);
6880 EXPECT_EQ(insecure_origin_cookie1->SourceScheme(),
6881 CookieSourceScheme::kNonSecure);
6882
6883 // Origin cookies that have a warning for scheme binding don't affect domain
6884 // cookies.
6885 cookie_ptrs = {insecure_origin_cookie1.get(), domain_cookie1.get()};
6886 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6887 &included, &excluded);
6888 EXPECT_TRUE(CookieListsMatch(included, cookie_ptrs));
6889 EXPECT_TRUE(DomainCookiesHaveWarnings(included, {}));
6890 EXPECT_TRUE(included[0].access_result.status.HasWarningReason(
6891 CookieInclusionStatus::WARN_SCHEME_MISMATCH));
6892 reset();
6893
6894 auto insecure_domain_cookie1 = CanonicalCookie::CreateForTesting(
6895 http_www_foo_.url(),
6896 "foo1=insecuredomain; Domain=" + http_www_foo_.domain(), creation_time,
6897 server_time);
6898
6899 // Domain cookies that are excluded due to scheme binding shouldn't also get a
6900 // shadow warning.
6901 cookie_ptrs = {origin_cookie1.get(), insecure_domain_cookie1.get()};
6902 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6903 &included, &excluded);
6904 EXPECT_TRUE(CookieListsMatch(included, cookie_ptrs));
6905 EXPECT_TRUE(DomainCookiesHaveWarnings(included, {}));
6906 EXPECT_TRUE(
6907 included[1].access_result.status.HasExactlyWarningReasonsForTesting(
6908 {CookieInclusionStatus::WARN_SCHEME_MISMATCH}));
6909 reset();
6910
6911 // If both domain and origin cookie have warnings due to scheme binding then
6912 // domain cookie shouldn't get shadowing warning.
6913 cookie_ptrs = {insecure_origin_cookie1.get(), insecure_domain_cookie1.get()};
6914 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6915 &included, &excluded);
6916 EXPECT_TRUE(CookieListsMatch(included, cookie_ptrs));
6917 EXPECT_TRUE(DomainCookiesHaveWarnings(included, {}));
6918 EXPECT_TRUE(included[0].access_result.status.HasWarningReason(
6919 CookieInclusionStatus::WARN_SCHEME_MISMATCH));
6920 EXPECT_TRUE(
6921 included[1].access_result.status.HasExactlyWarningReasonsForTesting(
6922 {CookieInclusionStatus::WARN_SCHEME_MISMATCH}));
6923 reset();
6924
6925 cm->SetCookieAccessDelegate(std::make_unique<TestCookieAccessDelegate>());
6926
6927 CookieURLHelper http_www_trustworthy =
6928 CookieURLHelper("http://www.trustworthysitefortestdelegate.example");
6929 CookieURLHelper https_www_trustworthy =
6930 CookieURLHelper("https://www.trustworthysitefortestdelegate.example");
6931
6932 auto trust_origin_cookie1 = CanonicalCookie::CreateForTesting(
6933 http_www_trustworthy.url(), "foo1=trustorigin", creation_time,
6934 server_time);
6935
6936 auto secure_trust_domain_cookie1 = CanonicalCookie::CreateForTesting(
6937 https_www_trustworthy.url(),
6938 "foo1=securetrustdomain; Domain=" + https_www_trustworthy.domain(),
6939 creation_time, server_time);
6940 auto secure_trust_domain_cookie2 = CanonicalCookie::CreateForTesting(
6941 https_www_trustworthy.url(),
6942 "foo2=securetrustdomain; Domain=" + https_www_trustworthy.domain(),
6943 creation_time, server_time);
6944
6945 // Securely set domain cookie has warning when shadowing trustworthy-ly set
6946 // origin cookies.
6947 cookie_ptrs = {trust_origin_cookie1.get(), secure_trust_domain_cookie1.get(),
6948 secure_trust_domain_cookie2.get()};
6949 cm->FilterCookiesWithOptions(http_www_trustworthy.url(), options,
6950 &cookie_ptrs, &included, &excluded);
6951 EXPECT_TRUE(CookieListsMatch(included, cookie_ptrs));
6952 EXPECT_TRUE(
6953 DomainCookiesHaveWarnings(included, {*secure_trust_domain_cookie1}));
6954 reset();
6955
6956 auto trust_domain_cookie1 = CanonicalCookie::CreateForTesting(
6957 http_www_trustworthy.url(),
6958 "foo1=trustdomain; Domain=" + http_www_trustworthy.domain(),
6959 creation_time, server_time);
6960 auto trust_domain_cookie2 = CanonicalCookie::CreateForTesting(
6961 http_www_trustworthy.url(),
6962 "foo2=trustdomain; Domain=" + http_www_trustworthy.domain(),
6963 creation_time, server_time);
6964 auto secure_trust_origin_cookie1 = CanonicalCookie::CreateForTesting(
6965 https_www_trustworthy.url(), "foo1=securetrustorigin", creation_time,
6966 server_time);
6967
6968 // Trustworthy-ly set domain cookies are excluded when shadowing securely set
6969 // origin cookies.
6970 cookie_ptrs = {secure_trust_origin_cookie1.get(), trust_domain_cookie1.get(),
6971 trust_domain_cookie2.get()};
6972 cm->FilterCookiesWithOptions(http_www_trustworthy.url(), options,
6973 &cookie_ptrs, &included, &excluded);
6974 EXPECT_TRUE(CookieListsMatch(included, cookie_ptrs));
6975 EXPECT_TRUE(DomainCookiesHaveWarnings(included, {*trust_domain_cookie1}));
6976 reset();
6977
6978 auto port_origin_cookie1 = CanonicalCookie::CreateForTesting(
6979 https_www_foo_.url(), "foo1=differentportorigin", creation_time,
6980 server_time);
6981 port_origin_cookie1->SetSourcePort(123);
6982
6983 // Origin cookies that have warnings due to port binding don't affect domain
6984 // cookies.
6985 cookie_ptrs = {port_origin_cookie1.get(), domain_cookie1.get()};
6986 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
6987 &included, &excluded);
6988 EXPECT_TRUE(CookieListsMatch(included, cookie_ptrs));
6989 EXPECT_TRUE(DomainCookiesHaveWarnings(included, {}));
6990 EXPECT_TRUE(included[0].access_result.status.HasWarningReason(
6991 CookieInclusionStatus::WARN_PORT_MISMATCH));
6992 reset();
6993
6994 auto port_insecure_origin_cookie1 =
6995 std::make_unique<CanonicalCookie>(*insecure_origin_cookie1);
6996 port_insecure_origin_cookie1->SetSourcePort(123);
6997
6998 // Origin cookies that have warnings due to scheme and port binding don't
6999 // affect domain cookies.
7000 cookie_ptrs = {port_insecure_origin_cookie1.get(), domain_cookie1.get()};
7001 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
7002 &included, &excluded);
7003 EXPECT_TRUE(CookieListsMatch(included, cookie_ptrs));
7004 EXPECT_TRUE(DomainCookiesHaveWarnings(included, {}));
7005 EXPECT_TRUE(
7006 included[0].access_result.status.HasExactlyWarningReasonsForTesting(
7007 {CookieInclusionStatus::WARN_SCHEME_MISMATCH,
7008 CookieInclusionStatus::WARN_PORT_MISMATCH}));
7009 reset();
7010
7011 // Enable port binding to test with port exclusions.
7012 scoped_feature_list.Reset();
7013 scoped_feature_list.InitWithFeatures(
7014 {net::features::kEnablePortBoundCookies},
7015 {net::features::kEnableSchemeBoundCookies});
7016
7017 // Origin cookies that are excluded due to port binding don't affect domain
7018 // cookies.
7019 cookie_ptrs = {port_origin_cookie1.get(), domain_cookie1.get()};
7020 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
7021 &included, &excluded);
7022 EXPECT_TRUE(CookieListsMatch(included, {domain_cookie1.get()}));
7023 EXPECT_TRUE(DomainCookiesHaveWarnings(included, {}));
7024 EXPECT_TRUE(CookieListsMatch(excluded, {port_origin_cookie1.get()}));
7025 EXPECT_TRUE(
7026 excluded[0].access_result.status.HasExactlyExclusionReasonsForTesting(
7027 {CookieInclusionStatus::EXCLUDE_PORT_MISMATCH}));
7028 reset();
7029
7030 // Origin cookies that are excluded due to port binding and have a scheme
7031 // binding warning don't affect domain cookies.
7032 cookie_ptrs = {port_insecure_origin_cookie1.get(), domain_cookie1.get()};
7033 cm->FilterCookiesWithOptions(https_www_foo_.url(), options, &cookie_ptrs,
7034 &included, &excluded);
7035 EXPECT_TRUE(CookieListsMatch(included, {domain_cookie1.get()}));
7036 EXPECT_TRUE(DomainCookiesHaveWarnings(included, {}));
7037 EXPECT_TRUE(CookieListsMatch(excluded, {port_insecure_origin_cookie1.get()}));
7038 EXPECT_TRUE(
7039 excluded[0].access_result.status.HasExactlyExclusionReasonsForTesting(
7040 {CookieInclusionStatus::EXCLUDE_PORT_MISMATCH}));
7041 EXPECT_TRUE(excluded[0].access_result.status.HasWarningReason(
7042 CookieInclusionStatus::WARN_SCHEME_MISMATCH));
7043 reset();
7044 }
7045
7046 // This test sets a cookie (only checked using IsCanonicalForFromStorage)
7047 // that's 300 days old and expires in 800 days. It checks that this cookie was
7048 // stored, and then update it. It checks that the updated cookie has the
7049 // creation and expiry dates expected.
TEST_F(CookieMonsterTest,FromStorageCookieCreated300DaysAgoThenUpdatedNow)7050 TEST_F(CookieMonsterTest, FromStorageCookieCreated300DaysAgoThenUpdatedNow) {
7051 auto store = base::MakeRefCounted<FlushablePersistentStore>();
7052 auto cookie_monster =
7053 std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
7054 cookie_monster->SetPersistSessionCookies(true);
7055 EXPECT_TRUE(GetAllCookies(cookie_monster.get()).empty());
7056
7057 // Bypass IsCanonical and store a 300 day old cookie to bypass clamping.
7058 base::Time original_creation = base::Time::Now() - base::Days(300);
7059 base::Time original_expiry = original_creation + base::Days(800);
7060 CookieList list;
7061 list.push_back(*CanonicalCookie::CreateUnsafeCookieForTesting(
7062 "A", "B", "." + https_www_foo_.url().host(), "/", original_creation,
7063 original_expiry, base::Time(), base::Time(), true, false,
7064 CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT));
7065 EXPECT_TRUE(SetAllCookies(cookie_monster.get(), list));
7066
7067 // Verify the cookie exists and was not clamped, even if clamping is on.
7068 EXPECT_THAT(GetAllCookies(cookie_monster.get()),
7069 ElementsAre(MatchesCookieNameValueCreationExpiry(
7070 "A", "B", original_creation, original_expiry)));
7071
7072 // Update the cookie without bypassing clamping.
7073 base::Time new_creation = base::Time::Now();
7074 base::Time new_expiry = new_creation + base::Days(800);
7075 EXPECT_TRUE(SetCanonicalCookie(
7076 cookie_monster.get(),
7077 CanonicalCookie::CreateSanitizedCookie(
7078 https_www_foo_.url(), "A", "B", https_www_foo_.url().host(), "/",
7079 new_creation, new_expiry, base::Time(), true, false,
7080 CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, std::nullopt,
7081 /*status=*/nullptr),
7082 https_www_foo_.url(), false));
7083 EXPECT_THAT(
7084 GetAllCookies(cookie_monster.get()),
7085 ElementsAre(MatchesCookieNameValueCreationExpiry(
7086 "A", "B", original_creation, new_creation + base::Days(400))));
7087 }
7088
7089 // This test sets a cookie (only checked using IsCanonicalForFromStorage)
7090 // that's 500 days old and expires in 800 days. It checks that this cookie was
7091 // stored, and then update it. It checks that the updated cookie has the
7092 // creation and expiry dates expected.
TEST_F(CookieMonsterTest,FromStorageCookieCreated500DaysAgoThenUpdatedNow)7093 TEST_F(CookieMonsterTest, FromStorageCookieCreated500DaysAgoThenUpdatedNow) {
7094 auto store = base::MakeRefCounted<FlushablePersistentStore>();
7095 auto cookie_monster =
7096 std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
7097 cookie_monster->SetPersistSessionCookies(true);
7098 EXPECT_TRUE(GetAllCookies(cookie_monster.get()).empty());
7099
7100 // Bypass IsCanonical and store a 500 day old cookie to bypass clamping.
7101 base::Time original_creation = base::Time::Now() - base::Days(500);
7102 base::Time original_expiry = original_creation + base::Days(800);
7103 CookieList list;
7104 list.push_back(*CanonicalCookie::CreateUnsafeCookieForTesting(
7105 "A", "B", "." + https_www_foo_.url().host(), "/", original_creation,
7106 original_expiry, base::Time(), base::Time(), true, false,
7107 CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT));
7108 EXPECT_TRUE(SetAllCookies(cookie_monster.get(), list));
7109
7110 // Verify the cookie exists and was not clamped, even if clamping is on.
7111 EXPECT_THAT(GetAllCookies(cookie_monster.get()),
7112 ElementsAre(MatchesCookieNameValueCreationExpiry(
7113 "A", "B", original_creation, original_expiry)));
7114
7115 // Update the cookie without bypassing clamping.
7116 base::Time new_creation = base::Time::Now();
7117 base::Time new_expiry = new_creation + base::Days(800);
7118 EXPECT_TRUE(SetCanonicalCookie(
7119 cookie_monster.get(),
7120 CanonicalCookie::CreateSanitizedCookie(
7121 https_www_foo_.url(), "A", "B", https_www_foo_.url().host(), "/",
7122 new_creation, new_expiry, base::Time(), true, false,
7123 CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, std::nullopt,
7124 /*status=*/nullptr),
7125 https_www_foo_.url(), false));
7126 EXPECT_THAT(
7127 GetAllCookies(cookie_monster.get()),
7128 ElementsAre(MatchesCookieNameValueCreationExpiry(
7129 "A", "B", original_creation, new_creation + base::Days(400))));
7130 }
7131
7132 // This test sets a cookie (checked using IsCanonical) that's 300 days old and
7133 // expires in 800 days. It checks that this cookie was stored, and then update
7134 // it. It checks that the updated cookie has the creation and expiry dates
7135 // expected.
TEST_F(CookieMonsterTest,SanitizedCookieCreated300DaysAgoThenUpdatedNow)7136 TEST_F(CookieMonsterTest, SanitizedCookieCreated300DaysAgoThenUpdatedNow) {
7137 auto store = base::MakeRefCounted<FlushablePersistentStore>();
7138 auto cookie_monster =
7139 std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
7140 cookie_monster->SetPersistSessionCookies(true);
7141 EXPECT_TRUE(GetAllCookies(cookie_monster.get()).empty());
7142
7143 // Store a 300 day old cookie without bypassing clamping.
7144 base::Time original_creation = base::Time::Now() - base::Days(300);
7145 base::Time original_expiry = original_creation + base::Days(800);
7146 EXPECT_TRUE(SetCanonicalCookie(
7147 cookie_monster.get(),
7148 CanonicalCookie::CreateSanitizedCookie(
7149 https_www_foo_.url(), "A", "B", https_www_foo_.url().host(), "/",
7150 original_creation, original_expiry, base::Time(), true, false,
7151 CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, std::nullopt,
7152 /*status=*/nullptr),
7153 https_www_foo_.url(), false));
7154 EXPECT_THAT(
7155 GetAllCookies(cookie_monster.get()),
7156 ElementsAre(MatchesCookieNameValueCreationExpiry(
7157 "A", "B", original_creation, original_creation + base::Days(400))));
7158
7159 // Update the cookie without bypassing clamping.
7160 base::Time new_creation = base::Time::Now();
7161 base::Time new_expiry = new_creation + base::Days(800);
7162 EXPECT_TRUE(SetCanonicalCookie(
7163 cookie_monster.get(),
7164 CanonicalCookie::CreateSanitizedCookie(
7165 https_www_foo_.url(), "A", "B", https_www_foo_.url().host(), "/",
7166 new_creation, new_expiry, base::Time(), true, false,
7167 CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, std::nullopt,
7168 /*status=*/nullptr),
7169 https_www_foo_.url(), false));
7170 EXPECT_THAT(
7171 GetAllCookies(cookie_monster.get()),
7172 ElementsAre(MatchesCookieNameValueCreationExpiry(
7173 "A", "B", original_creation, new_creation + base::Days(400))));
7174 }
7175
7176 // This test sets a cookie (checked using IsCanonical) that's 500 days old and
7177 // expires in 800 days. It checks that this cookie was stored, and then update
7178 // it. It checks that the updated cookie has the creation and expiry dates
7179 // expected.
TEST_F(CookieMonsterTest,SanitizedCookieCreated500DaysAgoThenUpdatedNow)7180 TEST_F(CookieMonsterTest, SanitizedCookieCreated500DaysAgoThenUpdatedNow) {
7181 auto store = base::MakeRefCounted<FlushablePersistentStore>();
7182 auto cookie_monster =
7183 std::make_unique<CookieMonster>(store.get(), net::NetLog::Get());
7184 cookie_monster->SetPersistSessionCookies(true);
7185 EXPECT_TRUE(GetAllCookies(cookie_monster.get()).empty());
7186
7187 // Store a 500 day old cookie without bypassing clamping.
7188 base::Time original_creation = base::Time::Now() - base::Days(500);
7189 base::Time original_expiry = original_creation + base::Days(800);
7190 EXPECT_TRUE(SetCanonicalCookie(
7191 cookie_monster.get(),
7192 CanonicalCookie::CreateSanitizedCookie(
7193 https_www_foo_.url(), "A", "B", https_www_foo_.url().host(), "/",
7194 original_creation, original_expiry, base::Time(), true, false,
7195 CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, std::nullopt,
7196 /*status=*/nullptr),
7197 https_www_foo_.url(), false));
7198 EXPECT_TRUE(GetAllCookies(cookie_monster.get()).empty());
7199
7200 // Update the cookie without bypassing clamping.
7201 base::Time new_creation = base::Time::Now();
7202 base::Time new_expiry = new_creation + base::Days(800);
7203 EXPECT_TRUE(SetCanonicalCookie(
7204 cookie_monster.get(),
7205 CanonicalCookie::CreateSanitizedCookie(
7206 https_www_foo_.url(), "A", "B", https_www_foo_.url().host(), "/",
7207 new_creation, new_expiry, base::Time(), true, false,
7208 CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, std::nullopt,
7209 /*status=*/nullptr),
7210 https_www_foo_.url(), false));
7211 EXPECT_THAT(GetAllCookies(cookie_monster.get()),
7212 ElementsAre(MatchesCookieNameValueCreationExpiry(
7213 "A", "B", new_creation, new_creation + base::Days(400))));
7214 }
7215
7216 INSTANTIATE_TEST_SUITE_P(/* no label */,
7217 CookieMonsterTestPriorityGarbageCollectionObc,
7218 testing::Combine(testing::Bool(), testing::Bool()));
7219
7220 INSTANTIATE_TEST_SUITE_P(/* no label */,
7221 CookieMonsterTestGarbageCollectionObc,
7222 testing::ValuesIn(std::vector<std::tuple<bool, bool>>{
7223 {true, false},
7224 {false, true},
7225 {true, true}}));
7226
7227 } // namespace net
7228