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