xref: /aosp_15_r20/external/cronet/net/cookies/cookie_monster.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker // Portions of this code based on Mozilla:
6*6777b538SAndroid Build Coastguard Worker //   (netwerk/cookie/src/nsCookieService.cpp)
7*6777b538SAndroid Build Coastguard Worker /* ***** BEGIN LICENSE BLOCK *****
8*6777b538SAndroid Build Coastguard Worker  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
9*6777b538SAndroid Build Coastguard Worker  *
10*6777b538SAndroid Build Coastguard Worker  * The contents of this file are subject to the Mozilla Public License Version
11*6777b538SAndroid Build Coastguard Worker  * 1.1 (the "License"); you may not use this file except in compliance with
12*6777b538SAndroid Build Coastguard Worker  * the License. You may obtain a copy of the License at
13*6777b538SAndroid Build Coastguard Worker  * http://www.mozilla.org/MPL/
14*6777b538SAndroid Build Coastguard Worker  *
15*6777b538SAndroid Build Coastguard Worker  * Software distributed under the License is distributed on an "AS IS" basis,
16*6777b538SAndroid Build Coastguard Worker  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
17*6777b538SAndroid Build Coastguard Worker  * for the specific language governing rights and limitations under the
18*6777b538SAndroid Build Coastguard Worker  * License.
19*6777b538SAndroid Build Coastguard Worker  *
20*6777b538SAndroid Build Coastguard Worker  * The Original Code is mozilla.org code.
21*6777b538SAndroid Build Coastguard Worker  *
22*6777b538SAndroid Build Coastguard Worker  * The Initial Developer of the Original Code is
23*6777b538SAndroid Build Coastguard Worker  * Netscape Communications Corporation.
24*6777b538SAndroid Build Coastguard Worker  * Portions created by the Initial Developer are Copyright (C) 2003
25*6777b538SAndroid Build Coastguard Worker  * the Initial Developer. All Rights Reserved.
26*6777b538SAndroid Build Coastguard Worker  *
27*6777b538SAndroid Build Coastguard Worker  * Contributor(s):
28*6777b538SAndroid Build Coastguard Worker  *   Daniel Witte ([email protected])
29*6777b538SAndroid Build Coastguard Worker  *   Michiel van Leeuwen ([email protected])
30*6777b538SAndroid Build Coastguard Worker  *
31*6777b538SAndroid Build Coastguard Worker  * Alternatively, the contents of this file may be used under the terms of
32*6777b538SAndroid Build Coastguard Worker  * either the GNU General Public License Version 2 or later (the "GPL"), or
33*6777b538SAndroid Build Coastguard Worker  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
34*6777b538SAndroid Build Coastguard Worker  * in which case the provisions of the GPL or the LGPL are applicable instead
35*6777b538SAndroid Build Coastguard Worker  * of those above. If you wish to allow use of your version of this file only
36*6777b538SAndroid Build Coastguard Worker  * under the terms of either the GPL or the LGPL, and not to allow others to
37*6777b538SAndroid Build Coastguard Worker  * use your version of this file under the terms of the MPL, indicate your
38*6777b538SAndroid Build Coastguard Worker  * decision by deleting the provisions above and replace them with the notice
39*6777b538SAndroid Build Coastguard Worker  * and other provisions required by the GPL or the LGPL. If you do not delete
40*6777b538SAndroid Build Coastguard Worker  * the provisions above, a recipient may use your version of this file under
41*6777b538SAndroid Build Coastguard Worker  * the terms of any one of the MPL, the GPL or the LGPL.
42*6777b538SAndroid Build Coastguard Worker  *
43*6777b538SAndroid Build Coastguard Worker  * ***** END LICENSE BLOCK ***** */
44*6777b538SAndroid Build Coastguard Worker 
45*6777b538SAndroid Build Coastguard Worker #include "net/cookies/cookie_monster.h"
46*6777b538SAndroid Build Coastguard Worker 
47*6777b538SAndroid Build Coastguard Worker #include <functional>
48*6777b538SAndroid Build Coastguard Worker #include <list>
49*6777b538SAndroid Build Coastguard Worker #include <numeric>
50*6777b538SAndroid Build Coastguard Worker #include <optional>
51*6777b538SAndroid Build Coastguard Worker #include <set>
52*6777b538SAndroid Build Coastguard Worker #include <string_view>
53*6777b538SAndroid Build Coastguard Worker #include <utility>
54*6777b538SAndroid Build Coastguard Worker 
55*6777b538SAndroid Build Coastguard Worker #include "base/check_is_test.h"
56*6777b538SAndroid Build Coastguard Worker #include "base/containers/flat_map.h"
57*6777b538SAndroid Build Coastguard Worker #include "base/feature_list.h"
58*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
59*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback.h"
60*6777b538SAndroid Build Coastguard Worker #include "base/location.h"
61*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
62*6777b538SAndroid Build Coastguard Worker #include "base/metrics/field_trial.h"
63*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_functions.h"
64*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_macros.h"
65*6777b538SAndroid Build Coastguard Worker #include "base/ranges/algorithm.h"
66*6777b538SAndroid Build Coastguard Worker #include "base/strings/strcat.h"
67*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
68*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
69*6777b538SAndroid Build Coastguard Worker #include "base/task/single_thread_task_runner.h"
70*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_checker.h"
71*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h"
72*6777b538SAndroid Build Coastguard Worker #include "net/base/isolation_info.h"
73*6777b538SAndroid Build Coastguard Worker #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
74*6777b538SAndroid Build Coastguard Worker #include "net/base/schemeful_site.h"
75*6777b538SAndroid Build Coastguard Worker #include "net/base/url_util.h"
76*6777b538SAndroid Build Coastguard Worker #include "net/cookies/canonical_cookie.h"
77*6777b538SAndroid Build Coastguard Worker #include "net/cookies/cookie_constants.h"
78*6777b538SAndroid Build Coastguard Worker #include "net/cookies/cookie_monster_change_dispatcher.h"
79*6777b538SAndroid Build Coastguard Worker #include "net/cookies/cookie_monster_netlog_params.h"
80*6777b538SAndroid Build Coastguard Worker #include "net/cookies/cookie_partition_key.h"
81*6777b538SAndroid Build Coastguard Worker #include "net/cookies/cookie_partition_key_collection.h"
82*6777b538SAndroid Build Coastguard Worker #include "net/cookies/cookie_util.h"
83*6777b538SAndroid Build Coastguard Worker #include "net/cookies/parsed_cookie.h"
84*6777b538SAndroid Build Coastguard Worker #include "net/http/http_util.h"
85*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log.h"
86*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log_values.h"
87*6777b538SAndroid Build Coastguard Worker #include "url/origin.h"
88*6777b538SAndroid Build Coastguard Worker #include "url/third_party/mozilla/url_parse.h"
89*6777b538SAndroid Build Coastguard Worker #include "url/url_canon.h"
90*6777b538SAndroid Build Coastguard Worker #include "url/url_constants.h"
91*6777b538SAndroid Build Coastguard Worker 
92*6777b538SAndroid Build Coastguard Worker using base::Time;
93*6777b538SAndroid Build Coastguard Worker using base::TimeTicks;
94*6777b538SAndroid Build Coastguard Worker using TimeRange = net::CookieDeletionInfo::TimeRange;
95*6777b538SAndroid Build Coastguard Worker 
96*6777b538SAndroid Build Coastguard Worker // In steady state, most cookie requests can be satisfied by the in memory
97*6777b538SAndroid Build Coastguard Worker // cookie monster store. If the cookie request cannot be satisfied by the in
98*6777b538SAndroid Build Coastguard Worker // memory store, the relevant cookies must be fetched from the persistent
99*6777b538SAndroid Build Coastguard Worker // store. The task is queued in CookieMonster::tasks_pending_ if it requires
100*6777b538SAndroid Build Coastguard Worker // all cookies to be loaded from the backend, or tasks_pending_for_key_ if it
101*6777b538SAndroid Build Coastguard Worker // only requires all cookies associated with an eTLD+1.
102*6777b538SAndroid Build Coastguard Worker //
103*6777b538SAndroid Build Coastguard Worker // On the browser critical paths (e.g. for loading initial web pages in a
104*6777b538SAndroid Build Coastguard Worker // session restore) it may take too long to wait for the full load. If a cookie
105*6777b538SAndroid Build Coastguard Worker // request is for a specific URL, DoCookieCallbackForURL is called, which
106*6777b538SAndroid Build Coastguard Worker // triggers a priority load if the key is not loaded yet by calling
107*6777b538SAndroid Build Coastguard Worker // PersistentCookieStore::LoadCookiesForKey. The request is queued in
108*6777b538SAndroid Build Coastguard Worker // CookieMonster::tasks_pending_for_key_ and executed upon receiving
109*6777b538SAndroid Build Coastguard Worker // notification of key load completion via CookieMonster::OnKeyLoaded(). If
110*6777b538SAndroid Build Coastguard Worker // multiple requests for the same eTLD+1 are received before key load
111*6777b538SAndroid Build Coastguard Worker // completion, only the first request calls
112*6777b538SAndroid Build Coastguard Worker // PersistentCookieStore::LoadCookiesForKey, all subsequent requests are queued
113*6777b538SAndroid Build Coastguard Worker // in CookieMonster::tasks_pending_for_key_ and executed upon receiving
114*6777b538SAndroid Build Coastguard Worker // notification of key load completion triggered by the first request for the
115*6777b538SAndroid Build Coastguard Worker // same eTLD+1.
116*6777b538SAndroid Build Coastguard Worker 
117*6777b538SAndroid Build Coastguard Worker static const int kDaysInTenYears = 10 * 365;
118*6777b538SAndroid Build Coastguard Worker static const int kMinutesInTenYears = kDaysInTenYears * 24 * 60;
119*6777b538SAndroid Build Coastguard Worker 
120*6777b538SAndroid Build Coastguard Worker namespace {
121*6777b538SAndroid Build Coastguard Worker 
122*6777b538SAndroid Build Coastguard Worker // This enum is used to generate a histogramed bitmask measureing the types
123*6777b538SAndroid Build Coastguard Worker // of stored cookies. Please do not reorder the list when adding new entries.
124*6777b538SAndroid Build Coastguard Worker // New items MUST be added at the end of the list, just before
125*6777b538SAndroid Build Coastguard Worker // COOKIE_TYPE_LAST_ENTRY;
126*6777b538SAndroid Build Coastguard Worker // There will be 2^COOKIE_TYPE_LAST_ENTRY buckets in the linear histogram.
127*6777b538SAndroid Build Coastguard Worker enum CookieType {
128*6777b538SAndroid Build Coastguard Worker   COOKIE_TYPE_SAME_SITE = 0,
129*6777b538SAndroid Build Coastguard Worker   COOKIE_TYPE_HTTPONLY,
130*6777b538SAndroid Build Coastguard Worker   COOKIE_TYPE_SECURE,
131*6777b538SAndroid Build Coastguard Worker   COOKIE_TYPE_PERSISTENT,
132*6777b538SAndroid Build Coastguard Worker   COOKIE_TYPE_LAST_ENTRY
133*6777b538SAndroid Build Coastguard Worker };
134*6777b538SAndroid Build Coastguard Worker 
MaybeRunDeleteCallback(base::WeakPtr<net::CookieMonster> cookie_monster,base::OnceClosure callback)135*6777b538SAndroid Build Coastguard Worker void MaybeRunDeleteCallback(base::WeakPtr<net::CookieMonster> cookie_monster,
136*6777b538SAndroid Build Coastguard Worker                             base::OnceClosure callback) {
137*6777b538SAndroid Build Coastguard Worker   if (cookie_monster && callback)
138*6777b538SAndroid Build Coastguard Worker     std::move(callback).Run();
139*6777b538SAndroid Build Coastguard Worker }
140*6777b538SAndroid Build Coastguard Worker 
141*6777b538SAndroid Build Coastguard Worker template <typename CB, typename... R>
MaybeRunCookieCallback(base::OnceCallback<CB> callback,R &&...result)142*6777b538SAndroid Build Coastguard Worker void MaybeRunCookieCallback(base::OnceCallback<CB> callback, R&&... result) {
143*6777b538SAndroid Build Coastguard Worker   if (callback) {
144*6777b538SAndroid Build Coastguard Worker     std::move(callback).Run(std::forward<R>(result)...);
145*6777b538SAndroid Build Coastguard Worker   }
146*6777b538SAndroid Build Coastguard Worker }
147*6777b538SAndroid Build Coastguard Worker 
148*6777b538SAndroid Build Coastguard Worker // Anonymous and Fenced Frame uses a CookiePartitionKey with a nonce. In these
149*6777b538SAndroid Build Coastguard Worker // contexts, access to unpartitioned cookie is not granted.
150*6777b538SAndroid Build Coastguard Worker //
151*6777b538SAndroid Build Coastguard Worker // This returns true if the |list| of key should include unpartitioned cookie in
152*6777b538SAndroid Build Coastguard Worker // GetCookie...().
IncludeUnpartitionedCookies(const net::CookiePartitionKeyCollection & list)153*6777b538SAndroid Build Coastguard Worker bool IncludeUnpartitionedCookies(
154*6777b538SAndroid Build Coastguard Worker     const net::CookiePartitionKeyCollection& list) {
155*6777b538SAndroid Build Coastguard Worker   if (list.IsEmpty() || list.ContainsAllKeys())
156*6777b538SAndroid Build Coastguard Worker     return true;
157*6777b538SAndroid Build Coastguard Worker 
158*6777b538SAndroid Build Coastguard Worker   for (const net::CookiePartitionKey& key : list.PartitionKeys()) {
159*6777b538SAndroid Build Coastguard Worker     if (!key.nonce())
160*6777b538SAndroid Build Coastguard Worker       return true;
161*6777b538SAndroid Build Coastguard Worker   }
162*6777b538SAndroid Build Coastguard Worker   return false;
163*6777b538SAndroid Build Coastguard Worker }
164*6777b538SAndroid Build Coastguard Worker 
NameValueSizeBytes(const net::CanonicalCookie & cc)165*6777b538SAndroid Build Coastguard Worker size_t NameValueSizeBytes(const net::CanonicalCookie& cc) {
166*6777b538SAndroid Build Coastguard Worker   base::CheckedNumeric<size_t> name_value_pair_size = cc.Name().size();
167*6777b538SAndroid Build Coastguard Worker   name_value_pair_size += cc.Value().size();
168*6777b538SAndroid Build Coastguard Worker   DCHECK(name_value_pair_size.IsValid());
169*6777b538SAndroid Build Coastguard Worker   return name_value_pair_size.ValueOrDie();
170*6777b538SAndroid Build Coastguard Worker }
171*6777b538SAndroid Build Coastguard Worker 
NumBytesInCookieMapForKey(const net::CookieMonster::CookieMap & cookie_map,const std::string & key)172*6777b538SAndroid Build Coastguard Worker size_t NumBytesInCookieMapForKey(
173*6777b538SAndroid Build Coastguard Worker     const net::CookieMonster::CookieMap& cookie_map,
174*6777b538SAndroid Build Coastguard Worker     const std::string& key) {
175*6777b538SAndroid Build Coastguard Worker   size_t result = 0;
176*6777b538SAndroid Build Coastguard Worker   auto range = cookie_map.equal_range(key);
177*6777b538SAndroid Build Coastguard Worker   for (auto it = range.first; it != range.second; ++it) {
178*6777b538SAndroid Build Coastguard Worker     result += NameValueSizeBytes(*it->second);
179*6777b538SAndroid Build Coastguard Worker   }
180*6777b538SAndroid Build Coastguard Worker   return result;
181*6777b538SAndroid Build Coastguard Worker }
182*6777b538SAndroid Build Coastguard Worker 
NumBytesInCookieItVector(const net::CookieMonster::CookieItVector & cookie_its)183*6777b538SAndroid Build Coastguard Worker size_t NumBytesInCookieItVector(
184*6777b538SAndroid Build Coastguard Worker     const net::CookieMonster::CookieItVector& cookie_its) {
185*6777b538SAndroid Build Coastguard Worker   size_t result = 0;
186*6777b538SAndroid Build Coastguard Worker   for (const auto& it : cookie_its) {
187*6777b538SAndroid Build Coastguard Worker     result += NameValueSizeBytes(*it->second);
188*6777b538SAndroid Build Coastguard Worker   }
189*6777b538SAndroid Build Coastguard Worker   return result;
190*6777b538SAndroid Build Coastguard Worker }
191*6777b538SAndroid Build Coastguard Worker 
LogStoredCookieToUMA(const net::CanonicalCookie & cc,const net::CookieAccessResult & access_result)192*6777b538SAndroid Build Coastguard Worker void LogStoredCookieToUMA(const net::CanonicalCookie& cc,
193*6777b538SAndroid Build Coastguard Worker                           const net::CookieAccessResult& access_result) {
194*6777b538SAndroid Build Coastguard Worker   // Cookie.Type2 collects a bitvector of important cookie attributes.
195*6777b538SAndroid Build Coastguard Worker   int32_t type_sample =
196*6777b538SAndroid Build Coastguard Worker       !cc.IsEffectivelySameSiteNone(access_result.access_semantics)
197*6777b538SAndroid Build Coastguard Worker           ? 1 << COOKIE_TYPE_SAME_SITE
198*6777b538SAndroid Build Coastguard Worker           : 0;
199*6777b538SAndroid Build Coastguard Worker   type_sample |= cc.IsHttpOnly() ? 1 << COOKIE_TYPE_HTTPONLY : 0;
200*6777b538SAndroid Build Coastguard Worker   type_sample |= cc.SecureAttribute() ? 1 << COOKIE_TYPE_SECURE : 0;
201*6777b538SAndroid Build Coastguard Worker   type_sample |= cc.IsPersistent() ? 1 << COOKIE_TYPE_PERSISTENT : 0;
202*6777b538SAndroid Build Coastguard Worker   UMA_HISTOGRAM_EXACT_LINEAR("Cookie.Type2", type_sample,
203*6777b538SAndroid Build Coastguard Worker                              (1 << COOKIE_TYPE_LAST_ENTRY));
204*6777b538SAndroid Build Coastguard Worker 
205*6777b538SAndroid Build Coastguard Worker   // Cookie.SourceType collects the CookieSourceType of the stored cookie.
206*6777b538SAndroid Build Coastguard Worker   UMA_HISTOGRAM_ENUMERATION("Cookie.SourceType", cc.SourceType());
207*6777b538SAndroid Build Coastguard Worker }
208*6777b538SAndroid Build Coastguard Worker 
209*6777b538SAndroid Build Coastguard Worker }  // namespace
210*6777b538SAndroid Build Coastguard Worker 
211*6777b538SAndroid Build Coastguard Worker namespace net {
212*6777b538SAndroid Build Coastguard Worker 
213*6777b538SAndroid Build Coastguard Worker // See comments at declaration of these variables in cookie_monster.h
214*6777b538SAndroid Build Coastguard Worker // for details.
215*6777b538SAndroid Build Coastguard Worker const size_t CookieMonster::kDomainMaxCookies = 180;
216*6777b538SAndroid Build Coastguard Worker const size_t CookieMonster::kDomainPurgeCookies = 30;
217*6777b538SAndroid Build Coastguard Worker const size_t CookieMonster::kMaxCookies = 3300;
218*6777b538SAndroid Build Coastguard Worker const size_t CookieMonster::kPurgeCookies = 300;
219*6777b538SAndroid Build Coastguard Worker 
220*6777b538SAndroid Build Coastguard Worker const size_t CookieMonster::kMaxDomainPurgedKeys = 100;
221*6777b538SAndroid Build Coastguard Worker 
222*6777b538SAndroid Build Coastguard Worker const size_t CookieMonster::kPerPartitionDomainMaxCookieBytes = 10240;
223*6777b538SAndroid Build Coastguard Worker const size_t CookieMonster::kPerPartitionDomainMaxCookies = 180;
224*6777b538SAndroid Build Coastguard Worker 
225*6777b538SAndroid Build Coastguard Worker const size_t CookieMonster::kDomainCookiesQuotaLow = 30;
226*6777b538SAndroid Build Coastguard Worker const size_t CookieMonster::kDomainCookiesQuotaMedium = 50;
227*6777b538SAndroid Build Coastguard Worker const size_t CookieMonster::kDomainCookiesQuotaHigh =
228*6777b538SAndroid Build Coastguard Worker     kDomainMaxCookies - kDomainPurgeCookies - kDomainCookiesQuotaLow -
229*6777b538SAndroid Build Coastguard Worker     kDomainCookiesQuotaMedium;
230*6777b538SAndroid Build Coastguard Worker 
231*6777b538SAndroid Build Coastguard Worker const int CookieMonster::kSafeFromGlobalPurgeDays = 30;
232*6777b538SAndroid Build Coastguard Worker 
233*6777b538SAndroid Build Coastguard Worker namespace {
234*6777b538SAndroid Build Coastguard Worker 
ContainsControlCharacter(const std::string & s)235*6777b538SAndroid Build Coastguard Worker bool ContainsControlCharacter(const std::string& s) {
236*6777b538SAndroid Build Coastguard Worker   return base::ranges::any_of(s, &HttpUtil::IsControlChar);
237*6777b538SAndroid Build Coastguard Worker }
238*6777b538SAndroid Build Coastguard Worker 
239*6777b538SAndroid Build Coastguard Worker typedef std::vector<CanonicalCookie*> CanonicalCookieVector;
240*6777b538SAndroid Build Coastguard Worker 
241*6777b538SAndroid Build Coastguard Worker // Default minimum delay after updating a cookie's LastAccessDate before we
242*6777b538SAndroid Build Coastguard Worker // will update it again.
243*6777b538SAndroid Build Coastguard Worker const int kDefaultAccessUpdateThresholdSeconds = 60;
244*6777b538SAndroid Build Coastguard Worker 
245*6777b538SAndroid Build Coastguard Worker // Comparator to sort cookies from highest creation date to lowest
246*6777b538SAndroid Build Coastguard Worker // creation date.
247*6777b538SAndroid Build Coastguard Worker struct OrderByCreationTimeDesc {
operator ()net::__anonbb611ec80211::OrderByCreationTimeDesc248*6777b538SAndroid Build Coastguard Worker   bool operator()(const CookieMonster::CookieMap::iterator& a,
249*6777b538SAndroid Build Coastguard Worker                   const CookieMonster::CookieMap::iterator& b) const {
250*6777b538SAndroid Build Coastguard Worker     return a->second->CreationDate() > b->second->CreationDate();
251*6777b538SAndroid Build Coastguard Worker   }
252*6777b538SAndroid Build Coastguard Worker };
253*6777b538SAndroid Build Coastguard Worker 
LRACookieSorter(const CookieMonster::CookieMap::iterator & it1,const CookieMonster::CookieMap::iterator & it2)254*6777b538SAndroid Build Coastguard Worker bool LRACookieSorter(const CookieMonster::CookieMap::iterator& it1,
255*6777b538SAndroid Build Coastguard Worker                      const CookieMonster::CookieMap::iterator& it2) {
256*6777b538SAndroid Build Coastguard Worker   if (it1->second->LastAccessDate() != it2->second->LastAccessDate())
257*6777b538SAndroid Build Coastguard Worker     return it1->second->LastAccessDate() < it2->second->LastAccessDate();
258*6777b538SAndroid Build Coastguard Worker 
259*6777b538SAndroid Build Coastguard Worker   // Ensure stability for == last access times by falling back to creation.
260*6777b538SAndroid Build Coastguard Worker   return it1->second->CreationDate() < it2->second->CreationDate();
261*6777b538SAndroid Build Coastguard Worker }
262*6777b538SAndroid Build Coastguard Worker 
263*6777b538SAndroid Build Coastguard Worker // For a CookieItVector iterator range [|it_begin|, |it_end|),
264*6777b538SAndroid Build Coastguard Worker // sorts the first |num_sort| elements by LastAccessDate().
SortLeastRecentlyAccessed(CookieMonster::CookieItVector::iterator it_begin,CookieMonster::CookieItVector::iterator it_end,size_t num_sort)265*6777b538SAndroid Build Coastguard Worker void SortLeastRecentlyAccessed(CookieMonster::CookieItVector::iterator it_begin,
266*6777b538SAndroid Build Coastguard Worker                                CookieMonster::CookieItVector::iterator it_end,
267*6777b538SAndroid Build Coastguard Worker                                size_t num_sort) {
268*6777b538SAndroid Build Coastguard Worker   DCHECK_LE(static_cast<int>(num_sort), it_end - it_begin);
269*6777b538SAndroid Build Coastguard Worker   std::partial_sort(it_begin, it_begin + num_sort, it_end, LRACookieSorter);
270*6777b538SAndroid Build Coastguard Worker }
271*6777b538SAndroid Build Coastguard Worker 
272*6777b538SAndroid Build Coastguard Worker // Given a single cookie vector |cookie_its|, pushs all of the secure cookies in
273*6777b538SAndroid Build Coastguard Worker // |cookie_its| into |secure_cookie_its| and all of the non-secure cookies into
274*6777b538SAndroid Build Coastguard Worker // |non_secure_cookie_its|. Both |secure_cookie_its| and |non_secure_cookie_its|
275*6777b538SAndroid Build Coastguard Worker // must be non-NULL.
SplitCookieVectorIntoSecureAndNonSecure(const CookieMonster::CookieItVector & cookie_its,CookieMonster::CookieItVector * secure_cookie_its,CookieMonster::CookieItVector * non_secure_cookie_its)276*6777b538SAndroid Build Coastguard Worker void SplitCookieVectorIntoSecureAndNonSecure(
277*6777b538SAndroid Build Coastguard Worker     const CookieMonster::CookieItVector& cookie_its,
278*6777b538SAndroid Build Coastguard Worker     CookieMonster::CookieItVector* secure_cookie_its,
279*6777b538SAndroid Build Coastguard Worker     CookieMonster::CookieItVector* non_secure_cookie_its) {
280*6777b538SAndroid Build Coastguard Worker   DCHECK(secure_cookie_its && non_secure_cookie_its);
281*6777b538SAndroid Build Coastguard Worker   for (const auto& curit : cookie_its) {
282*6777b538SAndroid Build Coastguard Worker     if (curit->second->SecureAttribute()) {
283*6777b538SAndroid Build Coastguard Worker       secure_cookie_its->push_back(curit);
284*6777b538SAndroid Build Coastguard Worker     } else {
285*6777b538SAndroid Build Coastguard Worker       non_secure_cookie_its->push_back(curit);
286*6777b538SAndroid Build Coastguard Worker     }
287*6777b538SAndroid Build Coastguard Worker   }
288*6777b538SAndroid Build Coastguard Worker }
289*6777b538SAndroid Build Coastguard Worker 
LowerBoundAccessDateComparator(const CookieMonster::CookieMap::iterator it,const Time & access_date)290*6777b538SAndroid Build Coastguard Worker bool LowerBoundAccessDateComparator(const CookieMonster::CookieMap::iterator it,
291*6777b538SAndroid Build Coastguard Worker                                     const Time& access_date) {
292*6777b538SAndroid Build Coastguard Worker   return it->second->LastAccessDate() < access_date;
293*6777b538SAndroid Build Coastguard Worker }
294*6777b538SAndroid Build Coastguard Worker 
295*6777b538SAndroid Build Coastguard Worker // For a CookieItVector iterator range [|it_begin|, |it_end|)
296*6777b538SAndroid Build Coastguard Worker // from a CookieItVector sorted by LastAccessDate(), returns the
297*6777b538SAndroid Build Coastguard Worker // first iterator with access date >= |access_date|, or cookie_its_end if this
298*6777b538SAndroid Build Coastguard Worker // holds for all.
LowerBoundAccessDate(const CookieMonster::CookieItVector::iterator its_begin,const CookieMonster::CookieItVector::iterator its_end,const Time & access_date)299*6777b538SAndroid Build Coastguard Worker CookieMonster::CookieItVector::iterator LowerBoundAccessDate(
300*6777b538SAndroid Build Coastguard Worker     const CookieMonster::CookieItVector::iterator its_begin,
301*6777b538SAndroid Build Coastguard Worker     const CookieMonster::CookieItVector::iterator its_end,
302*6777b538SAndroid Build Coastguard Worker     const Time& access_date) {
303*6777b538SAndroid Build Coastguard Worker   return std::lower_bound(its_begin, its_end, access_date,
304*6777b538SAndroid Build Coastguard Worker                           LowerBoundAccessDateComparator);
305*6777b538SAndroid Build Coastguard Worker }
306*6777b538SAndroid Build Coastguard Worker 
307*6777b538SAndroid Build Coastguard Worker // Mapping between DeletionCause and CookieChangeCause; the
308*6777b538SAndroid Build Coastguard Worker // mapping also provides a boolean that specifies whether or not an
309*6777b538SAndroid Build Coastguard Worker // OnCookieChange notification ought to be generated.
310*6777b538SAndroid Build Coastguard Worker typedef struct ChangeCausePair_struct {
311*6777b538SAndroid Build Coastguard Worker   CookieChangeCause cause;
312*6777b538SAndroid Build Coastguard Worker   bool notify;
313*6777b538SAndroid Build Coastguard Worker } ChangeCausePair;
314*6777b538SAndroid Build Coastguard Worker const ChangeCausePair kChangeCauseMapping[] = {
315*6777b538SAndroid Build Coastguard Worker     // DELETE_COOKIE_EXPLICIT
316*6777b538SAndroid Build Coastguard Worker     {CookieChangeCause::EXPLICIT, true},
317*6777b538SAndroid Build Coastguard Worker     // DELETE_COOKIE_OVERWRITE
318*6777b538SAndroid Build Coastguard Worker     {CookieChangeCause::OVERWRITE, true},
319*6777b538SAndroid Build Coastguard Worker     // DELETE_COOKIE_EXPIRED
320*6777b538SAndroid Build Coastguard Worker     {CookieChangeCause::EXPIRED, true},
321*6777b538SAndroid Build Coastguard Worker     // DELETE_COOKIE_EVICTED
322*6777b538SAndroid Build Coastguard Worker     {CookieChangeCause::EVICTED, true},
323*6777b538SAndroid Build Coastguard Worker     // DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE
324*6777b538SAndroid Build Coastguard Worker     {CookieChangeCause::EXPLICIT, false},
325*6777b538SAndroid Build Coastguard Worker     // DELETE_COOKIE_DONT_RECORD
326*6777b538SAndroid Build Coastguard Worker     {CookieChangeCause::EXPLICIT, false},
327*6777b538SAndroid Build Coastguard Worker     // DELETE_COOKIE_EVICTED_DOMAIN
328*6777b538SAndroid Build Coastguard Worker     {CookieChangeCause::EVICTED, true},
329*6777b538SAndroid Build Coastguard Worker     // DELETE_COOKIE_EVICTED_GLOBAL
330*6777b538SAndroid Build Coastguard Worker     {CookieChangeCause::EVICTED, true},
331*6777b538SAndroid Build Coastguard Worker     // DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE
332*6777b538SAndroid Build Coastguard Worker     {CookieChangeCause::EVICTED, true},
333*6777b538SAndroid Build Coastguard Worker     // DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE
334*6777b538SAndroid Build Coastguard Worker     {CookieChangeCause::EVICTED, true},
335*6777b538SAndroid Build Coastguard Worker     // DELETE_COOKIE_EXPIRED_OVERWRITE
336*6777b538SAndroid Build Coastguard Worker     {CookieChangeCause::EXPIRED_OVERWRITE, true},
337*6777b538SAndroid Build Coastguard Worker     // DELETE_COOKIE_CONTROL_CHAR
338*6777b538SAndroid Build Coastguard Worker     {CookieChangeCause::EVICTED, true},
339*6777b538SAndroid Build Coastguard Worker     // DELETE_COOKIE_NON_SECURE
340*6777b538SAndroid Build Coastguard Worker     {CookieChangeCause::EVICTED, true},
341*6777b538SAndroid Build Coastguard Worker     // DELETE_COOKIE_EVICTED_PER_PARTITION_DOMAIN
342*6777b538SAndroid Build Coastguard Worker     {CookieChangeCause::EVICTED, true},
343*6777b538SAndroid Build Coastguard Worker     // DELETE_COOKIE_LAST_ENTRY
344*6777b538SAndroid Build Coastguard Worker     {CookieChangeCause::EXPLICIT, false}};
345*6777b538SAndroid Build Coastguard Worker 
IsCookieEligibleForEviction(CookiePriority current_priority_level,bool protect_secure_cookies,const CanonicalCookie * cookie)346*6777b538SAndroid Build Coastguard Worker bool IsCookieEligibleForEviction(CookiePriority current_priority_level,
347*6777b538SAndroid Build Coastguard Worker                                  bool protect_secure_cookies,
348*6777b538SAndroid Build Coastguard Worker                                  const CanonicalCookie* cookie) {
349*6777b538SAndroid Build Coastguard Worker   if (cookie->Priority() == current_priority_level && protect_secure_cookies)
350*6777b538SAndroid Build Coastguard Worker     return !cookie->SecureAttribute();
351*6777b538SAndroid Build Coastguard Worker 
352*6777b538SAndroid Build Coastguard Worker   return cookie->Priority() == current_priority_level;
353*6777b538SAndroid Build Coastguard Worker }
354*6777b538SAndroid Build Coastguard Worker 
CountCookiesForPossibleDeletion(CookiePriority priority,const CookieMonster::CookieItVector * cookies,bool protect_secure_cookies)355*6777b538SAndroid Build Coastguard Worker size_t CountCookiesForPossibleDeletion(
356*6777b538SAndroid Build Coastguard Worker     CookiePriority priority,
357*6777b538SAndroid Build Coastguard Worker     const CookieMonster::CookieItVector* cookies,
358*6777b538SAndroid Build Coastguard Worker     bool protect_secure_cookies) {
359*6777b538SAndroid Build Coastguard Worker   size_t cookies_count = 0U;
360*6777b538SAndroid Build Coastguard Worker   for (const auto& cookie : *cookies) {
361*6777b538SAndroid Build Coastguard Worker     if (cookie->second->Priority() == priority) {
362*6777b538SAndroid Build Coastguard Worker       if (!protect_secure_cookies || cookie->second->SecureAttribute()) {
363*6777b538SAndroid Build Coastguard Worker         cookies_count++;
364*6777b538SAndroid Build Coastguard Worker       }
365*6777b538SAndroid Build Coastguard Worker     }
366*6777b538SAndroid Build Coastguard Worker   }
367*6777b538SAndroid Build Coastguard Worker   return cookies_count;
368*6777b538SAndroid Build Coastguard Worker }
369*6777b538SAndroid Build Coastguard Worker 
370*6777b538SAndroid Build Coastguard Worker struct DeletionCookieLists {
371*6777b538SAndroid Build Coastguard Worker   std::list<CookieMonster::CookieItList::const_iterator> host_cookies;
372*6777b538SAndroid Build Coastguard Worker   std::list<CookieMonster::CookieItList::const_iterator> domain_cookies;
373*6777b538SAndroid Build Coastguard Worker };
374*6777b538SAndroid Build Coastguard Worker 
375*6777b538SAndroid Build Coastguard Worker // Performs 2 tasks
376*6777b538SAndroid Build Coastguard Worker // * Counts every cookie at the given `priority` in `cookies`. This is the
377*6777b538SAndroid Build Coastguard Worker // return value.
378*6777b538SAndroid Build Coastguard Worker // * Fills in the host & domain lists for `could_be_deleted` with every cookie
379*6777b538SAndroid Build Coastguard Worker // of the given {secureness, priority} in `cookies`.
CountCookiesAndGenerateListsForPossibleDeletion(CookiePriority priority,DeletionCookieLists & could_be_deleted,const CookieMonster::CookieItList * cookies,bool generate_for_secure)380*6777b538SAndroid Build Coastguard Worker size_t CountCookiesAndGenerateListsForPossibleDeletion(
381*6777b538SAndroid Build Coastguard Worker     CookiePriority priority,
382*6777b538SAndroid Build Coastguard Worker     DeletionCookieLists& could_be_deleted,
383*6777b538SAndroid Build Coastguard Worker     const CookieMonster::CookieItList* cookies,
384*6777b538SAndroid Build Coastguard Worker     bool generate_for_secure) {
385*6777b538SAndroid Build Coastguard Worker   size_t total_cookies_at_priority = 0;
386*6777b538SAndroid Build Coastguard Worker 
387*6777b538SAndroid Build Coastguard Worker   for (auto list_it = cookies->begin(); list_it != cookies->end(); list_it++) {
388*6777b538SAndroid Build Coastguard Worker     const auto cookiemap_it = *list_it;
389*6777b538SAndroid Build Coastguard Worker     const auto& cookie = cookiemap_it->second;
390*6777b538SAndroid Build Coastguard Worker 
391*6777b538SAndroid Build Coastguard Worker     if (cookie->Priority() != priority) {
392*6777b538SAndroid Build Coastguard Worker       continue;
393*6777b538SAndroid Build Coastguard Worker     }
394*6777b538SAndroid Build Coastguard Worker 
395*6777b538SAndroid Build Coastguard Worker     // Because we want to keep a specific number of cookies per priority level,
396*6777b538SAndroid Build Coastguard Worker     // independent of securness of the cookies, we need to count all the cookies
397*6777b538SAndroid Build Coastguard Worker     // at the level even if we'll skip adding them to the deletion lists.
398*6777b538SAndroid Build Coastguard Worker     total_cookies_at_priority++;
399*6777b538SAndroid Build Coastguard Worker 
400*6777b538SAndroid Build Coastguard Worker     if (cookie->IsSecure() != generate_for_secure) {
401*6777b538SAndroid Build Coastguard Worker       continue;
402*6777b538SAndroid Build Coastguard Worker     }
403*6777b538SAndroid Build Coastguard Worker 
404*6777b538SAndroid Build Coastguard Worker     if (cookie->IsHostCookie()) {
405*6777b538SAndroid Build Coastguard Worker       could_be_deleted.host_cookies.push_back(list_it);
406*6777b538SAndroid Build Coastguard Worker     } else {  // Is a domain cookie.
407*6777b538SAndroid Build Coastguard Worker       could_be_deleted.domain_cookies.push_back(list_it);
408*6777b538SAndroid Build Coastguard Worker     }
409*6777b538SAndroid Build Coastguard Worker   }
410*6777b538SAndroid Build Coastguard Worker 
411*6777b538SAndroid Build Coastguard Worker   return total_cookies_at_priority;
412*6777b538SAndroid Build Coastguard Worker }
413*6777b538SAndroid Build Coastguard Worker 
414*6777b538SAndroid Build Coastguard Worker // Records minutes until the expiration date of a cookie to the appropriate
415*6777b538SAndroid Build Coastguard Worker // histogram. Only histograms cookies that have an expiration date (i.e. are
416*6777b538SAndroid Build Coastguard Worker // persistent).
HistogramExpirationDuration(const CanonicalCookie & cookie,base::Time creation_time)417*6777b538SAndroid Build Coastguard Worker void HistogramExpirationDuration(const CanonicalCookie& cookie,
418*6777b538SAndroid Build Coastguard Worker                                  base::Time creation_time) {
419*6777b538SAndroid Build Coastguard Worker   if (!cookie.IsPersistent())
420*6777b538SAndroid Build Coastguard Worker     return;
421*6777b538SAndroid Build Coastguard Worker 
422*6777b538SAndroid Build Coastguard Worker   int expiration_duration_minutes =
423*6777b538SAndroid Build Coastguard Worker       (cookie.ExpiryDate() - creation_time).InMinutes();
424*6777b538SAndroid Build Coastguard Worker   if (cookie.SecureAttribute()) {
425*6777b538SAndroid Build Coastguard Worker     UMA_HISTOGRAM_CUSTOM_COUNTS("Cookie.ExpirationDurationMinutesSecure",
426*6777b538SAndroid Build Coastguard Worker                                 expiration_duration_minutes, 1,
427*6777b538SAndroid Build Coastguard Worker                                 kMinutesInTenYears, 50);
428*6777b538SAndroid Build Coastguard Worker   } else {
429*6777b538SAndroid Build Coastguard Worker     UMA_HISTOGRAM_CUSTOM_COUNTS("Cookie.ExpirationDurationMinutesNonSecure",
430*6777b538SAndroid Build Coastguard Worker                                 expiration_duration_minutes, 1,
431*6777b538SAndroid Build Coastguard Worker                                 kMinutesInTenYears, 50);
432*6777b538SAndroid Build Coastguard Worker   }
433*6777b538SAndroid Build Coastguard Worker   // The proposed rfc6265bis sets an upper limit on Expires/Max-Age attribute
434*6777b538SAndroid Build Coastguard Worker   // values of 400 days. We need to study the impact this change would have:
435*6777b538SAndroid Build Coastguard Worker   // https://httpwg.org/http-extensions/draft-ietf-httpbis-rfc6265bis.html
436*6777b538SAndroid Build Coastguard Worker   int expiration_duration_days = (cookie.ExpiryDate() - creation_time).InDays();
437*6777b538SAndroid Build Coastguard Worker   if (expiration_duration_days > 400) {
438*6777b538SAndroid Build Coastguard Worker     UMA_HISTOGRAM_CUSTOM_COUNTS("Cookie.ExpirationDuration400DaysGT",
439*6777b538SAndroid Build Coastguard Worker                                 expiration_duration_days, 401, kDaysInTenYears,
440*6777b538SAndroid Build Coastguard Worker                                 100);
441*6777b538SAndroid Build Coastguard Worker   } else {
442*6777b538SAndroid Build Coastguard Worker     UMA_HISTOGRAM_CUSTOM_COUNTS("Cookie.ExpirationDuration400DaysLTE",
443*6777b538SAndroid Build Coastguard Worker                                 expiration_duration_days, 1, 400, 50);
444*6777b538SAndroid Build Coastguard Worker   }
445*6777b538SAndroid Build Coastguard Worker }
446*6777b538SAndroid Build Coastguard Worker 
447*6777b538SAndroid Build Coastguard Worker }  // namespace
448*6777b538SAndroid Build Coastguard Worker 
CookieMonster(scoped_refptr<PersistentCookieStore> store,NetLog * net_log)449*6777b538SAndroid Build Coastguard Worker CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
450*6777b538SAndroid Build Coastguard Worker                              NetLog* net_log)
451*6777b538SAndroid Build Coastguard Worker     : CookieMonster(std::move(store),
452*6777b538SAndroid Build Coastguard Worker                     base::Seconds(kDefaultAccessUpdateThresholdSeconds),
453*6777b538SAndroid Build Coastguard Worker                     net_log) {}
454*6777b538SAndroid Build Coastguard Worker 
CookieMonster(scoped_refptr<PersistentCookieStore> store,base::TimeDelta last_access_threshold,NetLog * net_log)455*6777b538SAndroid Build Coastguard Worker CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
456*6777b538SAndroid Build Coastguard Worker                              base::TimeDelta last_access_threshold,
457*6777b538SAndroid Build Coastguard Worker                              NetLog* net_log)
458*6777b538SAndroid Build Coastguard Worker     : change_dispatcher_(this),
459*6777b538SAndroid Build Coastguard Worker       net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::COOKIE_STORE)),
460*6777b538SAndroid Build Coastguard Worker       store_(std::move(store)),
461*6777b538SAndroid Build Coastguard Worker       last_access_threshold_(last_access_threshold),
462*6777b538SAndroid Build Coastguard Worker       last_statistic_record_time_(base::Time::Now()) {
463*6777b538SAndroid Build Coastguard Worker   cookieable_schemes_.insert(
464*6777b538SAndroid Build Coastguard Worker       cookieable_schemes_.begin(), kDefaultCookieableSchemes,
465*6777b538SAndroid Build Coastguard Worker       kDefaultCookieableSchemes + kDefaultCookieableSchemesCount);
466*6777b538SAndroid Build Coastguard Worker   net_log_.BeginEvent(NetLogEventType::COOKIE_STORE_ALIVE, [&] {
467*6777b538SAndroid Build Coastguard Worker     return NetLogCookieMonsterConstructorParams(store_ != nullptr);
468*6777b538SAndroid Build Coastguard Worker   });
469*6777b538SAndroid Build Coastguard Worker }
470*6777b538SAndroid Build Coastguard Worker 
471*6777b538SAndroid Build Coastguard Worker // Asynchronous CookieMonster API
472*6777b538SAndroid Build Coastguard Worker 
FlushStore(base::OnceClosure callback)473*6777b538SAndroid Build Coastguard Worker void CookieMonster::FlushStore(base::OnceClosure callback) {
474*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
475*6777b538SAndroid Build Coastguard Worker 
476*6777b538SAndroid Build Coastguard Worker   if (initialized_ && store_.get()) {
477*6777b538SAndroid Build Coastguard Worker     store_->Flush(std::move(callback));
478*6777b538SAndroid Build Coastguard Worker   } else if (callback) {
479*6777b538SAndroid Build Coastguard Worker     base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
480*6777b538SAndroid Build Coastguard Worker         FROM_HERE, std::move(callback));
481*6777b538SAndroid Build Coastguard Worker   }
482*6777b538SAndroid Build Coastguard Worker }
483*6777b538SAndroid Build Coastguard Worker 
SetForceKeepSessionState()484*6777b538SAndroid Build Coastguard Worker void CookieMonster::SetForceKeepSessionState() {
485*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
486*6777b538SAndroid Build Coastguard Worker 
487*6777b538SAndroid Build Coastguard Worker   if (store_)
488*6777b538SAndroid Build Coastguard Worker     store_->SetForceKeepSessionState();
489*6777b538SAndroid Build Coastguard Worker }
490*6777b538SAndroid Build Coastguard Worker 
SetAllCookiesAsync(const CookieList & list,SetCookiesCallback callback)491*6777b538SAndroid Build Coastguard Worker void CookieMonster::SetAllCookiesAsync(const CookieList& list,
492*6777b538SAndroid Build Coastguard Worker                                        SetCookiesCallback callback) {
493*6777b538SAndroid Build Coastguard Worker   DoCookieCallback(base::BindOnce(
494*6777b538SAndroid Build Coastguard Worker       // base::Unretained is safe as DoCookieCallback stores
495*6777b538SAndroid Build Coastguard Worker       // the callback on |*this|, so the callback will not outlive
496*6777b538SAndroid Build Coastguard Worker       // the object.
497*6777b538SAndroid Build Coastguard Worker       &CookieMonster::SetAllCookies, base::Unretained(this), list,
498*6777b538SAndroid Build Coastguard Worker       std::move(callback)));
499*6777b538SAndroid Build Coastguard Worker }
500*6777b538SAndroid Build Coastguard Worker 
SetCanonicalCookieAsync(std::unique_ptr<CanonicalCookie> cookie,const GURL & source_url,const CookieOptions & options,SetCookiesCallback callback,std::optional<CookieAccessResult> cookie_access_result)501*6777b538SAndroid Build Coastguard Worker void CookieMonster::SetCanonicalCookieAsync(
502*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<CanonicalCookie> cookie,
503*6777b538SAndroid Build Coastguard Worker     const GURL& source_url,
504*6777b538SAndroid Build Coastguard Worker     const CookieOptions& options,
505*6777b538SAndroid Build Coastguard Worker     SetCookiesCallback callback,
506*6777b538SAndroid Build Coastguard Worker     std::optional<CookieAccessResult> cookie_access_result) {
507*6777b538SAndroid Build Coastguard Worker   DCHECK(cookie->IsCanonical());
508*6777b538SAndroid Build Coastguard Worker 
509*6777b538SAndroid Build Coastguard Worker   std::string domain = cookie->Domain();
510*6777b538SAndroid Build Coastguard Worker   DoCookieCallbackForHostOrDomain(
511*6777b538SAndroid Build Coastguard Worker       base::BindOnce(
512*6777b538SAndroid Build Coastguard Worker           // base::Unretained is safe as DoCookieCallbackForHostOrDomain stores
513*6777b538SAndroid Build Coastguard Worker           // the callback on |*this|, so the callback will not outlive
514*6777b538SAndroid Build Coastguard Worker           // the object.
515*6777b538SAndroid Build Coastguard Worker           &CookieMonster::SetCanonicalCookie, base::Unretained(this),
516*6777b538SAndroid Build Coastguard Worker           std::move(cookie), source_url, options, std::move(callback),
517*6777b538SAndroid Build Coastguard Worker           std::move(cookie_access_result)),
518*6777b538SAndroid Build Coastguard Worker       domain);
519*6777b538SAndroid Build Coastguard Worker }
520*6777b538SAndroid Build Coastguard Worker 
GetCookieListWithOptionsAsync(const GURL & url,const CookieOptions & options,const CookiePartitionKeyCollection & cookie_partition_key_collection,GetCookieListCallback callback)521*6777b538SAndroid Build Coastguard Worker void CookieMonster::GetCookieListWithOptionsAsync(
522*6777b538SAndroid Build Coastguard Worker     const GURL& url,
523*6777b538SAndroid Build Coastguard Worker     const CookieOptions& options,
524*6777b538SAndroid Build Coastguard Worker     const CookiePartitionKeyCollection& cookie_partition_key_collection,
525*6777b538SAndroid Build Coastguard Worker     GetCookieListCallback callback) {
526*6777b538SAndroid Build Coastguard Worker   DoCookieCallbackForURL(
527*6777b538SAndroid Build Coastguard Worker       base::BindOnce(
528*6777b538SAndroid Build Coastguard Worker           // base::Unretained is safe as DoCookieCallbackForURL stores
529*6777b538SAndroid Build Coastguard Worker           // the callback on |*this|, so the callback will not outlive
530*6777b538SAndroid Build Coastguard Worker           // the object.
531*6777b538SAndroid Build Coastguard Worker           &CookieMonster::GetCookieListWithOptions, base::Unretained(this), url,
532*6777b538SAndroid Build Coastguard Worker           options, cookie_partition_key_collection, std::move(callback)),
533*6777b538SAndroid Build Coastguard Worker       url);
534*6777b538SAndroid Build Coastguard Worker }
535*6777b538SAndroid Build Coastguard Worker 
GetAllCookiesAsync(GetAllCookiesCallback callback)536*6777b538SAndroid Build Coastguard Worker void CookieMonster::GetAllCookiesAsync(GetAllCookiesCallback callback) {
537*6777b538SAndroid Build Coastguard Worker   DoCookieCallback(base::BindOnce(
538*6777b538SAndroid Build Coastguard Worker       // base::Unretained is safe as DoCookieCallback stores
539*6777b538SAndroid Build Coastguard Worker       // the callback on |*this|, so the callback will not outlive
540*6777b538SAndroid Build Coastguard Worker       // the object.
541*6777b538SAndroid Build Coastguard Worker       &CookieMonster::GetAllCookies, base::Unretained(this),
542*6777b538SAndroid Build Coastguard Worker       std::move(callback)));
543*6777b538SAndroid Build Coastguard Worker }
544*6777b538SAndroid Build Coastguard Worker 
GetAllCookiesWithAccessSemanticsAsync(GetAllCookiesWithAccessSemanticsCallback callback)545*6777b538SAndroid Build Coastguard Worker void CookieMonster::GetAllCookiesWithAccessSemanticsAsync(
546*6777b538SAndroid Build Coastguard Worker     GetAllCookiesWithAccessSemanticsCallback callback) {
547*6777b538SAndroid Build Coastguard Worker   DoCookieCallback(base::BindOnce(
548*6777b538SAndroid Build Coastguard Worker       // base::Unretained is safe as DoCookieCallback stores
549*6777b538SAndroid Build Coastguard Worker       // the callback on |*this|, so the callback will not outlive
550*6777b538SAndroid Build Coastguard Worker       // the object.
551*6777b538SAndroid Build Coastguard Worker       &CookieMonster::GetAllCookies, base::Unretained(this),
552*6777b538SAndroid Build Coastguard Worker       base::BindOnce(&CookieMonster::AttachAccessSemanticsListForCookieList,
553*6777b538SAndroid Build Coastguard Worker                      base::Unretained(this), std::move(callback))));
554*6777b538SAndroid Build Coastguard Worker }
555*6777b538SAndroid Build Coastguard Worker 
DeleteCanonicalCookieAsync(const CanonicalCookie & cookie,DeleteCallback callback)556*6777b538SAndroid Build Coastguard Worker void CookieMonster::DeleteCanonicalCookieAsync(const CanonicalCookie& cookie,
557*6777b538SAndroid Build Coastguard Worker                                                DeleteCallback callback) {
558*6777b538SAndroid Build Coastguard Worker   DoCookieCallback(base::BindOnce(
559*6777b538SAndroid Build Coastguard Worker       // base::Unretained is safe as DoCookieCallback stores
560*6777b538SAndroid Build Coastguard Worker       // the callback on |*this|, so the callback will not outlive
561*6777b538SAndroid Build Coastguard Worker       // the object.
562*6777b538SAndroid Build Coastguard Worker       &CookieMonster::DeleteCanonicalCookie, base::Unretained(this), cookie,
563*6777b538SAndroid Build Coastguard Worker       std::move(callback)));
564*6777b538SAndroid Build Coastguard Worker }
565*6777b538SAndroid Build Coastguard Worker 
DeleteAllCreatedInTimeRangeAsync(const TimeRange & creation_range,DeleteCallback callback)566*6777b538SAndroid Build Coastguard Worker void CookieMonster::DeleteAllCreatedInTimeRangeAsync(
567*6777b538SAndroid Build Coastguard Worker     const TimeRange& creation_range,
568*6777b538SAndroid Build Coastguard Worker     DeleteCallback callback) {
569*6777b538SAndroid Build Coastguard Worker   DoCookieCallback(base::BindOnce(
570*6777b538SAndroid Build Coastguard Worker       // base::Unretained is safe as DoCookieCallback stores
571*6777b538SAndroid Build Coastguard Worker       // the callback on |*this|, so the callback will not outlive
572*6777b538SAndroid Build Coastguard Worker       // the object.
573*6777b538SAndroid Build Coastguard Worker       &CookieMonster::DeleteAllCreatedInTimeRange, base::Unretained(this),
574*6777b538SAndroid Build Coastguard Worker       creation_range, std::move(callback)));
575*6777b538SAndroid Build Coastguard Worker }
576*6777b538SAndroid Build Coastguard Worker 
DeleteAllMatchingInfoAsync(CookieDeletionInfo delete_info,DeleteCallback callback)577*6777b538SAndroid Build Coastguard Worker void CookieMonster::DeleteAllMatchingInfoAsync(CookieDeletionInfo delete_info,
578*6777b538SAndroid Build Coastguard Worker                                                DeleteCallback callback) {
579*6777b538SAndroid Build Coastguard Worker   auto cookie_matcher =
580*6777b538SAndroid Build Coastguard Worker       base::BindRepeating(&CookieMonster::MatchCookieDeletionInfo,
581*6777b538SAndroid Build Coastguard Worker                           base::Unretained(this), std::move(delete_info));
582*6777b538SAndroid Build Coastguard Worker 
583*6777b538SAndroid Build Coastguard Worker   DoCookieCallback(base::BindOnce(
584*6777b538SAndroid Build Coastguard Worker       // base::Unretained is safe as DoCookieCallback stores
585*6777b538SAndroid Build Coastguard Worker       // the callback on |*this|, so the callback will not outlive
586*6777b538SAndroid Build Coastguard Worker       // the object.
587*6777b538SAndroid Build Coastguard Worker       &CookieMonster::DeleteMatchingCookies, base::Unretained(this),
588*6777b538SAndroid Build Coastguard Worker       std::move(cookie_matcher), DELETE_COOKIE_EXPLICIT, std::move(callback)));
589*6777b538SAndroid Build Coastguard Worker }
590*6777b538SAndroid Build Coastguard Worker 
DeleteSessionCookiesAsync(CookieStore::DeleteCallback callback)591*6777b538SAndroid Build Coastguard Worker void CookieMonster::DeleteSessionCookiesAsync(
592*6777b538SAndroid Build Coastguard Worker     CookieStore::DeleteCallback callback) {
593*6777b538SAndroid Build Coastguard Worker   auto session_cookie_matcher =
594*6777b538SAndroid Build Coastguard Worker       base::BindRepeating([](const net::CanonicalCookie& cookie) {
595*6777b538SAndroid Build Coastguard Worker         return !cookie.IsPersistent();
596*6777b538SAndroid Build Coastguard Worker       });
597*6777b538SAndroid Build Coastguard Worker   DoCookieCallback(base::BindOnce(
598*6777b538SAndroid Build Coastguard Worker       // base::Unretained is safe as DoCookieCallback stores
599*6777b538SAndroid Build Coastguard Worker       // the callback on |*this|, so the callback will not outlive
600*6777b538SAndroid Build Coastguard Worker       // the object.
601*6777b538SAndroid Build Coastguard Worker       &CookieMonster::DeleteMatchingCookies, base::Unretained(this),
602*6777b538SAndroid Build Coastguard Worker       std::move(session_cookie_matcher), DELETE_COOKIE_EXPIRED,
603*6777b538SAndroid Build Coastguard Worker       std::move(callback)));
604*6777b538SAndroid Build Coastguard Worker }
605*6777b538SAndroid Build Coastguard Worker 
DeleteMatchingCookiesAsync(CookieStore::DeletePredicate predicate,CookieStore::DeleteCallback callback)606*6777b538SAndroid Build Coastguard Worker void CookieMonster::DeleteMatchingCookiesAsync(
607*6777b538SAndroid Build Coastguard Worker     CookieStore::DeletePredicate predicate,
608*6777b538SAndroid Build Coastguard Worker     CookieStore::DeleteCallback callback) {
609*6777b538SAndroid Build Coastguard Worker   DoCookieCallback(base::BindOnce(
610*6777b538SAndroid Build Coastguard Worker       // base::Unretained is safe as DoCookieCallback stores
611*6777b538SAndroid Build Coastguard Worker       // the callback on |*this|, so the callback will not outlive
612*6777b538SAndroid Build Coastguard Worker       // the object.
613*6777b538SAndroid Build Coastguard Worker       &CookieMonster::DeleteMatchingCookies, base::Unretained(this),
614*6777b538SAndroid Build Coastguard Worker       std::move(predicate), DELETE_COOKIE_EXPLICIT, std::move(callback)));
615*6777b538SAndroid Build Coastguard Worker }
616*6777b538SAndroid Build Coastguard Worker 
SetCookieableSchemes(const std::vector<std::string> & schemes,SetCookieableSchemesCallback callback)617*6777b538SAndroid Build Coastguard Worker void CookieMonster::SetCookieableSchemes(
618*6777b538SAndroid Build Coastguard Worker     const std::vector<std::string>& schemes,
619*6777b538SAndroid Build Coastguard Worker     SetCookieableSchemesCallback callback) {
620*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
621*6777b538SAndroid Build Coastguard Worker 
622*6777b538SAndroid Build Coastguard Worker   // Calls to this method will have no effect if made after a WebView or
623*6777b538SAndroid Build Coastguard Worker   // CookieManager instance has been created.
624*6777b538SAndroid Build Coastguard Worker   if (initialized_) {
625*6777b538SAndroid Build Coastguard Worker     MaybeRunCookieCallback(std::move(callback), false);
626*6777b538SAndroid Build Coastguard Worker     return;
627*6777b538SAndroid Build Coastguard Worker   }
628*6777b538SAndroid Build Coastguard Worker 
629*6777b538SAndroid Build Coastguard Worker   cookieable_schemes_ = schemes;
630*6777b538SAndroid Build Coastguard Worker   MaybeRunCookieCallback(std::move(callback), true);
631*6777b538SAndroid Build Coastguard Worker }
632*6777b538SAndroid Build Coastguard Worker 
633*6777b538SAndroid Build Coastguard Worker // This function must be called before the CookieMonster is used.
SetPersistSessionCookies(bool persist_session_cookies)634*6777b538SAndroid Build Coastguard Worker void CookieMonster::SetPersistSessionCookies(bool persist_session_cookies) {
635*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
636*6777b538SAndroid Build Coastguard Worker   DCHECK(!initialized_);
637*6777b538SAndroid Build Coastguard Worker   net_log_.AddEntryWithBoolParams(
638*6777b538SAndroid Build Coastguard Worker       NetLogEventType::COOKIE_STORE_SESSION_PERSISTENCE, NetLogEventPhase::NONE,
639*6777b538SAndroid Build Coastguard Worker       "persistence", persist_session_cookies);
640*6777b538SAndroid Build Coastguard Worker   persist_session_cookies_ = persist_session_cookies;
641*6777b538SAndroid Build Coastguard Worker }
642*6777b538SAndroid Build Coastguard Worker 
643*6777b538SAndroid Build Coastguard Worker const char* const CookieMonster::kDefaultCookieableSchemes[] = {"http", "https",
644*6777b538SAndroid Build Coastguard Worker                                                                 "ws", "wss"};
645*6777b538SAndroid Build Coastguard Worker const int CookieMonster::kDefaultCookieableSchemesCount =
646*6777b538SAndroid Build Coastguard Worker     std::size(kDefaultCookieableSchemes);
647*6777b538SAndroid Build Coastguard Worker 
GetChangeDispatcher()648*6777b538SAndroid Build Coastguard Worker CookieChangeDispatcher& CookieMonster::GetChangeDispatcher() {
649*6777b538SAndroid Build Coastguard Worker   return change_dispatcher_;
650*6777b538SAndroid Build Coastguard Worker }
651*6777b538SAndroid Build Coastguard Worker 
~CookieMonster()652*6777b538SAndroid Build Coastguard Worker CookieMonster::~CookieMonster() {
653*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
654*6777b538SAndroid Build Coastguard Worker   net_log_.EndEvent(NetLogEventType::COOKIE_STORE_ALIVE);
655*6777b538SAndroid Build Coastguard Worker }
656*6777b538SAndroid Build Coastguard Worker 
657*6777b538SAndroid Build Coastguard Worker // static
CookieSorter(const CanonicalCookie * cc1,const CanonicalCookie * cc2)658*6777b538SAndroid Build Coastguard Worker bool CookieMonster::CookieSorter(const CanonicalCookie* cc1,
659*6777b538SAndroid Build Coastguard Worker                                  const CanonicalCookie* cc2) {
660*6777b538SAndroid Build Coastguard Worker   // Mozilla sorts on the path length (longest first), and then it sorts by
661*6777b538SAndroid Build Coastguard Worker   // creation time (oldest first).  The RFC says the sort order for the domain
662*6777b538SAndroid Build Coastguard Worker   // attribute is undefined.
663*6777b538SAndroid Build Coastguard Worker   if (cc1->Path().length() == cc2->Path().length())
664*6777b538SAndroid Build Coastguard Worker     return cc1->CreationDate() < cc2->CreationDate();
665*6777b538SAndroid Build Coastguard Worker   return cc1->Path().length() > cc2->Path().length();
666*6777b538SAndroid Build Coastguard Worker }
667*6777b538SAndroid Build Coastguard Worker 
GetAllCookies(GetAllCookiesCallback callback)668*6777b538SAndroid Build Coastguard Worker void CookieMonster::GetAllCookies(GetAllCookiesCallback callback) {
669*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
670*6777b538SAndroid Build Coastguard Worker 
671*6777b538SAndroid Build Coastguard Worker   // This function is being called to scrape the cookie list for management UI
672*6777b538SAndroid Build Coastguard Worker   // or similar.  We shouldn't show expired cookies in this list since it will
673*6777b538SAndroid Build Coastguard Worker   // just be confusing to users, and this function is called rarely enough (and
674*6777b538SAndroid Build Coastguard Worker   // is already slow enough) that it's OK to take the time to garbage collect
675*6777b538SAndroid Build Coastguard Worker   // the expired cookies now.
676*6777b538SAndroid Build Coastguard Worker   //
677*6777b538SAndroid Build Coastguard Worker   // Note that this does not prune cookies to be below our limits (if we've
678*6777b538SAndroid Build Coastguard Worker   // exceeded them) the way that calling GarbageCollect() would.
679*6777b538SAndroid Build Coastguard Worker   GarbageCollectExpired(
680*6777b538SAndroid Build Coastguard Worker       Time::Now(), CookieMapItPair(cookies_.begin(), cookies_.end()), nullptr);
681*6777b538SAndroid Build Coastguard Worker   GarbageCollectAllExpiredPartitionedCookies(Time::Now());
682*6777b538SAndroid Build Coastguard Worker 
683*6777b538SAndroid Build Coastguard Worker   // Copy the CanonicalCookie pointers from the map so that we can use the same
684*6777b538SAndroid Build Coastguard Worker   // sorter as elsewhere, then copy the result out.
685*6777b538SAndroid Build Coastguard Worker   std::vector<CanonicalCookie*> cookie_ptrs;
686*6777b538SAndroid Build Coastguard Worker   cookie_ptrs.reserve(cookies_.size());
687*6777b538SAndroid Build Coastguard Worker   for (const auto& cookie : cookies_)
688*6777b538SAndroid Build Coastguard Worker     cookie_ptrs.push_back(cookie.second.get());
689*6777b538SAndroid Build Coastguard Worker 
690*6777b538SAndroid Build Coastguard Worker   for (const auto& cookie_partition : partitioned_cookies_) {
691*6777b538SAndroid Build Coastguard Worker     for (const auto& cookie : *cookie_partition.second.get())
692*6777b538SAndroid Build Coastguard Worker       cookie_ptrs.push_back(cookie.second.get());
693*6777b538SAndroid Build Coastguard Worker   }
694*6777b538SAndroid Build Coastguard Worker 
695*6777b538SAndroid Build Coastguard Worker   std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
696*6777b538SAndroid Build Coastguard Worker 
697*6777b538SAndroid Build Coastguard Worker   CookieList cookie_list;
698*6777b538SAndroid Build Coastguard Worker   cookie_list.reserve(cookie_ptrs.size());
699*6777b538SAndroid Build Coastguard Worker   for (auto* cookie_ptr : cookie_ptrs)
700*6777b538SAndroid Build Coastguard Worker     cookie_list.push_back(*cookie_ptr);
701*6777b538SAndroid Build Coastguard Worker 
702*6777b538SAndroid Build Coastguard Worker   MaybeRunCookieCallback(std::move(callback), cookie_list);
703*6777b538SAndroid Build Coastguard Worker }
704*6777b538SAndroid Build Coastguard Worker 
AttachAccessSemanticsListForCookieList(GetAllCookiesWithAccessSemanticsCallback callback,const CookieList & cookie_list)705*6777b538SAndroid Build Coastguard Worker void CookieMonster::AttachAccessSemanticsListForCookieList(
706*6777b538SAndroid Build Coastguard Worker     GetAllCookiesWithAccessSemanticsCallback callback,
707*6777b538SAndroid Build Coastguard Worker     const CookieList& cookie_list) {
708*6777b538SAndroid Build Coastguard Worker   std::vector<CookieAccessSemantics> access_semantics_list;
709*6777b538SAndroid Build Coastguard Worker   for (const CanonicalCookie& cookie : cookie_list) {
710*6777b538SAndroid Build Coastguard Worker     access_semantics_list.push_back(GetAccessSemanticsForCookie(cookie));
711*6777b538SAndroid Build Coastguard Worker   }
712*6777b538SAndroid Build Coastguard Worker   MaybeRunCookieCallback(std::move(callback), cookie_list,
713*6777b538SAndroid Build Coastguard Worker                          access_semantics_list);
714*6777b538SAndroid Build Coastguard Worker }
715*6777b538SAndroid Build Coastguard Worker 
GetCookieListWithOptions(const GURL & url,const CookieOptions & options,const CookiePartitionKeyCollection & cookie_partition_key_collection,GetCookieListCallback callback)716*6777b538SAndroid Build Coastguard Worker void CookieMonster::GetCookieListWithOptions(
717*6777b538SAndroid Build Coastguard Worker     const GURL& url,
718*6777b538SAndroid Build Coastguard Worker     const CookieOptions& options,
719*6777b538SAndroid Build Coastguard Worker     const CookiePartitionKeyCollection& cookie_partition_key_collection,
720*6777b538SAndroid Build Coastguard Worker     GetCookieListCallback callback) {
721*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
722*6777b538SAndroid Build Coastguard Worker 
723*6777b538SAndroid Build Coastguard Worker   CookieAccessResultList included_cookies;
724*6777b538SAndroid Build Coastguard Worker   CookieAccessResultList excluded_cookies;
725*6777b538SAndroid Build Coastguard Worker   if (HasCookieableScheme(url)) {
726*6777b538SAndroid Build Coastguard Worker     std::vector<CanonicalCookie*> cookie_ptrs;
727*6777b538SAndroid Build Coastguard Worker     if (IncludeUnpartitionedCookies(cookie_partition_key_collection)) {
728*6777b538SAndroid Build Coastguard Worker       cookie_ptrs = FindCookiesForRegistryControlledHost(url);
729*6777b538SAndroid Build Coastguard Worker     } else {
730*6777b538SAndroid Build Coastguard Worker       DCHECK(!cookie_partition_key_collection.IsEmpty());
731*6777b538SAndroid Build Coastguard Worker     }
732*6777b538SAndroid Build Coastguard Worker 
733*6777b538SAndroid Build Coastguard Worker     if (!cookie_partition_key_collection.IsEmpty()) {
734*6777b538SAndroid Build Coastguard Worker       if (cookie_partition_key_collection.ContainsAllKeys()) {
735*6777b538SAndroid Build Coastguard Worker         for (const auto& it : partitioned_cookies_) {
736*6777b538SAndroid Build Coastguard Worker           std::vector<CanonicalCookie*> partitioned_cookie_ptrs =
737*6777b538SAndroid Build Coastguard Worker               FindPartitionedCookiesForRegistryControlledHost(it.first, url);
738*6777b538SAndroid Build Coastguard Worker           cookie_ptrs.insert(cookie_ptrs.end(), partitioned_cookie_ptrs.begin(),
739*6777b538SAndroid Build Coastguard Worker                              partitioned_cookie_ptrs.end());
740*6777b538SAndroid Build Coastguard Worker         }
741*6777b538SAndroid Build Coastguard Worker       } else {
742*6777b538SAndroid Build Coastguard Worker         for (const CookiePartitionKey& key :
743*6777b538SAndroid Build Coastguard Worker              cookie_partition_key_collection.PartitionKeys()) {
744*6777b538SAndroid Build Coastguard Worker           std::vector<CanonicalCookie*> partitioned_cookie_ptrs =
745*6777b538SAndroid Build Coastguard Worker               FindPartitionedCookiesForRegistryControlledHost(key, url);
746*6777b538SAndroid Build Coastguard Worker           cookie_ptrs.insert(cookie_ptrs.end(), partitioned_cookie_ptrs.begin(),
747*6777b538SAndroid Build Coastguard Worker                              partitioned_cookie_ptrs.end());
748*6777b538SAndroid Build Coastguard Worker         }
749*6777b538SAndroid Build Coastguard Worker       }
750*6777b538SAndroid Build Coastguard Worker     }
751*6777b538SAndroid Build Coastguard Worker     std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
752*6777b538SAndroid Build Coastguard Worker 
753*6777b538SAndroid Build Coastguard Worker     included_cookies.reserve(cookie_ptrs.size());
754*6777b538SAndroid Build Coastguard Worker     FilterCookiesWithOptions(url, options, &cookie_ptrs, &included_cookies,
755*6777b538SAndroid Build Coastguard Worker                              &excluded_cookies);
756*6777b538SAndroid Build Coastguard Worker   }
757*6777b538SAndroid Build Coastguard Worker 
758*6777b538SAndroid Build Coastguard Worker   MaybeRunCookieCallback(std::move(callback), included_cookies,
759*6777b538SAndroid Build Coastguard Worker                          excluded_cookies);
760*6777b538SAndroid Build Coastguard Worker }
761*6777b538SAndroid Build Coastguard Worker 
DeleteAllCreatedInTimeRange(const TimeRange & creation_range,DeleteCallback callback)762*6777b538SAndroid Build Coastguard Worker void CookieMonster::DeleteAllCreatedInTimeRange(const TimeRange& creation_range,
763*6777b538SAndroid Build Coastguard Worker                                                 DeleteCallback callback) {
764*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
765*6777b538SAndroid Build Coastguard Worker 
766*6777b538SAndroid Build Coastguard Worker   uint32_t num_deleted = 0;
767*6777b538SAndroid Build Coastguard Worker   for (auto it = cookies_.begin(); it != cookies_.end();) {
768*6777b538SAndroid Build Coastguard Worker     auto curit = it;
769*6777b538SAndroid Build Coastguard Worker     CanonicalCookie* cc = curit->second.get();
770*6777b538SAndroid Build Coastguard Worker     ++it;
771*6777b538SAndroid Build Coastguard Worker 
772*6777b538SAndroid Build Coastguard Worker     if (creation_range.Contains(cc->CreationDate())) {
773*6777b538SAndroid Build Coastguard Worker       InternalDeleteCookie(curit, true, /*sync_to_store*/
774*6777b538SAndroid Build Coastguard Worker                            DELETE_COOKIE_EXPLICIT);
775*6777b538SAndroid Build Coastguard Worker       ++num_deleted;
776*6777b538SAndroid Build Coastguard Worker     }
777*6777b538SAndroid Build Coastguard Worker   }
778*6777b538SAndroid Build Coastguard Worker 
779*6777b538SAndroid Build Coastguard Worker   for (PartitionedCookieMap::iterator partition_it =
780*6777b538SAndroid Build Coastguard Worker            partitioned_cookies_.begin();
781*6777b538SAndroid Build Coastguard Worker        partition_it != partitioned_cookies_.end();) {
782*6777b538SAndroid Build Coastguard Worker     auto cur_partition_it = partition_it;
783*6777b538SAndroid Build Coastguard Worker     CookieMap::iterator cookie_it = cur_partition_it->second->begin();
784*6777b538SAndroid Build Coastguard Worker     CookieMap::iterator cookie_end = cur_partition_it->second->end();
785*6777b538SAndroid Build Coastguard Worker     // InternalDeletePartitionedCookie may delete this cookie partition if it
786*6777b538SAndroid Build Coastguard Worker     // only has one cookie, so we need to increment the iterator beforehand.
787*6777b538SAndroid Build Coastguard Worker     ++partition_it;
788*6777b538SAndroid Build Coastguard Worker 
789*6777b538SAndroid Build Coastguard Worker     while (cookie_it != cookie_end) {
790*6777b538SAndroid Build Coastguard Worker       auto cur_cookie_it = cookie_it;
791*6777b538SAndroid Build Coastguard Worker       CanonicalCookie* cc = cur_cookie_it->second.get();
792*6777b538SAndroid Build Coastguard Worker       ++cookie_it;
793*6777b538SAndroid Build Coastguard Worker 
794*6777b538SAndroid Build Coastguard Worker       if (creation_range.Contains(cc->CreationDate())) {
795*6777b538SAndroid Build Coastguard Worker         InternalDeletePartitionedCookie(cur_partition_it, cur_cookie_it,
796*6777b538SAndroid Build Coastguard Worker                                         true /*sync_to_store*/,
797*6777b538SAndroid Build Coastguard Worker                                         DELETE_COOKIE_EXPLICIT);
798*6777b538SAndroid Build Coastguard Worker         ++num_deleted;
799*6777b538SAndroid Build Coastguard Worker       }
800*6777b538SAndroid Build Coastguard Worker     }
801*6777b538SAndroid Build Coastguard Worker   }
802*6777b538SAndroid Build Coastguard Worker 
803*6777b538SAndroid Build Coastguard Worker   FlushStore(
804*6777b538SAndroid Build Coastguard Worker       base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
805*6777b538SAndroid Build Coastguard Worker                      callback ? base::BindOnce(std::move(callback), num_deleted)
806*6777b538SAndroid Build Coastguard Worker                               : base::OnceClosure()));
807*6777b538SAndroid Build Coastguard Worker }
808*6777b538SAndroid Build Coastguard Worker 
MatchCookieDeletionInfo(const CookieDeletionInfo & delete_info,const net::CanonicalCookie & cookie)809*6777b538SAndroid Build Coastguard Worker bool CookieMonster::MatchCookieDeletionInfo(
810*6777b538SAndroid Build Coastguard Worker     const CookieDeletionInfo& delete_info,
811*6777b538SAndroid Build Coastguard Worker     const net::CanonicalCookie& cookie) {
812*6777b538SAndroid Build Coastguard Worker   bool delegate_treats_url_as_trustworthy = false;  // irrelevant if no URL.
813*6777b538SAndroid Build Coastguard Worker   if (delete_info.url.has_value()) {
814*6777b538SAndroid Build Coastguard Worker     delegate_treats_url_as_trustworthy =
815*6777b538SAndroid Build Coastguard Worker         cookie_access_delegate() &&
816*6777b538SAndroid Build Coastguard Worker         cookie_access_delegate()->ShouldTreatUrlAsTrustworthy(
817*6777b538SAndroid Build Coastguard Worker             delete_info.url.value());
818*6777b538SAndroid Build Coastguard Worker   }
819*6777b538SAndroid Build Coastguard Worker 
820*6777b538SAndroid Build Coastguard Worker   return delete_info.Matches(
821*6777b538SAndroid Build Coastguard Worker       cookie, CookieAccessParams{GetAccessSemanticsForCookie(cookie),
822*6777b538SAndroid Build Coastguard Worker                                  delegate_treats_url_as_trustworthy});
823*6777b538SAndroid Build Coastguard Worker }
824*6777b538SAndroid Build Coastguard Worker 
DeleteCanonicalCookie(const CanonicalCookie & cookie,DeleteCallback callback)825*6777b538SAndroid Build Coastguard Worker void CookieMonster::DeleteCanonicalCookie(const CanonicalCookie& cookie,
826*6777b538SAndroid Build Coastguard Worker                                           DeleteCallback callback) {
827*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
828*6777b538SAndroid Build Coastguard Worker   uint32_t result = 0u;
829*6777b538SAndroid Build Coastguard Worker   CookieMap* cookie_map = nullptr;
830*6777b538SAndroid Build Coastguard Worker   PartitionedCookieMap::iterator cookie_partition_it;
831*6777b538SAndroid Build Coastguard Worker 
832*6777b538SAndroid Build Coastguard Worker   if (cookie.IsPartitioned()) {
833*6777b538SAndroid Build Coastguard Worker     cookie_partition_it =
834*6777b538SAndroid Build Coastguard Worker         partitioned_cookies_.find(cookie.PartitionKey().value());
835*6777b538SAndroid Build Coastguard Worker     if (cookie_partition_it != partitioned_cookies_.end())
836*6777b538SAndroid Build Coastguard Worker       cookie_map = cookie_partition_it->second.get();
837*6777b538SAndroid Build Coastguard Worker   } else {
838*6777b538SAndroid Build Coastguard Worker     cookie_map = &cookies_;
839*6777b538SAndroid Build Coastguard Worker   }
840*6777b538SAndroid Build Coastguard Worker   if (cookie_map) {
841*6777b538SAndroid Build Coastguard Worker     for (CookieMapItPair its = cookie_map->equal_range(GetKey(cookie.Domain()));
842*6777b538SAndroid Build Coastguard Worker          its.first != its.second; ++its.first) {
843*6777b538SAndroid Build Coastguard Worker       const std::unique_ptr<CanonicalCookie>& candidate = its.first->second;
844*6777b538SAndroid Build Coastguard Worker       // Historically, this has refused modification if the cookie has changed
845*6777b538SAndroid Build Coastguard Worker       // value in between the CanonicalCookie object was returned by a getter
846*6777b538SAndroid Build Coastguard Worker       // and when this ran.  The later parts of the conditional (everything but
847*6777b538SAndroid Build Coastguard Worker       // the equivalence check) attempt to preserve this behavior.
848*6777b538SAndroid Build Coastguard Worker       if (candidate->IsEquivalent(cookie) &&
849*6777b538SAndroid Build Coastguard Worker           candidate->Value() == cookie.Value()) {
850*6777b538SAndroid Build Coastguard Worker         if (cookie.IsPartitioned()) {
851*6777b538SAndroid Build Coastguard Worker           InternalDeletePartitionedCookie(cookie_partition_it, its.first, true,
852*6777b538SAndroid Build Coastguard Worker                                           DELETE_COOKIE_EXPLICIT);
853*6777b538SAndroid Build Coastguard Worker         } else {
854*6777b538SAndroid Build Coastguard Worker           InternalDeleteCookie(its.first, true, DELETE_COOKIE_EXPLICIT);
855*6777b538SAndroid Build Coastguard Worker         }
856*6777b538SAndroid Build Coastguard Worker         result = 1u;
857*6777b538SAndroid Build Coastguard Worker         break;
858*6777b538SAndroid Build Coastguard Worker       }
859*6777b538SAndroid Build Coastguard Worker     }
860*6777b538SAndroid Build Coastguard Worker   }
861*6777b538SAndroid Build Coastguard Worker   FlushStore(
862*6777b538SAndroid Build Coastguard Worker       base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
863*6777b538SAndroid Build Coastguard Worker                      callback ? base::BindOnce(std::move(callback), result)
864*6777b538SAndroid Build Coastguard Worker                               : base::OnceClosure()));
865*6777b538SAndroid Build Coastguard Worker }
866*6777b538SAndroid Build Coastguard Worker 
DeleteMatchingCookies(DeletePredicate predicate,DeletionCause cause,DeleteCallback callback)867*6777b538SAndroid Build Coastguard Worker void CookieMonster::DeleteMatchingCookies(DeletePredicate predicate,
868*6777b538SAndroid Build Coastguard Worker                                           DeletionCause cause,
869*6777b538SAndroid Build Coastguard Worker                                           DeleteCallback callback) {
870*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
871*6777b538SAndroid Build Coastguard Worker   DCHECK(predicate);
872*6777b538SAndroid Build Coastguard Worker 
873*6777b538SAndroid Build Coastguard Worker   uint32_t num_deleted = 0;
874*6777b538SAndroid Build Coastguard Worker   for (auto it = cookies_.begin(); it != cookies_.end();) {
875*6777b538SAndroid Build Coastguard Worker     auto curit = it;
876*6777b538SAndroid Build Coastguard Worker     CanonicalCookie* cc = curit->second.get();
877*6777b538SAndroid Build Coastguard Worker     ++it;
878*6777b538SAndroid Build Coastguard Worker     if (predicate.Run(*cc)) {
879*6777b538SAndroid Build Coastguard Worker       InternalDeleteCookie(curit, true /*sync_to_store*/, cause);
880*6777b538SAndroid Build Coastguard Worker       ++num_deleted;
881*6777b538SAndroid Build Coastguard Worker     }
882*6777b538SAndroid Build Coastguard Worker   }
883*6777b538SAndroid Build Coastguard Worker   for (auto partition_it = partitioned_cookies_.begin();
884*6777b538SAndroid Build Coastguard Worker        partition_it != partitioned_cookies_.end();) {
885*6777b538SAndroid Build Coastguard Worker     // InternalDeletePartitionedCookie may invalidate |partition_it| if that
886*6777b538SAndroid Build Coastguard Worker     // cookie partition only has one cookie.
887*6777b538SAndroid Build Coastguard Worker     auto cur_partition_it = partition_it;
888*6777b538SAndroid Build Coastguard Worker     CookieMap::iterator cookie_it = cur_partition_it->second->begin();
889*6777b538SAndroid Build Coastguard Worker     CookieMap::iterator cookie_end = cur_partition_it->second->end();
890*6777b538SAndroid Build Coastguard Worker     ++partition_it;
891*6777b538SAndroid Build Coastguard Worker 
892*6777b538SAndroid Build Coastguard Worker     while (cookie_it != cookie_end) {
893*6777b538SAndroid Build Coastguard Worker       auto cur_cookie_it = cookie_it;
894*6777b538SAndroid Build Coastguard Worker       CanonicalCookie* cc = cur_cookie_it->second.get();
895*6777b538SAndroid Build Coastguard Worker       ++cookie_it;
896*6777b538SAndroid Build Coastguard Worker 
897*6777b538SAndroid Build Coastguard Worker       if (predicate.Run(*cc)) {
898*6777b538SAndroid Build Coastguard Worker         InternalDeletePartitionedCookie(cur_partition_it, cur_cookie_it, true,
899*6777b538SAndroid Build Coastguard Worker                                         cause);
900*6777b538SAndroid Build Coastguard Worker         ++num_deleted;
901*6777b538SAndroid Build Coastguard Worker       }
902*6777b538SAndroid Build Coastguard Worker     }
903*6777b538SAndroid Build Coastguard Worker   }
904*6777b538SAndroid Build Coastguard Worker 
905*6777b538SAndroid Build Coastguard Worker   FlushStore(
906*6777b538SAndroid Build Coastguard Worker       base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
907*6777b538SAndroid Build Coastguard Worker                      callback ? base::BindOnce(std::move(callback), num_deleted)
908*6777b538SAndroid Build Coastguard Worker                               : base::OnceClosure()));
909*6777b538SAndroid Build Coastguard Worker }
910*6777b538SAndroid Build Coastguard Worker 
MarkCookieStoreAsInitialized()911*6777b538SAndroid Build Coastguard Worker void CookieMonster::MarkCookieStoreAsInitialized() {
912*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
913*6777b538SAndroid Build Coastguard Worker   initialized_ = true;
914*6777b538SAndroid Build Coastguard Worker }
915*6777b538SAndroid Build Coastguard Worker 
FetchAllCookiesIfNecessary()916*6777b538SAndroid Build Coastguard Worker void CookieMonster::FetchAllCookiesIfNecessary() {
917*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
918*6777b538SAndroid Build Coastguard Worker   if (store_.get() && !started_fetching_all_cookies_) {
919*6777b538SAndroid Build Coastguard Worker     started_fetching_all_cookies_ = true;
920*6777b538SAndroid Build Coastguard Worker     FetchAllCookies();
921*6777b538SAndroid Build Coastguard Worker   }
922*6777b538SAndroid Build Coastguard Worker }
923*6777b538SAndroid Build Coastguard Worker 
FetchAllCookies()924*6777b538SAndroid Build Coastguard Worker void CookieMonster::FetchAllCookies() {
925*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
926*6777b538SAndroid Build Coastguard Worker   DCHECK(store_.get()) << "Store must exist to initialize";
927*6777b538SAndroid Build Coastguard Worker   DCHECK(!finished_fetching_all_cookies_)
928*6777b538SAndroid Build Coastguard Worker       << "All cookies have already been fetched.";
929*6777b538SAndroid Build Coastguard Worker 
930*6777b538SAndroid Build Coastguard Worker   // We bind in the current time so that we can report the wall-clock time for
931*6777b538SAndroid Build Coastguard Worker   // loading cookies.
932*6777b538SAndroid Build Coastguard Worker   store_->Load(base::BindOnce(&CookieMonster::OnLoaded,
933*6777b538SAndroid Build Coastguard Worker                               weak_ptr_factory_.GetWeakPtr(), TimeTicks::Now()),
934*6777b538SAndroid Build Coastguard Worker                net_log_);
935*6777b538SAndroid Build Coastguard Worker }
936*6777b538SAndroid Build Coastguard Worker 
OnLoaded(TimeTicks beginning_time,std::vector<std::unique_ptr<CanonicalCookie>> cookies)937*6777b538SAndroid Build Coastguard Worker void CookieMonster::OnLoaded(
938*6777b538SAndroid Build Coastguard Worker     TimeTicks beginning_time,
939*6777b538SAndroid Build Coastguard Worker     std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
940*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
941*6777b538SAndroid Build Coastguard Worker   StoreLoadedCookies(std::move(cookies));
942*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramCustomTimes("Cookie.TimeBlockedOnLoad",
943*6777b538SAndroid Build Coastguard Worker                                 base::TimeTicks::Now() - beginning_time,
944*6777b538SAndroid Build Coastguard Worker                                 base::Milliseconds(1), base::Minutes(1), 50);
945*6777b538SAndroid Build Coastguard Worker 
946*6777b538SAndroid Build Coastguard Worker   // Invoke the task queue of cookie request.
947*6777b538SAndroid Build Coastguard Worker   InvokeQueue();
948*6777b538SAndroid Build Coastguard Worker }
949*6777b538SAndroid Build Coastguard Worker 
OnKeyLoaded(const std::string & key,std::vector<std::unique_ptr<CanonicalCookie>> cookies)950*6777b538SAndroid Build Coastguard Worker void CookieMonster::OnKeyLoaded(
951*6777b538SAndroid Build Coastguard Worker     const std::string& key,
952*6777b538SAndroid Build Coastguard Worker     std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
953*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
954*6777b538SAndroid Build Coastguard Worker 
955*6777b538SAndroid Build Coastguard Worker   StoreLoadedCookies(std::move(cookies));
956*6777b538SAndroid Build Coastguard Worker 
957*6777b538SAndroid Build Coastguard Worker   auto tasks_pending_for_key = tasks_pending_for_key_.find(key);
958*6777b538SAndroid Build Coastguard Worker 
959*6777b538SAndroid Build Coastguard Worker   // TODO(mmenke): Can this be turned into a DCHECK?
960*6777b538SAndroid Build Coastguard Worker   if (tasks_pending_for_key == tasks_pending_for_key_.end())
961*6777b538SAndroid Build Coastguard Worker     return;
962*6777b538SAndroid Build Coastguard Worker 
963*6777b538SAndroid Build Coastguard Worker   // Run all tasks for the key. Note that running a task can result in multiple
964*6777b538SAndroid Build Coastguard Worker   // tasks being added to the back of the deque.
965*6777b538SAndroid Build Coastguard Worker   while (!tasks_pending_for_key->second.empty()) {
966*6777b538SAndroid Build Coastguard Worker     base::OnceClosure task = std::move(tasks_pending_for_key->second.front());
967*6777b538SAndroid Build Coastguard Worker     tasks_pending_for_key->second.pop_front();
968*6777b538SAndroid Build Coastguard Worker     std::move(task).Run();
969*6777b538SAndroid Build Coastguard Worker   }
970*6777b538SAndroid Build Coastguard Worker 
971*6777b538SAndroid Build Coastguard Worker   tasks_pending_for_key_.erase(tasks_pending_for_key);
972*6777b538SAndroid Build Coastguard Worker 
973*6777b538SAndroid Build Coastguard Worker   // This has to be done last, in case running a task queues a new task for the
974*6777b538SAndroid Build Coastguard Worker   // key, to ensure tasks are run in the correct order.
975*6777b538SAndroid Build Coastguard Worker   keys_loaded_.insert(key);
976*6777b538SAndroid Build Coastguard Worker }
977*6777b538SAndroid Build Coastguard Worker 
StoreLoadedCookies(std::vector<std::unique_ptr<CanonicalCookie>> cookies)978*6777b538SAndroid Build Coastguard Worker void CookieMonster::StoreLoadedCookies(
979*6777b538SAndroid Build Coastguard Worker     std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
980*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
981*6777b538SAndroid Build Coastguard Worker 
982*6777b538SAndroid Build Coastguard Worker   // Even if a key is expired, insert it so it can be garbage collected,
983*6777b538SAndroid Build Coastguard Worker   // removed, and sync'd.
984*6777b538SAndroid Build Coastguard Worker   CookieItVector cookies_with_control_chars;
985*6777b538SAndroid Build Coastguard Worker   std::vector<PartitionedCookieMapIterators>
986*6777b538SAndroid Build Coastguard Worker       partitioned_cookies_with_control_chars;
987*6777b538SAndroid Build Coastguard Worker 
988*6777b538SAndroid Build Coastguard Worker   for (auto& cookie : cookies) {
989*6777b538SAndroid Build Coastguard Worker     CanonicalCookie* cookie_ptr = cookie.get();
990*6777b538SAndroid Build Coastguard Worker     CookieAccessResult access_result;
991*6777b538SAndroid Build Coastguard Worker     access_result.access_semantics = CookieAccessSemantics::UNKNOWN;
992*6777b538SAndroid Build Coastguard Worker 
993*6777b538SAndroid Build Coastguard Worker     if (cookie_ptr->IsPartitioned()) {
994*6777b538SAndroid Build Coastguard Worker       auto inserted = InternalInsertPartitionedCookie(
995*6777b538SAndroid Build Coastguard Worker           GetKey(cookie_ptr->Domain()), std::move(cookie),
996*6777b538SAndroid Build Coastguard Worker           false /* sync_to_store */, access_result,
997*6777b538SAndroid Build Coastguard Worker           false /* dispatch_change */);
998*6777b538SAndroid Build Coastguard Worker       if (ContainsControlCharacter(cookie_ptr->Name()) ||
999*6777b538SAndroid Build Coastguard Worker           ContainsControlCharacter(cookie_ptr->Value())) {
1000*6777b538SAndroid Build Coastguard Worker         partitioned_cookies_with_control_chars.push_back(inserted);
1001*6777b538SAndroid Build Coastguard Worker       }
1002*6777b538SAndroid Build Coastguard Worker     } else {
1003*6777b538SAndroid Build Coastguard Worker       auto inserted =
1004*6777b538SAndroid Build Coastguard Worker           InternalInsertCookie(GetKey(cookie_ptr->Domain()), std::move(cookie),
1005*6777b538SAndroid Build Coastguard Worker                                false /* sync_to_store */, access_result,
1006*6777b538SAndroid Build Coastguard Worker                                false /* dispatch_change */);
1007*6777b538SAndroid Build Coastguard Worker 
1008*6777b538SAndroid Build Coastguard Worker       if (ContainsControlCharacter(cookie_ptr->Name()) ||
1009*6777b538SAndroid Build Coastguard Worker           ContainsControlCharacter(cookie_ptr->Value())) {
1010*6777b538SAndroid Build Coastguard Worker         cookies_with_control_chars.push_back(inserted);
1011*6777b538SAndroid Build Coastguard Worker       }
1012*6777b538SAndroid Build Coastguard Worker     }
1013*6777b538SAndroid Build Coastguard Worker 
1014*6777b538SAndroid Build Coastguard Worker     const Time cookie_access_time(cookie_ptr->LastAccessDate());
1015*6777b538SAndroid Build Coastguard Worker     if (earliest_access_time_.is_null() ||
1016*6777b538SAndroid Build Coastguard Worker         cookie_access_time < earliest_access_time_) {
1017*6777b538SAndroid Build Coastguard Worker       earliest_access_time_ = cookie_access_time;
1018*6777b538SAndroid Build Coastguard Worker     }
1019*6777b538SAndroid Build Coastguard Worker   }
1020*6777b538SAndroid Build Coastguard Worker 
1021*6777b538SAndroid Build Coastguard Worker   // Any cookies that contain control characters that we have loaded from the
1022*6777b538SAndroid Build Coastguard Worker   // persistent store should be deleted. See http://crbug.com/238041.
1023*6777b538SAndroid Build Coastguard Worker   for (auto it = cookies_with_control_chars.begin();
1024*6777b538SAndroid Build Coastguard Worker        it != cookies_with_control_chars.end();) {
1025*6777b538SAndroid Build Coastguard Worker     auto curit = it;
1026*6777b538SAndroid Build Coastguard Worker     ++it;
1027*6777b538SAndroid Build Coastguard Worker     InternalDeleteCookie(*curit, true, DELETE_COOKIE_CONTROL_CHAR);
1028*6777b538SAndroid Build Coastguard Worker   }
1029*6777b538SAndroid Build Coastguard Worker   for (auto it = partitioned_cookies_with_control_chars.begin();
1030*6777b538SAndroid Build Coastguard Worker        it != partitioned_cookies_with_control_chars.end();) {
1031*6777b538SAndroid Build Coastguard Worker     // InternalDeletePartitionedCookie may invalidate the current iterator, so
1032*6777b538SAndroid Build Coastguard Worker     // we increment the iterator in the loop before calling the function.
1033*6777b538SAndroid Build Coastguard Worker     auto curit = it;
1034*6777b538SAndroid Build Coastguard Worker     ++it;
1035*6777b538SAndroid Build Coastguard Worker     InternalDeletePartitionedCookie(curit->first, curit->second, true,
1036*6777b538SAndroid Build Coastguard Worker                                     DELETE_COOKIE_CONTROL_CHAR);
1037*6777b538SAndroid Build Coastguard Worker   }
1038*6777b538SAndroid Build Coastguard Worker 
1039*6777b538SAndroid Build Coastguard Worker   // After importing cookies from the PersistentCookieStore, verify that
1040*6777b538SAndroid Build Coastguard Worker   // none of our other constraints are violated.
1041*6777b538SAndroid Build Coastguard Worker   // In particular, the backing store might have given us duplicate cookies.
1042*6777b538SAndroid Build Coastguard Worker 
1043*6777b538SAndroid Build Coastguard Worker   // This method could be called multiple times due to priority loading, thus
1044*6777b538SAndroid Build Coastguard Worker   // cookies loaded in previous runs will be validated again, but this is OK
1045*6777b538SAndroid Build Coastguard Worker   // since they are expected to be much fewer than total DB.
1046*6777b538SAndroid Build Coastguard Worker   EnsureCookiesMapIsValid();
1047*6777b538SAndroid Build Coastguard Worker }
1048*6777b538SAndroid Build Coastguard Worker 
InvokeQueue()1049*6777b538SAndroid Build Coastguard Worker void CookieMonster::InvokeQueue() {
1050*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1051*6777b538SAndroid Build Coastguard Worker 
1052*6777b538SAndroid Build Coastguard Worker   // Move all per-key tasks into the global queue, if there are any.  This is
1053*6777b538SAndroid Build Coastguard Worker   // protection about a race where the store learns about all cookies loading
1054*6777b538SAndroid Build Coastguard Worker   // before it learned about the cookies for a key loading.
1055*6777b538SAndroid Build Coastguard Worker 
1056*6777b538SAndroid Build Coastguard Worker   // Needed to prevent any recursively queued tasks from going back into the
1057*6777b538SAndroid Build Coastguard Worker   // per-key queues.
1058*6777b538SAndroid Build Coastguard Worker   seen_global_task_ = true;
1059*6777b538SAndroid Build Coastguard Worker   for (auto& tasks_for_key : tasks_pending_for_key_) {
1060*6777b538SAndroid Build Coastguard Worker     tasks_pending_.insert(tasks_pending_.begin(),
1061*6777b538SAndroid Build Coastguard Worker                           std::make_move_iterator(tasks_for_key.second.begin()),
1062*6777b538SAndroid Build Coastguard Worker                           std::make_move_iterator(tasks_for_key.second.end()));
1063*6777b538SAndroid Build Coastguard Worker   }
1064*6777b538SAndroid Build Coastguard Worker   tasks_pending_for_key_.clear();
1065*6777b538SAndroid Build Coastguard Worker 
1066*6777b538SAndroid Build Coastguard Worker   while (!tasks_pending_.empty()) {
1067*6777b538SAndroid Build Coastguard Worker     base::OnceClosure request_task = std::move(tasks_pending_.front());
1068*6777b538SAndroid Build Coastguard Worker     tasks_pending_.pop_front();
1069*6777b538SAndroid Build Coastguard Worker     std::move(request_task).Run();
1070*6777b538SAndroid Build Coastguard Worker   }
1071*6777b538SAndroid Build Coastguard Worker 
1072*6777b538SAndroid Build Coastguard Worker   DCHECK(tasks_pending_for_key_.empty());
1073*6777b538SAndroid Build Coastguard Worker 
1074*6777b538SAndroid Build Coastguard Worker   finished_fetching_all_cookies_ = true;
1075*6777b538SAndroid Build Coastguard Worker   keys_loaded_.clear();
1076*6777b538SAndroid Build Coastguard Worker }
1077*6777b538SAndroid Build Coastguard Worker 
EnsureCookiesMapIsValid()1078*6777b538SAndroid Build Coastguard Worker void CookieMonster::EnsureCookiesMapIsValid() {
1079*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1080*6777b538SAndroid Build Coastguard Worker 
1081*6777b538SAndroid Build Coastguard Worker   // Iterate through all the of the cookies, grouped by host.
1082*6777b538SAndroid Build Coastguard Worker   for (auto next = cookies_.begin(); next != cookies_.end();) {
1083*6777b538SAndroid Build Coastguard Worker     auto cur_range_begin = next;
1084*6777b538SAndroid Build Coastguard Worker     const std::string key = cur_range_begin->first;  // Keep a copy.
1085*6777b538SAndroid Build Coastguard Worker     auto cur_range_end = cookies_.upper_bound(key);
1086*6777b538SAndroid Build Coastguard Worker     next = cur_range_end;
1087*6777b538SAndroid Build Coastguard Worker 
1088*6777b538SAndroid Build Coastguard Worker     // Ensure no equivalent cookies for this host.
1089*6777b538SAndroid Build Coastguard Worker     TrimDuplicateCookiesForKey(key, cur_range_begin, cur_range_end,
1090*6777b538SAndroid Build Coastguard Worker                                std::nullopt);
1091*6777b538SAndroid Build Coastguard Worker   }
1092*6777b538SAndroid Build Coastguard Worker 
1093*6777b538SAndroid Build Coastguard Worker   for (auto cookie_partition_it = partitioned_cookies_.begin();
1094*6777b538SAndroid Build Coastguard Worker        cookie_partition_it != partitioned_cookies_.end();) {
1095*6777b538SAndroid Build Coastguard Worker     auto cur_cookie_partition_it = cookie_partition_it;
1096*6777b538SAndroid Build Coastguard Worker     ++cookie_partition_it;
1097*6777b538SAndroid Build Coastguard Worker 
1098*6777b538SAndroid Build Coastguard Worker     // Iterate through the cookies in this partition, grouped by host.
1099*6777b538SAndroid Build Coastguard Worker     CookieMap* cookie_partition = cur_cookie_partition_it->second.get();
1100*6777b538SAndroid Build Coastguard Worker     auto prev_range_end = cookie_partition->begin();
1101*6777b538SAndroid Build Coastguard Worker     while (prev_range_end != cookie_partition->end()) {
1102*6777b538SAndroid Build Coastguard Worker       auto cur_range_begin = prev_range_end;
1103*6777b538SAndroid Build Coastguard Worker       const std::string key = cur_range_begin->first;  // Keep a copy.
1104*6777b538SAndroid Build Coastguard Worker       auto cur_range_end = cookie_partition->upper_bound(key);
1105*6777b538SAndroid Build Coastguard Worker       prev_range_end = cur_range_end;
1106*6777b538SAndroid Build Coastguard Worker 
1107*6777b538SAndroid Build Coastguard Worker       // Ensure no equivalent cookies for this host and cookie partition key.
1108*6777b538SAndroid Build Coastguard Worker       TrimDuplicateCookiesForKey(key, cur_range_begin, cur_range_end,
1109*6777b538SAndroid Build Coastguard Worker                                  std::make_optional(cur_cookie_partition_it));
1110*6777b538SAndroid Build Coastguard Worker     }
1111*6777b538SAndroid Build Coastguard Worker   }
1112*6777b538SAndroid Build Coastguard Worker }
1113*6777b538SAndroid Build Coastguard Worker 
1114*6777b538SAndroid Build Coastguard Worker // Our strategy to find duplicates is:
1115*6777b538SAndroid Build Coastguard Worker // (1) Build a map from cookie unique key to
1116*6777b538SAndroid Build Coastguard Worker //     {list of cookies with this signature, sorted by creation time}.
1117*6777b538SAndroid Build Coastguard Worker // (2) For each list with more than 1 entry, keep the cookie having the
1118*6777b538SAndroid Build Coastguard Worker //     most recent creation time, and delete the others.
1119*6777b538SAndroid Build Coastguard Worker //
TrimDuplicateCookiesForKey(const std::string & key,CookieMap::iterator begin,CookieMap::iterator end,std::optional<PartitionedCookieMap::iterator> cookie_partition_it)1120*6777b538SAndroid Build Coastguard Worker void CookieMonster::TrimDuplicateCookiesForKey(
1121*6777b538SAndroid Build Coastguard Worker     const std::string& key,
1122*6777b538SAndroid Build Coastguard Worker     CookieMap::iterator begin,
1123*6777b538SAndroid Build Coastguard Worker     CookieMap::iterator end,
1124*6777b538SAndroid Build Coastguard Worker     std::optional<PartitionedCookieMap::iterator> cookie_partition_it) {
1125*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1126*6777b538SAndroid Build Coastguard Worker 
1127*6777b538SAndroid Build Coastguard Worker   // Set of cookies ordered by creation time.
1128*6777b538SAndroid Build Coastguard Worker   typedef std::multiset<CookieMap::iterator, OrderByCreationTimeDesc> CookieSet;
1129*6777b538SAndroid Build Coastguard Worker 
1130*6777b538SAndroid Build Coastguard Worker   // Helper map we populate to find the duplicates.
1131*6777b538SAndroid Build Coastguard Worker   typedef std::map<CanonicalCookie::UniqueCookieKey, CookieSet> EquivalenceMap;
1132*6777b538SAndroid Build Coastguard Worker   typedef std::map<CanonicalCookie::UniqueDomainCookieKey, CookieSet>
1133*6777b538SAndroid Build Coastguard Worker       DomainEquivalenceMap;
1134*6777b538SAndroid Build Coastguard Worker   EquivalenceMap equivalent_cookies;
1135*6777b538SAndroid Build Coastguard Worker   DomainEquivalenceMap equivalent_domain_cookies;
1136*6777b538SAndroid Build Coastguard Worker 
1137*6777b538SAndroid Build Coastguard Worker   // The number of duplicate cookies that have been found.
1138*6777b538SAndroid Build Coastguard Worker   int num_duplicates = 0;
1139*6777b538SAndroid Build Coastguard Worker   int num_domain_duplicates = 0;
1140*6777b538SAndroid Build Coastguard Worker 
1141*6777b538SAndroid Build Coastguard Worker   // Iterate through all of the cookies in our range, and insert them into
1142*6777b538SAndroid Build Coastguard Worker   // the equivalence map.
1143*6777b538SAndroid Build Coastguard Worker   for (auto it = begin; it != end; ++it) {
1144*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(key, it->first);
1145*6777b538SAndroid Build Coastguard Worker     CanonicalCookie* cookie = it->second.get();
1146*6777b538SAndroid Build Coastguard Worker 
1147*6777b538SAndroid Build Coastguard Worker     if (cookie->IsHostCookie()) {
1148*6777b538SAndroid Build Coastguard Worker       CanonicalCookie::UniqueCookieKey signature(cookie->UniqueKey());
1149*6777b538SAndroid Build Coastguard Worker       CookieSet& set = equivalent_cookies[signature];
1150*6777b538SAndroid Build Coastguard Worker 
1151*6777b538SAndroid Build Coastguard Worker       // We found a duplicate!
1152*6777b538SAndroid Build Coastguard Worker       if (!set.empty()) {
1153*6777b538SAndroid Build Coastguard Worker         num_duplicates++;
1154*6777b538SAndroid Build Coastguard Worker       }
1155*6777b538SAndroid Build Coastguard Worker 
1156*6777b538SAndroid Build Coastguard Worker       // We save the iterator into |cookies_| rather than the actual cookie
1157*6777b538SAndroid Build Coastguard Worker       // pointer, since we may need to delete it later.
1158*6777b538SAndroid Build Coastguard Worker       set.insert(it);
1159*6777b538SAndroid Build Coastguard Worker     }
1160*6777b538SAndroid Build Coastguard Worker     // Is a domain cookie.
1161*6777b538SAndroid Build Coastguard Worker     else {
1162*6777b538SAndroid Build Coastguard Worker       CanonicalCookie::UniqueDomainCookieKey signature(
1163*6777b538SAndroid Build Coastguard Worker           cookie->UniqueDomainKey());
1164*6777b538SAndroid Build Coastguard Worker       CookieSet& domain_set = equivalent_domain_cookies[signature];
1165*6777b538SAndroid Build Coastguard Worker 
1166*6777b538SAndroid Build Coastguard Worker       // We found a duplicate!
1167*6777b538SAndroid Build Coastguard Worker       if (!domain_set.empty()) {
1168*6777b538SAndroid Build Coastguard Worker         num_domain_duplicates++;
1169*6777b538SAndroid Build Coastguard Worker       }
1170*6777b538SAndroid Build Coastguard Worker 
1171*6777b538SAndroid Build Coastguard Worker       // We save the iterator into |cookies_| rather than the actual cookie
1172*6777b538SAndroid Build Coastguard Worker       // pointer, since we may need to delete it later.
1173*6777b538SAndroid Build Coastguard Worker       domain_set.insert(it);
1174*6777b538SAndroid Build Coastguard Worker     }
1175*6777b538SAndroid Build Coastguard Worker   }
1176*6777b538SAndroid Build Coastguard Worker 
1177*6777b538SAndroid Build Coastguard Worker   // If there were no duplicates, we are done!
1178*6777b538SAndroid Build Coastguard Worker   if (num_duplicates == 0 && num_domain_duplicates == 0) {
1179*6777b538SAndroid Build Coastguard Worker     return;
1180*6777b538SAndroid Build Coastguard Worker   }
1181*6777b538SAndroid Build Coastguard Worker 
1182*6777b538SAndroid Build Coastguard Worker   // Make sure we find everything below that we did above.
1183*6777b538SAndroid Build Coastguard Worker   int num_duplicates_found = 0;
1184*6777b538SAndroid Build Coastguard Worker 
1185*6777b538SAndroid Build Coastguard Worker   // Otherwise, delete all the duplicate host cookies, both from our in-memory
1186*6777b538SAndroid Build Coastguard Worker   // store and from the backing store.
1187*6777b538SAndroid Build Coastguard Worker   for (std::pair<const CanonicalCookie::UniqueCookieKey, CookieSet>&
1188*6777b538SAndroid Build Coastguard Worker            equivalent_cookie : equivalent_cookies) {
1189*6777b538SAndroid Build Coastguard Worker     const CanonicalCookie::UniqueCookieKey& signature = equivalent_cookie.first;
1190*6777b538SAndroid Build Coastguard Worker     CookieSet& dupes = equivalent_cookie.second;
1191*6777b538SAndroid Build Coastguard Worker 
1192*6777b538SAndroid Build Coastguard Worker     if (dupes.size() <= 1) {
1193*6777b538SAndroid Build Coastguard Worker       continue;  // This cookiename/path has no duplicates.
1194*6777b538SAndroid Build Coastguard Worker     }
1195*6777b538SAndroid Build Coastguard Worker 
1196*6777b538SAndroid Build Coastguard Worker     num_duplicates_found += dupes.size() - 1;
1197*6777b538SAndroid Build Coastguard Worker 
1198*6777b538SAndroid Build Coastguard Worker     // Since |dupes| is sorted by creation time (descending), the first cookie
1199*6777b538SAndroid Build Coastguard Worker     // is the most recent one (or tied for it), so we will keep it. The rest are
1200*6777b538SAndroid Build Coastguard Worker     // duplicates.
1201*6777b538SAndroid Build Coastguard Worker     dupes.erase(dupes.begin());
1202*6777b538SAndroid Build Coastguard Worker 
1203*6777b538SAndroid Build Coastguard Worker     // TODO(crbug.com/1225444) Include cookie partition key in this log
1204*6777b538SAndroid Build Coastguard Worker     // statement as well if needed.
1205*6777b538SAndroid Build Coastguard Worker     // TODO(crbug.com/1170548): Include source scheme and source port.
1206*6777b538SAndroid Build Coastguard Worker     LOG(ERROR) << base::StringPrintf(
1207*6777b538SAndroid Build Coastguard Worker         "Found %d duplicate cookies for key='%s', "
1208*6777b538SAndroid Build Coastguard Worker         "with {name='%s', domain='%s', path='%s'}",
1209*6777b538SAndroid Build Coastguard Worker         static_cast<int>(dupes.size()), key.c_str(),
1210*6777b538SAndroid Build Coastguard Worker         std::get<1>(signature).c_str(), std::get<2>(signature).c_str(),
1211*6777b538SAndroid Build Coastguard Worker         std::get<3>(signature).c_str());
1212*6777b538SAndroid Build Coastguard Worker 
1213*6777b538SAndroid Build Coastguard Worker     // Remove all the cookies identified by |dupes|. It is valid to delete our
1214*6777b538SAndroid Build Coastguard Worker     // list of iterators one at a time, since |cookies_| is a multimap (they
1215*6777b538SAndroid Build Coastguard Worker     // don't invalidate existing iterators following deletion).
1216*6777b538SAndroid Build Coastguard Worker     for (const CookieMap::iterator& dupe : dupes) {
1217*6777b538SAndroid Build Coastguard Worker       if (cookie_partition_it) {
1218*6777b538SAndroid Build Coastguard Worker         InternalDeletePartitionedCookie(
1219*6777b538SAndroid Build Coastguard Worker             cookie_partition_it.value(), dupe, true,
1220*6777b538SAndroid Build Coastguard Worker             DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE);
1221*6777b538SAndroid Build Coastguard Worker       } else {
1222*6777b538SAndroid Build Coastguard Worker         InternalDeleteCookie(dupe, true,
1223*6777b538SAndroid Build Coastguard Worker                              DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE);
1224*6777b538SAndroid Build Coastguard Worker       }
1225*6777b538SAndroid Build Coastguard Worker     }
1226*6777b538SAndroid Build Coastguard Worker   }
1227*6777b538SAndroid Build Coastguard Worker   CHECK_EQ(num_duplicates, num_duplicates_found);
1228*6777b538SAndroid Build Coastguard Worker 
1229*6777b538SAndroid Build Coastguard Worker   // Do the same again for domain cookies.
1230*6777b538SAndroid Build Coastguard Worker 
1231*6777b538SAndroid Build Coastguard Worker   if (num_domain_duplicates == 0) {
1232*6777b538SAndroid Build Coastguard Worker     return;
1233*6777b538SAndroid Build Coastguard Worker   }
1234*6777b538SAndroid Build Coastguard Worker 
1235*6777b538SAndroid Build Coastguard Worker   int num_domain_duplicates_found = 0;
1236*6777b538SAndroid Build Coastguard Worker 
1237*6777b538SAndroid Build Coastguard Worker   for (std::pair<const CanonicalCookie::UniqueDomainCookieKey, CookieSet>&
1238*6777b538SAndroid Build Coastguard Worker            equivalent_domain_cookie : equivalent_domain_cookies) {
1239*6777b538SAndroid Build Coastguard Worker     const CanonicalCookie::UniqueDomainCookieKey& signature =
1240*6777b538SAndroid Build Coastguard Worker         equivalent_domain_cookie.first;
1241*6777b538SAndroid Build Coastguard Worker     CookieSet& dupes = equivalent_domain_cookie.second;
1242*6777b538SAndroid Build Coastguard Worker 
1243*6777b538SAndroid Build Coastguard Worker     if (dupes.size() <= 1) {
1244*6777b538SAndroid Build Coastguard Worker       continue;
1245*6777b538SAndroid Build Coastguard Worker     }
1246*6777b538SAndroid Build Coastguard Worker 
1247*6777b538SAndroid Build Coastguard Worker     num_domain_duplicates_found += dupes.size() - 1;
1248*6777b538SAndroid Build Coastguard Worker 
1249*6777b538SAndroid Build Coastguard Worker     // Since |dupes| is sorted by creation time (descending), the first cookie
1250*6777b538SAndroid Build Coastguard Worker     // is the most recent one (or tied for it), so we will keep it. The rest are
1251*6777b538SAndroid Build Coastguard Worker     // duplicates.
1252*6777b538SAndroid Build Coastguard Worker     dupes.erase(dupes.begin());
1253*6777b538SAndroid Build Coastguard Worker 
1254*6777b538SAndroid Build Coastguard Worker     // TODO(crbug.com/1225444) Include cookie partition key in this log
1255*6777b538SAndroid Build Coastguard Worker     // statement as well if needed.
1256*6777b538SAndroid Build Coastguard Worker     // TODO(crbug.com/1170548): Include source scheme and source port.
1257*6777b538SAndroid Build Coastguard Worker     LOG(ERROR) << base::StringPrintf(
1258*6777b538SAndroid Build Coastguard Worker         "Found %d duplicate domain cookies for key='%s', "
1259*6777b538SAndroid Build Coastguard Worker         "with {name='%s', domain='%s', path='%s'}",
1260*6777b538SAndroid Build Coastguard Worker         static_cast<int>(dupes.size()), key.c_str(),
1261*6777b538SAndroid Build Coastguard Worker         std::get<1>(signature).c_str(), std::get<2>(signature).c_str(),
1262*6777b538SAndroid Build Coastguard Worker         std::get<3>(signature).c_str());
1263*6777b538SAndroid Build Coastguard Worker 
1264*6777b538SAndroid Build Coastguard Worker     // Remove all the cookies identified by |dupes|. It is valid to delete our
1265*6777b538SAndroid Build Coastguard Worker     // list of iterators one at a time, since |cookies_| is a multimap (they
1266*6777b538SAndroid Build Coastguard Worker     // don't invalidate existing iterators following deletion).
1267*6777b538SAndroid Build Coastguard Worker     for (const CookieMap::iterator& dupe : dupes) {
1268*6777b538SAndroid Build Coastguard Worker       if (cookie_partition_it) {
1269*6777b538SAndroid Build Coastguard Worker         InternalDeletePartitionedCookie(
1270*6777b538SAndroid Build Coastguard Worker             cookie_partition_it.value(), dupe, true,
1271*6777b538SAndroid Build Coastguard Worker             DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE);
1272*6777b538SAndroid Build Coastguard Worker       } else {
1273*6777b538SAndroid Build Coastguard Worker         InternalDeleteCookie(dupe, true,
1274*6777b538SAndroid Build Coastguard Worker                              DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE);
1275*6777b538SAndroid Build Coastguard Worker       }
1276*6777b538SAndroid Build Coastguard Worker     }
1277*6777b538SAndroid Build Coastguard Worker   }
1278*6777b538SAndroid Build Coastguard Worker 
1279*6777b538SAndroid Build Coastguard Worker   CHECK_EQ(num_domain_duplicates, num_domain_duplicates_found);
1280*6777b538SAndroid Build Coastguard Worker }
1281*6777b538SAndroid Build Coastguard Worker 
1282*6777b538SAndroid Build Coastguard Worker std::vector<CanonicalCookie*>
FindCookiesForRegistryControlledHost(const GURL & url,CookieMap * cookie_map,CookieMonster::PartitionedCookieMap::iterator * partition_it)1283*6777b538SAndroid Build Coastguard Worker CookieMonster::FindCookiesForRegistryControlledHost(
1284*6777b538SAndroid Build Coastguard Worker     const GURL& url,
1285*6777b538SAndroid Build Coastguard Worker     CookieMap* cookie_map,
1286*6777b538SAndroid Build Coastguard Worker     CookieMonster::PartitionedCookieMap::iterator* partition_it) {
1287*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1288*6777b538SAndroid Build Coastguard Worker 
1289*6777b538SAndroid Build Coastguard Worker   if (!cookie_map)
1290*6777b538SAndroid Build Coastguard Worker     cookie_map = &cookies_;
1291*6777b538SAndroid Build Coastguard Worker 
1292*6777b538SAndroid Build Coastguard Worker   Time current_time = Time::Now();
1293*6777b538SAndroid Build Coastguard Worker 
1294*6777b538SAndroid Build Coastguard Worker   // Retrieve all cookies for a given key
1295*6777b538SAndroid Build Coastguard Worker   const std::string key(GetKey(url.host_piece()));
1296*6777b538SAndroid Build Coastguard Worker 
1297*6777b538SAndroid Build Coastguard Worker   std::vector<CanonicalCookie*> cookies;
1298*6777b538SAndroid Build Coastguard Worker   for (CookieMapItPair its = cookie_map->equal_range(key);
1299*6777b538SAndroid Build Coastguard Worker        its.first != its.second;) {
1300*6777b538SAndroid Build Coastguard Worker     auto curit = its.first;
1301*6777b538SAndroid Build Coastguard Worker     CanonicalCookie* cc = curit->second.get();
1302*6777b538SAndroid Build Coastguard Worker     ++its.first;
1303*6777b538SAndroid Build Coastguard Worker 
1304*6777b538SAndroid Build Coastguard Worker     // If the cookie is expired, delete it.
1305*6777b538SAndroid Build Coastguard Worker     if (cc->IsExpired(current_time)) {
1306*6777b538SAndroid Build Coastguard Worker       if (cc->IsPartitioned()) {
1307*6777b538SAndroid Build Coastguard Worker         DCHECK(partition_it);
1308*6777b538SAndroid Build Coastguard Worker         DCHECK_EQ((*partition_it)->second.get(), cookie_map);
1309*6777b538SAndroid Build Coastguard Worker         InternalDeletePartitionedCookie(*partition_it, curit, true,
1310*6777b538SAndroid Build Coastguard Worker                                         DELETE_COOKIE_EXPIRED);
1311*6777b538SAndroid Build Coastguard Worker       } else {
1312*6777b538SAndroid Build Coastguard Worker         InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
1313*6777b538SAndroid Build Coastguard Worker       }
1314*6777b538SAndroid Build Coastguard Worker       continue;
1315*6777b538SAndroid Build Coastguard Worker     }
1316*6777b538SAndroid Build Coastguard Worker     cookies.push_back(cc);
1317*6777b538SAndroid Build Coastguard Worker   }
1318*6777b538SAndroid Build Coastguard Worker   return cookies;
1319*6777b538SAndroid Build Coastguard Worker }
1320*6777b538SAndroid Build Coastguard Worker 
1321*6777b538SAndroid Build Coastguard Worker std::vector<CanonicalCookie*>
FindPartitionedCookiesForRegistryControlledHost(const CookiePartitionKey & cookie_partition_key,const GURL & url)1322*6777b538SAndroid Build Coastguard Worker CookieMonster::FindPartitionedCookiesForRegistryControlledHost(
1323*6777b538SAndroid Build Coastguard Worker     const CookiePartitionKey& cookie_partition_key,
1324*6777b538SAndroid Build Coastguard Worker     const GURL& url) {
1325*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1326*6777b538SAndroid Build Coastguard Worker 
1327*6777b538SAndroid Build Coastguard Worker   PartitionedCookieMap::iterator it =
1328*6777b538SAndroid Build Coastguard Worker       partitioned_cookies_.find(cookie_partition_key);
1329*6777b538SAndroid Build Coastguard Worker   if (it == partitioned_cookies_.end())
1330*6777b538SAndroid Build Coastguard Worker     return std::vector<CanonicalCookie*>();
1331*6777b538SAndroid Build Coastguard Worker 
1332*6777b538SAndroid Build Coastguard Worker   return FindCookiesForRegistryControlledHost(url, it->second.get(), &it);
1333*6777b538SAndroid Build Coastguard Worker }
1334*6777b538SAndroid Build Coastguard Worker 
FilterCookiesWithOptions(const GURL url,const CookieOptions options,std::vector<CanonicalCookie * > * cookie_ptrs,CookieAccessResultList * included_cookies,CookieAccessResultList * excluded_cookies)1335*6777b538SAndroid Build Coastguard Worker void CookieMonster::FilterCookiesWithOptions(
1336*6777b538SAndroid Build Coastguard Worker     const GURL url,
1337*6777b538SAndroid Build Coastguard Worker     const CookieOptions options,
1338*6777b538SAndroid Build Coastguard Worker     std::vector<CanonicalCookie*>* cookie_ptrs,
1339*6777b538SAndroid Build Coastguard Worker     CookieAccessResultList* included_cookies,
1340*6777b538SAndroid Build Coastguard Worker     CookieAccessResultList* excluded_cookies) {
1341*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1342*6777b538SAndroid Build Coastguard Worker 
1343*6777b538SAndroid Build Coastguard Worker   // Probe to save statistics relatively frequently.  We do it here rather
1344*6777b538SAndroid Build Coastguard Worker   // than in the set path as many websites won't set cookies, and we
1345*6777b538SAndroid Build Coastguard Worker   // want to collect statistics whenever the browser's being used.
1346*6777b538SAndroid Build Coastguard Worker   Time current_time = Time::Now();
1347*6777b538SAndroid Build Coastguard Worker   RecordPeriodicStats(current_time);
1348*6777b538SAndroid Build Coastguard Worker 
1349*6777b538SAndroid Build Coastguard Worker   bool delegate_treats_url_as_trustworthy =
1350*6777b538SAndroid Build Coastguard Worker       cookie_access_delegate() &&
1351*6777b538SAndroid Build Coastguard Worker       cookie_access_delegate()->ShouldTreatUrlAsTrustworthy(url);
1352*6777b538SAndroid Build Coastguard Worker 
1353*6777b538SAndroid Build Coastguard Worker   std::vector<std::pair<CanonicalCookie*, CookieAccessResult>>
1354*6777b538SAndroid Build Coastguard Worker       cookies_and_access_results;
1355*6777b538SAndroid Build Coastguard Worker   cookies_and_access_results.reserve(cookie_ptrs->size());
1356*6777b538SAndroid Build Coastguard Worker   std::set<std::string> origin_cookie_names;
1357*6777b538SAndroid Build Coastguard Worker 
1358*6777b538SAndroid Build Coastguard Worker   for (CanonicalCookie* cookie_ptr : *cookie_ptrs) {
1359*6777b538SAndroid Build Coastguard Worker     // Filter out cookies that should not be included for a request to the
1360*6777b538SAndroid Build Coastguard Worker     // given |url|. HTTP only cookies are filtered depending on the passed
1361*6777b538SAndroid Build Coastguard Worker     // cookie |options|.
1362*6777b538SAndroid Build Coastguard Worker     CookieAccessResult access_result = cookie_ptr->IncludeForRequestURL(
1363*6777b538SAndroid Build Coastguard Worker         url, options,
1364*6777b538SAndroid Build Coastguard Worker         CookieAccessParams{GetAccessSemanticsForCookie(*cookie_ptr),
1365*6777b538SAndroid Build Coastguard Worker                            delegate_treats_url_as_trustworthy});
1366*6777b538SAndroid Build Coastguard Worker     cookies_and_access_results.emplace_back(cookie_ptr, access_result);
1367*6777b538SAndroid Build Coastguard Worker 
1368*6777b538SAndroid Build Coastguard Worker     // Record the names of all origin cookies that would be included if both
1369*6777b538SAndroid Build Coastguard Worker     // kEnablePortBoundCookies and kEnableSchemeBoundCookies are enabled.
1370*6777b538SAndroid Build Coastguard Worker     //
1371*6777b538SAndroid Build Coastguard Worker     // We DO want to record origin cookies that are being excluded for path
1372*6777b538SAndroid Build Coastguard Worker     // reasons, so we'll remove any potential path exclusions.
1373*6777b538SAndroid Build Coastguard Worker     CookieInclusionStatus status_copy = access_result.status;
1374*6777b538SAndroid Build Coastguard Worker     status_copy.RemoveExclusionReason(
1375*6777b538SAndroid Build Coastguard Worker         CookieInclusionStatus::EXCLUDE_NOT_ON_PATH);
1376*6777b538SAndroid Build Coastguard Worker 
1377*6777b538SAndroid Build Coastguard Worker     bool exclusion_or_warning =
1378*6777b538SAndroid Build Coastguard Worker         !status_copy.IsInclude() ||
1379*6777b538SAndroid Build Coastguard Worker         status_copy.HasWarningReason(
1380*6777b538SAndroid Build Coastguard Worker             CookieInclusionStatus::WARN_SCHEME_MISMATCH) ||
1381*6777b538SAndroid Build Coastguard Worker         status_copy.HasWarningReason(CookieInclusionStatus::WARN_PORT_MISMATCH);
1382*6777b538SAndroid Build Coastguard Worker 
1383*6777b538SAndroid Build Coastguard Worker     if (!exclusion_or_warning && cookie_ptr->IsHostCookie()) {
1384*6777b538SAndroid Build Coastguard Worker       origin_cookie_names.insert(cookie_ptr->Name());
1385*6777b538SAndroid Build Coastguard Worker     }
1386*6777b538SAndroid Build Coastguard Worker   }
1387*6777b538SAndroid Build Coastguard Worker 
1388*6777b538SAndroid Build Coastguard Worker   for (auto& cookie_result : cookies_and_access_results) {
1389*6777b538SAndroid Build Coastguard Worker     CanonicalCookie* cookie_ptr = cookie_result.first;
1390*6777b538SAndroid Build Coastguard Worker     CookieAccessResult& access_result = cookie_result.second;
1391*6777b538SAndroid Build Coastguard Worker 
1392*6777b538SAndroid Build Coastguard Worker     // We want to collect these metrics for cookies that would be included
1393*6777b538SAndroid Build Coastguard Worker     // without considering shadowing domain cookies.
1394*6777b538SAndroid Build Coastguard Worker     if (access_result.status.IsInclude()) {
1395*6777b538SAndroid Build Coastguard Worker       int destination_port = url.EffectiveIntPort();
1396*6777b538SAndroid Build Coastguard Worker 
1397*6777b538SAndroid Build Coastguard Worker       if (IsLocalhost(url)) {
1398*6777b538SAndroid Build Coastguard Worker         UMA_HISTOGRAM_ENUMERATION(
1399*6777b538SAndroid Build Coastguard Worker             "Cookie.Port.Read.Localhost",
1400*6777b538SAndroid Build Coastguard Worker             ReducePortRangeForCookieHistogram(destination_port));
1401*6777b538SAndroid Build Coastguard Worker         UMA_HISTOGRAM_ENUMERATION(
1402*6777b538SAndroid Build Coastguard Worker             "Cookie.Port.ReadDiffersFromSet.Localhost",
1403*6777b538SAndroid Build Coastguard Worker             IsCookieSentToSamePortThatSetIt(url, cookie_ptr->SourcePort(),
1404*6777b538SAndroid Build Coastguard Worker                                             cookie_ptr->SourceScheme()));
1405*6777b538SAndroid Build Coastguard Worker       } else {
1406*6777b538SAndroid Build Coastguard Worker         UMA_HISTOGRAM_ENUMERATION(
1407*6777b538SAndroid Build Coastguard Worker             "Cookie.Port.Read.RemoteHost",
1408*6777b538SAndroid Build Coastguard Worker             ReducePortRangeForCookieHistogram(destination_port));
1409*6777b538SAndroid Build Coastguard Worker         UMA_HISTOGRAM_ENUMERATION(
1410*6777b538SAndroid Build Coastguard Worker             "Cookie.Port.ReadDiffersFromSet.RemoteHost",
1411*6777b538SAndroid Build Coastguard Worker             IsCookieSentToSamePortThatSetIt(url, cookie_ptr->SourcePort(),
1412*6777b538SAndroid Build Coastguard Worker                                             cookie_ptr->SourceScheme()));
1413*6777b538SAndroid Build Coastguard Worker       }
1414*6777b538SAndroid Build Coastguard Worker 
1415*6777b538SAndroid Build Coastguard Worker       if (cookie_ptr->IsDomainCookie()) {
1416*6777b538SAndroid Build Coastguard Worker         UMA_HISTOGRAM_ENUMERATION(
1417*6777b538SAndroid Build Coastguard Worker             "Cookie.Port.ReadDiffersFromSet.DomainSet",
1418*6777b538SAndroid Build Coastguard Worker             IsCookieSentToSamePortThatSetIt(url, cookie_ptr->SourcePort(),
1419*6777b538SAndroid Build Coastguard Worker                                             cookie_ptr->SourceScheme()));
1420*6777b538SAndroid Build Coastguard Worker       }
1421*6777b538SAndroid Build Coastguard Worker     }
1422*6777b538SAndroid Build Coastguard Worker 
1423*6777b538SAndroid Build Coastguard Worker     // Filter out any domain `cookie_ptr` which are shadowing origin cookies.
1424*6777b538SAndroid Build Coastguard Worker     // Don't apply domain shadowing exclusion/warning reason if `cookie_ptr` is
1425*6777b538SAndroid Build Coastguard Worker     // already being excluded/warned for scheme matching reasons (Note, domain
1426*6777b538SAndroid Build Coastguard Worker     // cookies match every port so they'll never get excluded/warned for port
1427*6777b538SAndroid Build Coastguard Worker     // reasons).
1428*6777b538SAndroid Build Coastguard Worker     bool scheme_mismatch =
1429*6777b538SAndroid Build Coastguard Worker         access_result.status.HasExclusionReason(
1430*6777b538SAndroid Build Coastguard Worker             CookieInclusionStatus::EXCLUDE_SCHEME_MISMATCH) ||
1431*6777b538SAndroid Build Coastguard Worker         access_result.status.HasWarningReason(
1432*6777b538SAndroid Build Coastguard Worker             CookieInclusionStatus::WARN_SCHEME_MISMATCH);
1433*6777b538SAndroid Build Coastguard Worker 
1434*6777b538SAndroid Build Coastguard Worker     if (cookie_ptr->IsDomainCookie() && !scheme_mismatch &&
1435*6777b538SAndroid Build Coastguard Worker         origin_cookie_names.count(cookie_ptr->Name())) {
1436*6777b538SAndroid Build Coastguard Worker       if (cookie_util::IsSchemeBoundCookiesEnabled()) {
1437*6777b538SAndroid Build Coastguard Worker         access_result.status.AddExclusionReason(
1438*6777b538SAndroid Build Coastguard Worker             CookieInclusionStatus::EXCLUDE_SHADOWING_DOMAIN);
1439*6777b538SAndroid Build Coastguard Worker       } else {
1440*6777b538SAndroid Build Coastguard Worker         access_result.status.AddWarningReason(
1441*6777b538SAndroid Build Coastguard Worker             CookieInclusionStatus::WARN_SHADOWING_DOMAIN);
1442*6777b538SAndroid Build Coastguard Worker       }
1443*6777b538SAndroid Build Coastguard Worker     }
1444*6777b538SAndroid Build Coastguard Worker 
1445*6777b538SAndroid Build Coastguard Worker     if (!access_result.status.IsInclude()) {
1446*6777b538SAndroid Build Coastguard Worker       if (options.return_excluded_cookies()) {
1447*6777b538SAndroid Build Coastguard Worker         excluded_cookies->push_back({*cookie_ptr, access_result});
1448*6777b538SAndroid Build Coastguard Worker       }
1449*6777b538SAndroid Build Coastguard Worker       continue;
1450*6777b538SAndroid Build Coastguard Worker     }
1451*6777b538SAndroid Build Coastguard Worker 
1452*6777b538SAndroid Build Coastguard Worker     if (options.update_access_time()) {
1453*6777b538SAndroid Build Coastguard Worker       InternalUpdateCookieAccessTime(cookie_ptr, current_time);
1454*6777b538SAndroid Build Coastguard Worker     }
1455*6777b538SAndroid Build Coastguard Worker 
1456*6777b538SAndroid Build Coastguard Worker     included_cookies->push_back({*cookie_ptr, access_result});
1457*6777b538SAndroid Build Coastguard Worker   }
1458*6777b538SAndroid Build Coastguard Worker }
1459*6777b538SAndroid Build Coastguard Worker 
MaybeDeleteEquivalentCookieAndUpdateStatus(const std::string & key,const CanonicalCookie & cookie_being_set,bool allowed_to_set_secure_cookie,bool skip_httponly,bool already_expired,base::Time * creation_date_to_inherit,CookieInclusionStatus * status,std::optional<PartitionedCookieMap::iterator> cookie_partition_it)1460*6777b538SAndroid Build Coastguard Worker void CookieMonster::MaybeDeleteEquivalentCookieAndUpdateStatus(
1461*6777b538SAndroid Build Coastguard Worker     const std::string& key,
1462*6777b538SAndroid Build Coastguard Worker     const CanonicalCookie& cookie_being_set,
1463*6777b538SAndroid Build Coastguard Worker     bool allowed_to_set_secure_cookie,
1464*6777b538SAndroid Build Coastguard Worker     bool skip_httponly,
1465*6777b538SAndroid Build Coastguard Worker     bool already_expired,
1466*6777b538SAndroid Build Coastguard Worker     base::Time* creation_date_to_inherit,
1467*6777b538SAndroid Build Coastguard Worker     CookieInclusionStatus* status,
1468*6777b538SAndroid Build Coastguard Worker     std::optional<PartitionedCookieMap::iterator> cookie_partition_it) {
1469*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1470*6777b538SAndroid Build Coastguard Worker   DCHECK(!status->HasExclusionReason(
1471*6777b538SAndroid Build Coastguard Worker       CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE));
1472*6777b538SAndroid Build Coastguard Worker   DCHECK(!status->HasExclusionReason(
1473*6777b538SAndroid Build Coastguard Worker       CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY));
1474*6777b538SAndroid Build Coastguard Worker 
1475*6777b538SAndroid Build Coastguard Worker   CookieMap* cookie_map = &cookies_;
1476*6777b538SAndroid Build Coastguard Worker   if (cookie_partition_it) {
1477*6777b538SAndroid Build Coastguard Worker     cookie_map = cookie_partition_it.value()->second.get();
1478*6777b538SAndroid Build Coastguard Worker   }
1479*6777b538SAndroid Build Coastguard Worker 
1480*6777b538SAndroid Build Coastguard Worker   bool found_equivalent_cookie = false;
1481*6777b538SAndroid Build Coastguard Worker   CookieMap::iterator deletion_candidate_it = cookie_map->end();
1482*6777b538SAndroid Build Coastguard Worker   CanonicalCookie* skipped_secure_cookie = nullptr;
1483*6777b538SAndroid Build Coastguard Worker 
1484*6777b538SAndroid Build Coastguard Worker   // Check every cookie matching this domain key for equivalence.
1485*6777b538SAndroid Build Coastguard Worker   CookieMapItPair range_its = cookie_map->equal_range(key);
1486*6777b538SAndroid Build Coastguard Worker   for (auto cur_it = range_its.first; cur_it != range_its.second; ++cur_it) {
1487*6777b538SAndroid Build Coastguard Worker     CanonicalCookie* cur_existing_cookie = cur_it->second.get();
1488*6777b538SAndroid Build Coastguard Worker 
1489*6777b538SAndroid Build Coastguard Worker     // Evaluate "Leave Secure Cookies Alone":
1490*6777b538SAndroid Build Coastguard Worker     // If the cookie is being set from an insecure source, then if an
1491*6777b538SAndroid Build Coastguard Worker     // "equivalent" Secure cookie already exists, then the cookie should *not*
1492*6777b538SAndroid Build Coastguard Worker     // be updated.
1493*6777b538SAndroid Build Coastguard Worker     //
1494*6777b538SAndroid Build Coastguard Worker     // "Equivalent" means they are the same by
1495*6777b538SAndroid Build Coastguard Worker     // IsEquivalentForSecureCookieMatching(). See the comment there for
1496*6777b538SAndroid Build Coastguard Worker     // details. (Note this is not a symmetric comparison.) This notion of
1497*6777b538SAndroid Build Coastguard Worker     // equivalence is slightly more inclusive than the usual IsEquivalent() one.
1498*6777b538SAndroid Build Coastguard Worker     //
1499*6777b538SAndroid Build Coastguard Worker     // See: https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone
1500*6777b538SAndroid Build Coastguard Worker     if (cur_existing_cookie->SecureAttribute() &&
1501*6777b538SAndroid Build Coastguard Worker         !allowed_to_set_secure_cookie &&
1502*6777b538SAndroid Build Coastguard Worker         cookie_being_set.IsEquivalentForSecureCookieMatching(
1503*6777b538SAndroid Build Coastguard Worker             *cur_existing_cookie)) {
1504*6777b538SAndroid Build Coastguard Worker       // Hold onto this for additional Netlogging later if we end up preserving
1505*6777b538SAndroid Build Coastguard Worker       // a would-have-been-deleted cookie because of this.
1506*6777b538SAndroid Build Coastguard Worker       skipped_secure_cookie = cur_existing_cookie;
1507*6777b538SAndroid Build Coastguard Worker       net_log_.AddEvent(NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_SECURE,
1508*6777b538SAndroid Build Coastguard Worker                         [&](NetLogCaptureMode capture_mode) {
1509*6777b538SAndroid Build Coastguard Worker                           return NetLogCookieMonsterCookieRejectedSecure(
1510*6777b538SAndroid Build Coastguard Worker                               skipped_secure_cookie, &cookie_being_set,
1511*6777b538SAndroid Build Coastguard Worker                               capture_mode);
1512*6777b538SAndroid Build Coastguard Worker                         });
1513*6777b538SAndroid Build Coastguard Worker       status->AddExclusionReason(
1514*6777b538SAndroid Build Coastguard Worker           CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE);
1515*6777b538SAndroid Build Coastguard Worker     }
1516*6777b538SAndroid Build Coastguard Worker 
1517*6777b538SAndroid Build Coastguard Worker     if (cookie_being_set.IsEquivalent(*cur_existing_cookie)) {
1518*6777b538SAndroid Build Coastguard Worker       // We should never have more than one equivalent cookie, since they should
1519*6777b538SAndroid Build Coastguard Worker       // overwrite each other.
1520*6777b538SAndroid Build Coastguard Worker       CHECK(!found_equivalent_cookie)
1521*6777b538SAndroid Build Coastguard Worker           << "Duplicate equivalent cookies found, cookie store is corrupted.";
1522*6777b538SAndroid Build Coastguard Worker       DCHECK(deletion_candidate_it == cookie_map->end());
1523*6777b538SAndroid Build Coastguard Worker       found_equivalent_cookie = true;
1524*6777b538SAndroid Build Coastguard Worker 
1525*6777b538SAndroid Build Coastguard Worker       // The |cookie_being_set| is rejected for trying to overwrite an httponly
1526*6777b538SAndroid Build Coastguard Worker       // cookie when it should not be able to.
1527*6777b538SAndroid Build Coastguard Worker       if (skip_httponly && cur_existing_cookie->IsHttpOnly()) {
1528*6777b538SAndroid Build Coastguard Worker         net_log_.AddEvent(
1529*6777b538SAndroid Build Coastguard Worker             NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_HTTPONLY,
1530*6777b538SAndroid Build Coastguard Worker             [&](NetLogCaptureMode capture_mode) {
1531*6777b538SAndroid Build Coastguard Worker               return NetLogCookieMonsterCookieRejectedHttponly(
1532*6777b538SAndroid Build Coastguard Worker                   cur_existing_cookie, &cookie_being_set, capture_mode);
1533*6777b538SAndroid Build Coastguard Worker             });
1534*6777b538SAndroid Build Coastguard Worker         status->AddExclusionReason(
1535*6777b538SAndroid Build Coastguard Worker             CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY);
1536*6777b538SAndroid Build Coastguard Worker       } else {
1537*6777b538SAndroid Build Coastguard Worker         deletion_candidate_it = cur_it;
1538*6777b538SAndroid Build Coastguard Worker       }
1539*6777b538SAndroid Build Coastguard Worker     }
1540*6777b538SAndroid Build Coastguard Worker   }
1541*6777b538SAndroid Build Coastguard Worker 
1542*6777b538SAndroid Build Coastguard Worker   if (deletion_candidate_it != cookie_map->end()) {
1543*6777b538SAndroid Build Coastguard Worker     CanonicalCookie* deletion_candidate = deletion_candidate_it->second.get();
1544*6777b538SAndroid Build Coastguard Worker     if (deletion_candidate->Value() == cookie_being_set.Value())
1545*6777b538SAndroid Build Coastguard Worker       *creation_date_to_inherit = deletion_candidate->CreationDate();
1546*6777b538SAndroid Build Coastguard Worker     if (status->IsInclude()) {
1547*6777b538SAndroid Build Coastguard Worker       if (cookie_being_set.IsPartitioned()) {
1548*6777b538SAndroid Build Coastguard Worker         InternalDeletePartitionedCookie(
1549*6777b538SAndroid Build Coastguard Worker             cookie_partition_it.value(), deletion_candidate_it,
1550*6777b538SAndroid Build Coastguard Worker             true /* sync_to_store */,
1551*6777b538SAndroid Build Coastguard Worker             already_expired ? DELETE_COOKIE_EXPIRED_OVERWRITE
1552*6777b538SAndroid Build Coastguard Worker                             : DELETE_COOKIE_OVERWRITE);
1553*6777b538SAndroid Build Coastguard Worker       } else {
1554*6777b538SAndroid Build Coastguard Worker         InternalDeleteCookie(deletion_candidate_it, true /* sync_to_store */,
1555*6777b538SAndroid Build Coastguard Worker                              already_expired ? DELETE_COOKIE_EXPIRED_OVERWRITE
1556*6777b538SAndroid Build Coastguard Worker                                              : DELETE_COOKIE_OVERWRITE);
1557*6777b538SAndroid Build Coastguard Worker       }
1558*6777b538SAndroid Build Coastguard Worker     } else if (status->HasExclusionReason(
1559*6777b538SAndroid Build Coastguard Worker                    CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE)) {
1560*6777b538SAndroid Build Coastguard Worker       // Log that we preserved a cookie that would have been deleted due to
1561*6777b538SAndroid Build Coastguard Worker       // Leave Secure Cookies Alone. This arbitrarily only logs the last
1562*6777b538SAndroid Build Coastguard Worker       // |skipped_secure_cookie| that we were left with after the for loop, even
1563*6777b538SAndroid Build Coastguard Worker       // if there were multiple matching Secure cookies that were left alone.
1564*6777b538SAndroid Build Coastguard Worker       DCHECK(skipped_secure_cookie);
1565*6777b538SAndroid Build Coastguard Worker       net_log_.AddEvent(
1566*6777b538SAndroid Build Coastguard Worker           NetLogEventType::COOKIE_STORE_COOKIE_PRESERVED_SKIPPED_SECURE,
1567*6777b538SAndroid Build Coastguard Worker           [&](NetLogCaptureMode capture_mode) {
1568*6777b538SAndroid Build Coastguard Worker             return NetLogCookieMonsterCookiePreservedSkippedSecure(
1569*6777b538SAndroid Build Coastguard Worker                 skipped_secure_cookie, deletion_candidate, &cookie_being_set,
1570*6777b538SAndroid Build Coastguard Worker                 capture_mode);
1571*6777b538SAndroid Build Coastguard Worker           });
1572*6777b538SAndroid Build Coastguard Worker     }
1573*6777b538SAndroid Build Coastguard Worker   }
1574*6777b538SAndroid Build Coastguard Worker }
1575*6777b538SAndroid Build Coastguard Worker 
InternalInsertCookie(const std::string & key,std::unique_ptr<CanonicalCookie> cc,bool sync_to_store,const CookieAccessResult & access_result,bool dispatch_change)1576*6777b538SAndroid Build Coastguard Worker CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie(
1577*6777b538SAndroid Build Coastguard Worker     const std::string& key,
1578*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<CanonicalCookie> cc,
1579*6777b538SAndroid Build Coastguard Worker     bool sync_to_store,
1580*6777b538SAndroid Build Coastguard Worker     const CookieAccessResult& access_result,
1581*6777b538SAndroid Build Coastguard Worker     bool dispatch_change) {
1582*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1583*6777b538SAndroid Build Coastguard Worker   CanonicalCookie* cc_ptr = cc.get();
1584*6777b538SAndroid Build Coastguard Worker 
1585*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::COOKIE_STORE_COOKIE_ADDED,
1586*6777b538SAndroid Build Coastguard Worker                     [&](NetLogCaptureMode capture_mode) {
1587*6777b538SAndroid Build Coastguard Worker                       return NetLogCookieMonsterCookieAdded(
1588*6777b538SAndroid Build Coastguard Worker                           cc.get(), sync_to_store, capture_mode);
1589*6777b538SAndroid Build Coastguard Worker                     });
1590*6777b538SAndroid Build Coastguard Worker   if (ShouldUpdatePersistentStore(cc_ptr) && sync_to_store)
1591*6777b538SAndroid Build Coastguard Worker     store_->AddCookie(*cc_ptr);
1592*6777b538SAndroid Build Coastguard Worker 
1593*6777b538SAndroid Build Coastguard Worker   auto inserted = cookies_.insert(CookieMap::value_type(key, std::move(cc)));
1594*6777b538SAndroid Build Coastguard Worker 
1595*6777b538SAndroid Build Coastguard Worker   LogStoredCookieToUMA(*cc_ptr, access_result);
1596*6777b538SAndroid Build Coastguard Worker 
1597*6777b538SAndroid Build Coastguard Worker   DCHECK(access_result.status.IsInclude());
1598*6777b538SAndroid Build Coastguard Worker   if (dispatch_change) {
1599*6777b538SAndroid Build Coastguard Worker     change_dispatcher_.DispatchChange(
1600*6777b538SAndroid Build Coastguard Worker         CookieChangeInfo(*cc_ptr, access_result, CookieChangeCause::INSERTED),
1601*6777b538SAndroid Build Coastguard Worker         true);
1602*6777b538SAndroid Build Coastguard Worker   }
1603*6777b538SAndroid Build Coastguard Worker 
1604*6777b538SAndroid Build Coastguard Worker   // If this is the first cookie in |cookies_| with this key, increment the
1605*6777b538SAndroid Build Coastguard Worker   // |num_keys_| counter.
1606*6777b538SAndroid Build Coastguard Worker   bool different_prev =
1607*6777b538SAndroid Build Coastguard Worker       inserted == cookies_.begin() || std::prev(inserted)->first != key;
1608*6777b538SAndroid Build Coastguard Worker   // According to std::multiqueue documentation:
1609*6777b538SAndroid Build Coastguard Worker   // "If the container has elements with equivalent key, inserts at the upper
1610*6777b538SAndroid Build Coastguard Worker   // bound of that range. (since C++11)"
1611*6777b538SAndroid Build Coastguard Worker   // This means that "inserted" iterator either points to the last element in
1612*6777b538SAndroid Build Coastguard Worker   // the map, or the element succeeding it has to have different key.
1613*6777b538SAndroid Build Coastguard Worker   DCHECK(std::next(inserted) == cookies_.end() ||
1614*6777b538SAndroid Build Coastguard Worker          std::next(inserted)->first != key);
1615*6777b538SAndroid Build Coastguard Worker   if (different_prev)
1616*6777b538SAndroid Build Coastguard Worker     ++num_keys_;
1617*6777b538SAndroid Build Coastguard Worker 
1618*6777b538SAndroid Build Coastguard Worker   return inserted;
1619*6777b538SAndroid Build Coastguard Worker }
1620*6777b538SAndroid Build Coastguard Worker 
ShouldUpdatePersistentStore(CanonicalCookie * cc)1621*6777b538SAndroid Build Coastguard Worker bool CookieMonster::ShouldUpdatePersistentStore(CanonicalCookie* cc) {
1622*6777b538SAndroid Build Coastguard Worker   return (cc->IsPersistent() || persist_session_cookies_) && store_.get();
1623*6777b538SAndroid Build Coastguard Worker }
1624*6777b538SAndroid Build Coastguard Worker 
1625*6777b538SAndroid Build Coastguard Worker CookieMonster::PartitionedCookieMapIterators
InternalInsertPartitionedCookie(std::string key,std::unique_ptr<CanonicalCookie> cc,bool sync_to_store,const CookieAccessResult & access_result,bool dispatch_change)1626*6777b538SAndroid Build Coastguard Worker CookieMonster::InternalInsertPartitionedCookie(
1627*6777b538SAndroid Build Coastguard Worker     std::string key,
1628*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<CanonicalCookie> cc,
1629*6777b538SAndroid Build Coastguard Worker     bool sync_to_store,
1630*6777b538SAndroid Build Coastguard Worker     const CookieAccessResult& access_result,
1631*6777b538SAndroid Build Coastguard Worker     bool dispatch_change) {
1632*6777b538SAndroid Build Coastguard Worker   DCHECK(cc->IsPartitioned());
1633*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1634*6777b538SAndroid Build Coastguard Worker   CanonicalCookie* cc_ptr = cc.get();
1635*6777b538SAndroid Build Coastguard Worker 
1636*6777b538SAndroid Build Coastguard Worker   net_log_.AddEvent(NetLogEventType::COOKIE_STORE_COOKIE_ADDED,
1637*6777b538SAndroid Build Coastguard Worker                     [&](NetLogCaptureMode capture_mode) {
1638*6777b538SAndroid Build Coastguard Worker                       return NetLogCookieMonsterCookieAdded(
1639*6777b538SAndroid Build Coastguard Worker                           cc.get(), sync_to_store, capture_mode);
1640*6777b538SAndroid Build Coastguard Worker                     });
1641*6777b538SAndroid Build Coastguard Worker   if (ShouldUpdatePersistentStore(cc_ptr) && sync_to_store)
1642*6777b538SAndroid Build Coastguard Worker     store_->AddCookie(*cc_ptr);
1643*6777b538SAndroid Build Coastguard Worker 
1644*6777b538SAndroid Build Coastguard Worker   CookiePartitionKey partition_key(cc->PartitionKey().value());
1645*6777b538SAndroid Build Coastguard Worker 
1646*6777b538SAndroid Build Coastguard Worker   size_t n_bytes = NameValueSizeBytes(*cc);
1647*6777b538SAndroid Build Coastguard Worker   num_partitioned_cookies_bytes_ += n_bytes;
1648*6777b538SAndroid Build Coastguard Worker   bytes_per_cookie_partition_[partition_key] += n_bytes;
1649*6777b538SAndroid Build Coastguard Worker   if (partition_key.nonce()) {
1650*6777b538SAndroid Build Coastguard Worker     num_nonced_partitioned_cookie_bytes_ += n_bytes;
1651*6777b538SAndroid Build Coastguard Worker   }
1652*6777b538SAndroid Build Coastguard Worker 
1653*6777b538SAndroid Build Coastguard Worker   PartitionedCookieMap::iterator partition_it =
1654*6777b538SAndroid Build Coastguard Worker       partitioned_cookies_.find(partition_key);
1655*6777b538SAndroid Build Coastguard Worker   if (partition_it == partitioned_cookies_.end()) {
1656*6777b538SAndroid Build Coastguard Worker     partition_it =
1657*6777b538SAndroid Build Coastguard Worker         partitioned_cookies_
1658*6777b538SAndroid Build Coastguard Worker             .insert(PartitionedCookieMap::value_type(
1659*6777b538SAndroid Build Coastguard Worker                 std::move(partition_key), std::make_unique<CookieMap>()))
1660*6777b538SAndroid Build Coastguard Worker             .first;
1661*6777b538SAndroid Build Coastguard Worker   }
1662*6777b538SAndroid Build Coastguard Worker 
1663*6777b538SAndroid Build Coastguard Worker   CookieMap::iterator cookie_it = partition_it->second->insert(
1664*6777b538SAndroid Build Coastguard Worker       CookieMap::value_type(std::move(key), std::move(cc)));
1665*6777b538SAndroid Build Coastguard Worker   ++num_partitioned_cookies_;
1666*6777b538SAndroid Build Coastguard Worker   if (partition_it->first.nonce()) {
1667*6777b538SAndroid Build Coastguard Worker     ++num_nonced_partitioned_cookies_;
1668*6777b538SAndroid Build Coastguard Worker   }
1669*6777b538SAndroid Build Coastguard Worker   CHECK_GE(num_partitioned_cookies_, num_nonced_partitioned_cookies_);
1670*6777b538SAndroid Build Coastguard Worker 
1671*6777b538SAndroid Build Coastguard Worker   LogStoredCookieToUMA(*cc_ptr, access_result);
1672*6777b538SAndroid Build Coastguard Worker 
1673*6777b538SAndroid Build Coastguard Worker   DCHECK(access_result.status.IsInclude());
1674*6777b538SAndroid Build Coastguard Worker   if (dispatch_change) {
1675*6777b538SAndroid Build Coastguard Worker     change_dispatcher_.DispatchChange(
1676*6777b538SAndroid Build Coastguard Worker         CookieChangeInfo(*cc_ptr, access_result, CookieChangeCause::INSERTED),
1677*6777b538SAndroid Build Coastguard Worker         true);
1678*6777b538SAndroid Build Coastguard Worker   }
1679*6777b538SAndroid Build Coastguard Worker 
1680*6777b538SAndroid Build Coastguard Worker   return std::pair(partition_it, cookie_it);
1681*6777b538SAndroid Build Coastguard Worker }
1682*6777b538SAndroid Build Coastguard Worker 
SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc,const GURL & source_url,const CookieOptions & options,SetCookiesCallback callback,std::optional<CookieAccessResult> cookie_access_result)1683*6777b538SAndroid Build Coastguard Worker void CookieMonster::SetCanonicalCookie(
1684*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<CanonicalCookie> cc,
1685*6777b538SAndroid Build Coastguard Worker     const GURL& source_url,
1686*6777b538SAndroid Build Coastguard Worker     const CookieOptions& options,
1687*6777b538SAndroid Build Coastguard Worker     SetCookiesCallback callback,
1688*6777b538SAndroid Build Coastguard Worker     std::optional<CookieAccessResult> cookie_access_result) {
1689*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1690*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/1482799): Fix macos specific issue with CHECK_IS_TEST crashing
1691*6777b538SAndroid Build Coastguard Worker // network service process.
1692*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(IS_MAC)
1693*6777b538SAndroid Build Coastguard Worker   // Only tests should be adding new cookies with source type kUnknown. If this
1694*6777b538SAndroid Build Coastguard Worker   // line causes a fatal track down the callsite and have it correctly set the
1695*6777b538SAndroid Build Coastguard Worker   // source type to kOther (or kHTTP/kScript where applicable). See
1696*6777b538SAndroid Build Coastguard Worker   // CookieSourceType in net/cookies/cookie_constants.h for more.
1697*6777b538SAndroid Build Coastguard Worker   if (cc->SourceType() == CookieSourceType::kUnknown) {
1698*6777b538SAndroid Build Coastguard Worker     CHECK_IS_TEST(base::NotFatalUntil::M126);
1699*6777b538SAndroid Build Coastguard Worker   }
1700*6777b538SAndroid Build Coastguard Worker #endif
1701*6777b538SAndroid Build Coastguard Worker 
1702*6777b538SAndroid Build Coastguard Worker   bool delegate_treats_url_as_trustworthy =
1703*6777b538SAndroid Build Coastguard Worker       cookie_access_delegate() &&
1704*6777b538SAndroid Build Coastguard Worker       cookie_access_delegate()->ShouldTreatUrlAsTrustworthy(source_url);
1705*6777b538SAndroid Build Coastguard Worker 
1706*6777b538SAndroid Build Coastguard Worker   CookieAccessResult access_result = cc->IsSetPermittedInContext(
1707*6777b538SAndroid Build Coastguard Worker       source_url, options,
1708*6777b538SAndroid Build Coastguard Worker       CookieAccessParams(GetAccessSemanticsForCookie(*cc),
1709*6777b538SAndroid Build Coastguard Worker                          delegate_treats_url_as_trustworthy),
1710*6777b538SAndroid Build Coastguard Worker       cookieable_schemes_, cookie_access_result);
1711*6777b538SAndroid Build Coastguard Worker 
1712*6777b538SAndroid Build Coastguard Worker   const std::string key(GetKey(cc->Domain()));
1713*6777b538SAndroid Build Coastguard Worker 
1714*6777b538SAndroid Build Coastguard Worker   base::Time creation_date = cc->CreationDate();
1715*6777b538SAndroid Build Coastguard Worker   if (creation_date.is_null()) {
1716*6777b538SAndroid Build Coastguard Worker     creation_date = Time::Now();
1717*6777b538SAndroid Build Coastguard Worker     cc->SetCreationDate(creation_date);
1718*6777b538SAndroid Build Coastguard Worker   }
1719*6777b538SAndroid Build Coastguard Worker   bool already_expired = cc->IsExpired(creation_date);
1720*6777b538SAndroid Build Coastguard Worker 
1721*6777b538SAndroid Build Coastguard Worker   base::Time creation_date_to_inherit;
1722*6777b538SAndroid Build Coastguard Worker 
1723*6777b538SAndroid Build Coastguard Worker   std::optional<PartitionedCookieMap::iterator> cookie_partition_it;
1724*6777b538SAndroid Build Coastguard Worker   bool should_try_to_delete_duplicates = true;
1725*6777b538SAndroid Build Coastguard Worker 
1726*6777b538SAndroid Build Coastguard Worker   if (cc->IsPartitioned()) {
1727*6777b538SAndroid Build Coastguard Worker     auto it = partitioned_cookies_.find(cc->PartitionKey().value());
1728*6777b538SAndroid Build Coastguard Worker     if (it == partitioned_cookies_.end()) {
1729*6777b538SAndroid Build Coastguard Worker       // This is the first cookie in its partition, so it won't have any
1730*6777b538SAndroid Build Coastguard Worker       // duplicates.
1731*6777b538SAndroid Build Coastguard Worker       should_try_to_delete_duplicates = false;
1732*6777b538SAndroid Build Coastguard Worker     } else {
1733*6777b538SAndroid Build Coastguard Worker       cookie_partition_it = std::make_optional(it);
1734*6777b538SAndroid Build Coastguard Worker     }
1735*6777b538SAndroid Build Coastguard Worker   }
1736*6777b538SAndroid Build Coastguard Worker 
1737*6777b538SAndroid Build Coastguard Worker   // Iterates through existing cookies for the same eTLD+1, and potentially
1738*6777b538SAndroid Build Coastguard Worker   // deletes an existing cookie, so any ExclusionReasons in |status| that would
1739*6777b538SAndroid Build Coastguard Worker   // prevent such deletion should be finalized beforehand.
1740*6777b538SAndroid Build Coastguard Worker   if (should_try_to_delete_duplicates) {
1741*6777b538SAndroid Build Coastguard Worker     MaybeDeleteEquivalentCookieAndUpdateStatus(
1742*6777b538SAndroid Build Coastguard Worker         key, *cc, access_result.is_allowed_to_access_secure_cookies,
1743*6777b538SAndroid Build Coastguard Worker         options.exclude_httponly(), already_expired, &creation_date_to_inherit,
1744*6777b538SAndroid Build Coastguard Worker         &access_result.status, cookie_partition_it);
1745*6777b538SAndroid Build Coastguard Worker   }
1746*6777b538SAndroid Build Coastguard Worker 
1747*6777b538SAndroid Build Coastguard Worker   if (access_result.status.HasExclusionReason(
1748*6777b538SAndroid Build Coastguard Worker           CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE) ||
1749*6777b538SAndroid Build Coastguard Worker       access_result.status.HasExclusionReason(
1750*6777b538SAndroid Build Coastguard Worker           CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY)) {
1751*6777b538SAndroid Build Coastguard Worker     DVLOG(net::cookie_util::kVlogSetCookies)
1752*6777b538SAndroid Build Coastguard Worker         << "SetCookie() not clobbering httponly cookie or secure cookie for "
1753*6777b538SAndroid Build Coastguard Worker            "insecure scheme";
1754*6777b538SAndroid Build Coastguard Worker   }
1755*6777b538SAndroid Build Coastguard Worker 
1756*6777b538SAndroid Build Coastguard Worker   if (access_result.status.IsInclude()) {
1757*6777b538SAndroid Build Coastguard Worker     DVLOG(net::cookie_util::kVlogSetCookies)
1758*6777b538SAndroid Build Coastguard Worker         << "SetCookie() key: " << key << " cc: " << cc->DebugString();
1759*6777b538SAndroid Build Coastguard Worker 
1760*6777b538SAndroid Build Coastguard Worker     if (cc->IsEffectivelySameSiteNone()) {
1761*6777b538SAndroid Build Coastguard Worker       size_t cookie_size = NameValueSizeBytes(*cc);
1762*6777b538SAndroid Build Coastguard Worker       UMA_HISTOGRAM_COUNTS_10000("Cookie.SameSiteNoneSizeBytes", cookie_size);
1763*6777b538SAndroid Build Coastguard Worker       if (cc->IsPartitioned()) {
1764*6777b538SAndroid Build Coastguard Worker         UMA_HISTOGRAM_COUNTS_10000("Cookie.SameSiteNoneSizeBytes.Partitioned",
1765*6777b538SAndroid Build Coastguard Worker                                    cookie_size);
1766*6777b538SAndroid Build Coastguard Worker       } else {
1767*6777b538SAndroid Build Coastguard Worker         UMA_HISTOGRAM_COUNTS_10000("Cookie.SameSiteNoneSizeBytes.Unpartitioned",
1768*6777b538SAndroid Build Coastguard Worker                                    cookie_size);
1769*6777b538SAndroid Build Coastguard Worker       }
1770*6777b538SAndroid Build Coastguard Worker     }
1771*6777b538SAndroid Build Coastguard Worker 
1772*6777b538SAndroid Build Coastguard Worker     std::optional<CookiePartitionKey> cookie_partition_key = cc->PartitionKey();
1773*6777b538SAndroid Build Coastguard Worker     CHECK_EQ(cc->IsPartitioned(), cookie_partition_key.has_value());
1774*6777b538SAndroid Build Coastguard Worker 
1775*6777b538SAndroid Build Coastguard Worker     // Realize that we might be setting an expired cookie, and the only point
1776*6777b538SAndroid Build Coastguard Worker     // was to delete the cookie which we've already done.
1777*6777b538SAndroid Build Coastguard Worker     if (!already_expired) {
1778*6777b538SAndroid Build Coastguard Worker       HistogramExpirationDuration(*cc, creation_date);
1779*6777b538SAndroid Build Coastguard Worker 
1780*6777b538SAndroid Build Coastguard Worker       // Histogram the type of scheme used on URLs that set cookies. This
1781*6777b538SAndroid Build Coastguard Worker       // intentionally includes cookies that are set or overwritten by
1782*6777b538SAndroid Build Coastguard Worker       // http:// URLs, but not cookies that are cleared by http:// URLs, to
1783*6777b538SAndroid Build Coastguard Worker       // understand if the former behavior can be deprecated for Secure
1784*6777b538SAndroid Build Coastguard Worker       // cookies.
1785*6777b538SAndroid Build Coastguard Worker       // TODO(crbug.com/993120): Consider removing this histogram. The decision
1786*6777b538SAndroid Build Coastguard Worker       // it was added to evaluate has been implemented and standardized.
1787*6777b538SAndroid Build Coastguard Worker       CookieSource cookie_source_sample =
1788*6777b538SAndroid Build Coastguard Worker           (source_url.SchemeIsCryptographic()
1789*6777b538SAndroid Build Coastguard Worker                ? (cc->SecureAttribute()
1790*6777b538SAndroid Build Coastguard Worker                       ? CookieSource::kSecureCookieCryptographicScheme
1791*6777b538SAndroid Build Coastguard Worker                       : CookieSource::kNonsecureCookieCryptographicScheme)
1792*6777b538SAndroid Build Coastguard Worker                : (cc->SecureAttribute()
1793*6777b538SAndroid Build Coastguard Worker                       ? CookieSource::kSecureCookieNoncryptographicScheme
1794*6777b538SAndroid Build Coastguard Worker                       : CookieSource::kNonsecureCookieNoncryptographicScheme));
1795*6777b538SAndroid Build Coastguard Worker       UMA_HISTOGRAM_ENUMERATION("Cookie.CookieSourceScheme",
1796*6777b538SAndroid Build Coastguard Worker                                 cookie_source_sample);
1797*6777b538SAndroid Build Coastguard Worker 
1798*6777b538SAndroid Build Coastguard Worker       UMA_HISTOGRAM_BOOLEAN("Cookie.DomainSet", cc->IsDomainCookie());
1799*6777b538SAndroid Build Coastguard Worker 
1800*6777b538SAndroid Build Coastguard Worker       if (!creation_date_to_inherit.is_null()) {
1801*6777b538SAndroid Build Coastguard Worker         cc->SetCreationDate(creation_date_to_inherit);
1802*6777b538SAndroid Build Coastguard Worker       }
1803*6777b538SAndroid Build Coastguard Worker 
1804*6777b538SAndroid Build Coastguard Worker       if (cookie_partition_key.has_value()) {
1805*6777b538SAndroid Build Coastguard Worker         InternalInsertPartitionedCookie(key, std::move(cc), true,
1806*6777b538SAndroid Build Coastguard Worker                                         access_result);
1807*6777b538SAndroid Build Coastguard Worker       } else {
1808*6777b538SAndroid Build Coastguard Worker         InternalInsertCookie(key, std::move(cc), true, access_result);
1809*6777b538SAndroid Build Coastguard Worker       }
1810*6777b538SAndroid Build Coastguard Worker     } else {
1811*6777b538SAndroid Build Coastguard Worker       DVLOG(net::cookie_util::kVlogSetCookies)
1812*6777b538SAndroid Build Coastguard Worker           << "SetCookie() not storing already expired cookie.";
1813*6777b538SAndroid Build Coastguard Worker     }
1814*6777b538SAndroid Build Coastguard Worker 
1815*6777b538SAndroid Build Coastguard Worker     // We assume that hopefully setting a cookie will be less common than
1816*6777b538SAndroid Build Coastguard Worker     // querying a cookie.  Since setting a cookie can put us over our limits,
1817*6777b538SAndroid Build Coastguard Worker     // make sure that we garbage collect...  We can also make the assumption
1818*6777b538SAndroid Build Coastguard Worker     // that if a cookie was set, in the common case it will be used soon after,
1819*6777b538SAndroid Build Coastguard Worker     // and we will purge the expired cookies in GetCookies().
1820*6777b538SAndroid Build Coastguard Worker     if (cookie_partition_key.has_value()) {
1821*6777b538SAndroid Build Coastguard Worker       GarbageCollectPartitionedCookies(creation_date,
1822*6777b538SAndroid Build Coastguard Worker                                        cookie_partition_key.value(), key);
1823*6777b538SAndroid Build Coastguard Worker     } else {
1824*6777b538SAndroid Build Coastguard Worker       GarbageCollect(creation_date, key);
1825*6777b538SAndroid Build Coastguard Worker     }
1826*6777b538SAndroid Build Coastguard Worker 
1827*6777b538SAndroid Build Coastguard Worker     if (IsLocalhost(source_url)) {
1828*6777b538SAndroid Build Coastguard Worker       UMA_HISTOGRAM_ENUMERATION(
1829*6777b538SAndroid Build Coastguard Worker           "Cookie.Port.Set.Localhost",
1830*6777b538SAndroid Build Coastguard Worker           ReducePortRangeForCookieHistogram(source_url.EffectiveIntPort()));
1831*6777b538SAndroid Build Coastguard Worker     } else {
1832*6777b538SAndroid Build Coastguard Worker       UMA_HISTOGRAM_ENUMERATION(
1833*6777b538SAndroid Build Coastguard Worker           "Cookie.Port.Set.RemoteHost",
1834*6777b538SAndroid Build Coastguard Worker           ReducePortRangeForCookieHistogram(source_url.EffectiveIntPort()));
1835*6777b538SAndroid Build Coastguard Worker     }
1836*6777b538SAndroid Build Coastguard Worker 
1837*6777b538SAndroid Build Coastguard Worker     UMA_HISTOGRAM_ENUMERATION("Cookie.CookieSourceSchemeName",
1838*6777b538SAndroid Build Coastguard Worker                               GetSchemeNameEnum(source_url));
1839*6777b538SAndroid Build Coastguard Worker   } else {
1840*6777b538SAndroid Build Coastguard Worker     // If the cookie would be excluded, don't bother warning about the 3p cookie
1841*6777b538SAndroid Build Coastguard Worker     // phaseout.
1842*6777b538SAndroid Build Coastguard Worker     access_result.status.RemoveWarningReason(
1843*6777b538SAndroid Build Coastguard Worker         net::CookieInclusionStatus::WARN_THIRD_PARTY_PHASEOUT);
1844*6777b538SAndroid Build Coastguard Worker   }
1845*6777b538SAndroid Build Coastguard Worker 
1846*6777b538SAndroid Build Coastguard Worker   // TODO(chlily): Log metrics.
1847*6777b538SAndroid Build Coastguard Worker   MaybeRunCookieCallback(std::move(callback), access_result);
1848*6777b538SAndroid Build Coastguard Worker }
1849*6777b538SAndroid Build Coastguard Worker 
SetAllCookies(CookieList list,SetCookiesCallback callback)1850*6777b538SAndroid Build Coastguard Worker void CookieMonster::SetAllCookies(CookieList list,
1851*6777b538SAndroid Build Coastguard Worker                                   SetCookiesCallback callback) {
1852*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1853*6777b538SAndroid Build Coastguard Worker 
1854*6777b538SAndroid Build Coastguard Worker   // Nuke the existing store.
1855*6777b538SAndroid Build Coastguard Worker   while (!cookies_.empty()) {
1856*6777b538SAndroid Build Coastguard Worker     // TODO(rdsmith): The CANONICAL is a lie.
1857*6777b538SAndroid Build Coastguard Worker     InternalDeleteCookie(cookies_.begin(), true, DELETE_COOKIE_EXPLICIT);
1858*6777b538SAndroid Build Coastguard Worker   }
1859*6777b538SAndroid Build Coastguard Worker 
1860*6777b538SAndroid Build Coastguard Worker   // Set all passed in cookies.
1861*6777b538SAndroid Build Coastguard Worker   for (const auto& cookie : list) {
1862*6777b538SAndroid Build Coastguard Worker     const std::string key(GetKey(cookie.Domain()));
1863*6777b538SAndroid Build Coastguard Worker     Time creation_time = cookie.CreationDate();
1864*6777b538SAndroid Build Coastguard Worker     if (cookie.IsExpired(creation_time))
1865*6777b538SAndroid Build Coastguard Worker       continue;
1866*6777b538SAndroid Build Coastguard Worker 
1867*6777b538SAndroid Build Coastguard Worker     HistogramExpirationDuration(cookie, creation_time);
1868*6777b538SAndroid Build Coastguard Worker 
1869*6777b538SAndroid Build Coastguard Worker     CookieAccessResult access_result;
1870*6777b538SAndroid Build Coastguard Worker     access_result.access_semantics = GetAccessSemanticsForCookie(cookie);
1871*6777b538SAndroid Build Coastguard Worker 
1872*6777b538SAndroid Build Coastguard Worker     if (cookie.IsPartitioned()) {
1873*6777b538SAndroid Build Coastguard Worker       InternalInsertPartitionedCookie(
1874*6777b538SAndroid Build Coastguard Worker           key, std::make_unique<CanonicalCookie>(cookie), true, access_result);
1875*6777b538SAndroid Build Coastguard Worker       GarbageCollectPartitionedCookies(creation_time,
1876*6777b538SAndroid Build Coastguard Worker                                        cookie.PartitionKey().value(), key);
1877*6777b538SAndroid Build Coastguard Worker     } else {
1878*6777b538SAndroid Build Coastguard Worker       InternalInsertCookie(key, std::make_unique<CanonicalCookie>(cookie), true,
1879*6777b538SAndroid Build Coastguard Worker                            access_result);
1880*6777b538SAndroid Build Coastguard Worker       GarbageCollect(creation_time, key);
1881*6777b538SAndroid Build Coastguard Worker     }
1882*6777b538SAndroid Build Coastguard Worker   }
1883*6777b538SAndroid Build Coastguard Worker 
1884*6777b538SAndroid Build Coastguard Worker   // TODO(rdsmith): If this function always returns the same value, it
1885*6777b538SAndroid Build Coastguard Worker   // shouldn't have a return value.  But it should also be deleted (see
1886*6777b538SAndroid Build Coastguard Worker   // https://codereview.chromium.org/2882063002/#msg64), which would
1887*6777b538SAndroid Build Coastguard Worker   // solve the return value problem.
1888*6777b538SAndroid Build Coastguard Worker   MaybeRunCookieCallback(std::move(callback), CookieAccessResult());
1889*6777b538SAndroid Build Coastguard Worker }
1890*6777b538SAndroid Build Coastguard Worker 
InternalUpdateCookieAccessTime(CanonicalCookie * cc,const Time & current)1891*6777b538SAndroid Build Coastguard Worker void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc,
1892*6777b538SAndroid Build Coastguard Worker                                                    const Time& current) {
1893*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1894*6777b538SAndroid Build Coastguard Worker 
1895*6777b538SAndroid Build Coastguard Worker   // Based off the Mozilla code.  When a cookie has been accessed recently,
1896*6777b538SAndroid Build Coastguard Worker   // don't bother updating its access time again.  This reduces the number of
1897*6777b538SAndroid Build Coastguard Worker   // updates we do during pageload, which in turn reduces the chance our storage
1898*6777b538SAndroid Build Coastguard Worker   // backend will hit its batch thresholds and be forced to update.
1899*6777b538SAndroid Build Coastguard Worker   if ((current - cc->LastAccessDate()) < last_access_threshold_)
1900*6777b538SAndroid Build Coastguard Worker     return;
1901*6777b538SAndroid Build Coastguard Worker 
1902*6777b538SAndroid Build Coastguard Worker   cc->SetLastAccessDate(current);
1903*6777b538SAndroid Build Coastguard Worker   if (ShouldUpdatePersistentStore(cc))
1904*6777b538SAndroid Build Coastguard Worker     store_->UpdateCookieAccessTime(*cc);
1905*6777b538SAndroid Build Coastguard Worker }
1906*6777b538SAndroid Build Coastguard Worker 
1907*6777b538SAndroid Build Coastguard Worker // InternalDeleteCookies must not invalidate iterators other than the one being
1908*6777b538SAndroid Build Coastguard Worker // deleted.
InternalDeleteCookie(CookieMap::iterator it,bool sync_to_store,DeletionCause deletion_cause)1909*6777b538SAndroid Build Coastguard Worker void CookieMonster::InternalDeleteCookie(CookieMap::iterator it,
1910*6777b538SAndroid Build Coastguard Worker                                          bool sync_to_store,
1911*6777b538SAndroid Build Coastguard Worker                                          DeletionCause deletion_cause) {
1912*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1913*6777b538SAndroid Build Coastguard Worker 
1914*6777b538SAndroid Build Coastguard Worker   // Ideally, this would be asserted up where we define kChangeCauseMapping,
1915*6777b538SAndroid Build Coastguard Worker   // but DeletionCause's visibility (or lack thereof) forces us to make
1916*6777b538SAndroid Build Coastguard Worker   // this check here.
1917*6777b538SAndroid Build Coastguard Worker   static_assert(std::size(kChangeCauseMapping) == DELETE_COOKIE_LAST_ENTRY + 1,
1918*6777b538SAndroid Build Coastguard Worker                 "kChangeCauseMapping size should match DeletionCause size");
1919*6777b538SAndroid Build Coastguard Worker 
1920*6777b538SAndroid Build Coastguard Worker   CanonicalCookie* cc = it->second.get();
1921*6777b538SAndroid Build Coastguard Worker   DVLOG(net::cookie_util::kVlogSetCookies)
1922*6777b538SAndroid Build Coastguard Worker       << "InternalDeleteCookie()"
1923*6777b538SAndroid Build Coastguard Worker       << ", cause:" << deletion_cause << ", cc: " << cc->DebugString();
1924*6777b538SAndroid Build Coastguard Worker 
1925*6777b538SAndroid Build Coastguard Worker   ChangeCausePair mapping = kChangeCauseMapping[deletion_cause];
1926*6777b538SAndroid Build Coastguard Worker   if (deletion_cause != DELETE_COOKIE_DONT_RECORD) {
1927*6777b538SAndroid Build Coastguard Worker     net_log_.AddEvent(NetLogEventType::COOKIE_STORE_COOKIE_DELETED,
1928*6777b538SAndroid Build Coastguard Worker                       [&](NetLogCaptureMode capture_mode) {
1929*6777b538SAndroid Build Coastguard Worker                         return NetLogCookieMonsterCookieDeleted(
1930*6777b538SAndroid Build Coastguard Worker                             cc, mapping.cause, sync_to_store, capture_mode);
1931*6777b538SAndroid Build Coastguard Worker                       });
1932*6777b538SAndroid Build Coastguard Worker   }
1933*6777b538SAndroid Build Coastguard Worker 
1934*6777b538SAndroid Build Coastguard Worker   if (ShouldUpdatePersistentStore(cc) && sync_to_store)
1935*6777b538SAndroid Build Coastguard Worker     store_->DeleteCookie(*cc);
1936*6777b538SAndroid Build Coastguard Worker 
1937*6777b538SAndroid Build Coastguard Worker   change_dispatcher_.DispatchChange(
1938*6777b538SAndroid Build Coastguard Worker       CookieChangeInfo(
1939*6777b538SAndroid Build Coastguard Worker           *cc,
1940*6777b538SAndroid Build Coastguard Worker           CookieAccessResult(CookieEffectiveSameSite::UNDEFINED,
1941*6777b538SAndroid Build Coastguard Worker                              CookieInclusionStatus(),
1942*6777b538SAndroid Build Coastguard Worker                              GetAccessSemanticsForCookie(*cc),
1943*6777b538SAndroid Build Coastguard Worker                              true /* is_allowed_to_access_secure_cookies */),
1944*6777b538SAndroid Build Coastguard Worker           mapping.cause),
1945*6777b538SAndroid Build Coastguard Worker       mapping.notify);
1946*6777b538SAndroid Build Coastguard Worker 
1947*6777b538SAndroid Build Coastguard Worker   // If this is the last cookie in |cookies_| with this key, decrement the
1948*6777b538SAndroid Build Coastguard Worker   // |num_keys_| counter.
1949*6777b538SAndroid Build Coastguard Worker   bool different_prev =
1950*6777b538SAndroid Build Coastguard Worker       it == cookies_.begin() || std::prev(it)->first != it->first;
1951*6777b538SAndroid Build Coastguard Worker   bool different_next =
1952*6777b538SAndroid Build Coastguard Worker       std::next(it) == cookies_.end() || std::next(it)->first != it->first;
1953*6777b538SAndroid Build Coastguard Worker   if (different_prev && different_next)
1954*6777b538SAndroid Build Coastguard Worker     --num_keys_;
1955*6777b538SAndroid Build Coastguard Worker 
1956*6777b538SAndroid Build Coastguard Worker   DCHECK(cookies_.find(it->first) != cookies_.end())
1957*6777b538SAndroid Build Coastguard Worker       << "Called erase with an iterator not in the cookie map";
1958*6777b538SAndroid Build Coastguard Worker   cookies_.erase(it);
1959*6777b538SAndroid Build Coastguard Worker }
1960*6777b538SAndroid Build Coastguard Worker 
InternalDeletePartitionedCookie(PartitionedCookieMap::iterator partition_it,CookieMap::iterator cookie_it,bool sync_to_store,DeletionCause deletion_cause)1961*6777b538SAndroid Build Coastguard Worker void CookieMonster::InternalDeletePartitionedCookie(
1962*6777b538SAndroid Build Coastguard Worker     PartitionedCookieMap::iterator partition_it,
1963*6777b538SAndroid Build Coastguard Worker     CookieMap::iterator cookie_it,
1964*6777b538SAndroid Build Coastguard Worker     bool sync_to_store,
1965*6777b538SAndroid Build Coastguard Worker     DeletionCause deletion_cause) {
1966*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1967*6777b538SAndroid Build Coastguard Worker 
1968*6777b538SAndroid Build Coastguard Worker   // Ideally, this would be asserted up where we define kChangeCauseMapping,
1969*6777b538SAndroid Build Coastguard Worker   // but DeletionCause's visibility (or lack thereof) forces us to make
1970*6777b538SAndroid Build Coastguard Worker   // this check here.
1971*6777b538SAndroid Build Coastguard Worker   static_assert(std::size(kChangeCauseMapping) == DELETE_COOKIE_LAST_ENTRY + 1,
1972*6777b538SAndroid Build Coastguard Worker                 "kChangeCauseMapping size should match DeletionCause size");
1973*6777b538SAndroid Build Coastguard Worker 
1974*6777b538SAndroid Build Coastguard Worker   CanonicalCookie* cc = cookie_it->second.get();
1975*6777b538SAndroid Build Coastguard Worker   DCHECK(cc->IsPartitioned());
1976*6777b538SAndroid Build Coastguard Worker   DVLOG(net::cookie_util::kVlogSetCookies)
1977*6777b538SAndroid Build Coastguard Worker       << "InternalDeletePartitionedCookie()"
1978*6777b538SAndroid Build Coastguard Worker       << ", cause:" << deletion_cause << ", cc: " << cc->DebugString();
1979*6777b538SAndroid Build Coastguard Worker 
1980*6777b538SAndroid Build Coastguard Worker   ChangeCausePair mapping = kChangeCauseMapping[deletion_cause];
1981*6777b538SAndroid Build Coastguard Worker   if (deletion_cause != DELETE_COOKIE_DONT_RECORD) {
1982*6777b538SAndroid Build Coastguard Worker     net_log_.AddEvent(NetLogEventType::COOKIE_STORE_COOKIE_DELETED,
1983*6777b538SAndroid Build Coastguard Worker                       [&](NetLogCaptureMode capture_mode) {
1984*6777b538SAndroid Build Coastguard Worker                         return NetLogCookieMonsterCookieDeleted(
1985*6777b538SAndroid Build Coastguard Worker                             cc, mapping.cause, sync_to_store, capture_mode);
1986*6777b538SAndroid Build Coastguard Worker                       });
1987*6777b538SAndroid Build Coastguard Worker   }
1988*6777b538SAndroid Build Coastguard Worker 
1989*6777b538SAndroid Build Coastguard Worker   if (ShouldUpdatePersistentStore(cc) && sync_to_store)
1990*6777b538SAndroid Build Coastguard Worker     store_->DeleteCookie(*cc);
1991*6777b538SAndroid Build Coastguard Worker 
1992*6777b538SAndroid Build Coastguard Worker   change_dispatcher_.DispatchChange(
1993*6777b538SAndroid Build Coastguard Worker       CookieChangeInfo(
1994*6777b538SAndroid Build Coastguard Worker           *cc,
1995*6777b538SAndroid Build Coastguard Worker           CookieAccessResult(CookieEffectiveSameSite::UNDEFINED,
1996*6777b538SAndroid Build Coastguard Worker                              CookieInclusionStatus(),
1997*6777b538SAndroid Build Coastguard Worker                              GetAccessSemanticsForCookie(*cc),
1998*6777b538SAndroid Build Coastguard Worker                              true /* is_allowed_to_access_secure_cookies */),
1999*6777b538SAndroid Build Coastguard Worker           mapping.cause),
2000*6777b538SAndroid Build Coastguard Worker       mapping.notify);
2001*6777b538SAndroid Build Coastguard Worker 
2002*6777b538SAndroid Build Coastguard Worker   size_t n_bytes = NameValueSizeBytes(*cc);
2003*6777b538SAndroid Build Coastguard Worker   num_partitioned_cookies_bytes_ -= n_bytes;
2004*6777b538SAndroid Build Coastguard Worker   bytes_per_cookie_partition_[*cc->PartitionKey()] -= n_bytes;
2005*6777b538SAndroid Build Coastguard Worker   if (CookiePartitionKey::HasNonce(cc->PartitionKey())) {
2006*6777b538SAndroid Build Coastguard Worker     num_nonced_partitioned_cookie_bytes_ -= n_bytes;
2007*6777b538SAndroid Build Coastguard Worker   }
2008*6777b538SAndroid Build Coastguard Worker 
2009*6777b538SAndroid Build Coastguard Worker   DCHECK(partition_it->second->find(cookie_it->first) !=
2010*6777b538SAndroid Build Coastguard Worker          partition_it->second->end())
2011*6777b538SAndroid Build Coastguard Worker       << "Called erase with an iterator not in this partitioned cookie map";
2012*6777b538SAndroid Build Coastguard Worker   partition_it->second->erase(cookie_it);
2013*6777b538SAndroid Build Coastguard Worker   --num_partitioned_cookies_;
2014*6777b538SAndroid Build Coastguard Worker   if (partition_it->first.nonce()) {
2015*6777b538SAndroid Build Coastguard Worker     --num_nonced_partitioned_cookies_;
2016*6777b538SAndroid Build Coastguard Worker   }
2017*6777b538SAndroid Build Coastguard Worker   CHECK_GE(num_partitioned_cookies_, num_nonced_partitioned_cookies_);
2018*6777b538SAndroid Build Coastguard Worker 
2019*6777b538SAndroid Build Coastguard Worker   if (partition_it->second->empty())
2020*6777b538SAndroid Build Coastguard Worker     partitioned_cookies_.erase(partition_it);
2021*6777b538SAndroid Build Coastguard Worker }
2022*6777b538SAndroid Build Coastguard Worker 
2023*6777b538SAndroid Build Coastguard Worker // Domain expiry behavior is unchanged by key/expiry scheme (the
2024*6777b538SAndroid Build Coastguard Worker // meaning of the key is different, but that's not visible to this routine).
GarbageCollect(const Time & current,const std::string & key)2025*6777b538SAndroid Build Coastguard Worker size_t CookieMonster::GarbageCollect(const Time& current,
2026*6777b538SAndroid Build Coastguard Worker                                      const std::string& key) {
2027*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2028*6777b538SAndroid Build Coastguard Worker 
2029*6777b538SAndroid Build Coastguard Worker   size_t num_deleted = 0;
2030*6777b538SAndroid Build Coastguard Worker   const Time safe_date(Time::Now() - base::Days(kSafeFromGlobalPurgeDays));
2031*6777b538SAndroid Build Coastguard Worker 
2032*6777b538SAndroid Build Coastguard Worker   const bool obc_behavior_enabled =
2033*6777b538SAndroid Build Coastguard Worker       cookie_util::IsOriginBoundCookiesPartiallyEnabled();
2034*6777b538SAndroid Build Coastguard Worker 
2035*6777b538SAndroid Build Coastguard Worker   // Collect garbage for this key, minding cookie priorities.
2036*6777b538SAndroid Build Coastguard Worker   if (cookies_.count(key) > kDomainMaxCookies) {
2037*6777b538SAndroid Build Coastguard Worker     DVLOG(net::cookie_util::kVlogGarbageCollection)
2038*6777b538SAndroid Build Coastguard Worker         << "GarbageCollect() key: " << key;
2039*6777b538SAndroid Build Coastguard Worker 
2040*6777b538SAndroid Build Coastguard Worker     CookieItVector* cookie_its;
2041*6777b538SAndroid Build Coastguard Worker 
2042*6777b538SAndroid Build Coastguard Worker     CookieItVector non_expired_cookie_its;
2043*6777b538SAndroid Build Coastguard Worker     cookie_its = &non_expired_cookie_its;
2044*6777b538SAndroid Build Coastguard Worker     num_deleted +=
2045*6777b538SAndroid Build Coastguard Worker         GarbageCollectExpired(current, cookies_.equal_range(key), cookie_its);
2046*6777b538SAndroid Build Coastguard Worker 
2047*6777b538SAndroid Build Coastguard Worker     if (cookie_its->size() > kDomainMaxCookies) {
2048*6777b538SAndroid Build Coastguard Worker       DVLOG(net::cookie_util::kVlogGarbageCollection)
2049*6777b538SAndroid Build Coastguard Worker           << "Deep Garbage Collect domain.";
2050*6777b538SAndroid Build Coastguard Worker 
2051*6777b538SAndroid Build Coastguard Worker       if (domain_purged_keys_.size() < kMaxDomainPurgedKeys)
2052*6777b538SAndroid Build Coastguard Worker         domain_purged_keys_.insert(key);
2053*6777b538SAndroid Build Coastguard Worker 
2054*6777b538SAndroid Build Coastguard Worker       size_t purge_goal =
2055*6777b538SAndroid Build Coastguard Worker           cookie_its->size() - (kDomainMaxCookies - kDomainPurgeCookies);
2056*6777b538SAndroid Build Coastguard Worker       DCHECK(purge_goal > kDomainPurgeCookies);
2057*6777b538SAndroid Build Coastguard Worker 
2058*6777b538SAndroid Build Coastguard Worker       // Sort the cookies by access date, from least-recent to most-recent.
2059*6777b538SAndroid Build Coastguard Worker       std::sort(cookie_its->begin(), cookie_its->end(), LRACookieSorter);
2060*6777b538SAndroid Build Coastguard Worker 
2061*6777b538SAndroid Build Coastguard Worker       CookieItList cookie_it_list;
2062*6777b538SAndroid Build Coastguard Worker       if (obc_behavior_enabled) {
2063*6777b538SAndroid Build Coastguard Worker         cookie_it_list = CookieItList(cookie_its->begin(), cookie_its->end());
2064*6777b538SAndroid Build Coastguard Worker       }
2065*6777b538SAndroid Build Coastguard Worker 
2066*6777b538SAndroid Build Coastguard Worker       // Remove all but the kDomainCookiesQuotaLow most-recently accessed
2067*6777b538SAndroid Build Coastguard Worker       // cookies with low-priority. Then, if cookies still need to be removed,
2068*6777b538SAndroid Build Coastguard Worker       // bump the quota and remove low- and medium-priority. Then, if cookies
2069*6777b538SAndroid Build Coastguard Worker       // _still_ need to be removed, bump the quota and remove cookies with
2070*6777b538SAndroid Build Coastguard Worker       // any priority.
2071*6777b538SAndroid Build Coastguard Worker       //
2072*6777b538SAndroid Build Coastguard Worker       // 1.  Low-priority non-secure cookies.
2073*6777b538SAndroid Build Coastguard Worker       // 2.  Low-priority secure cookies.
2074*6777b538SAndroid Build Coastguard Worker       // 3.  Medium-priority non-secure cookies.
2075*6777b538SAndroid Build Coastguard Worker       // 4.  High-priority non-secure cookies.
2076*6777b538SAndroid Build Coastguard Worker       // 5.  Medium-priority secure cookies.
2077*6777b538SAndroid Build Coastguard Worker       // 6.  High-priority secure cookies.
2078*6777b538SAndroid Build Coastguard Worker       constexpr struct {
2079*6777b538SAndroid Build Coastguard Worker         CookiePriority priority;
2080*6777b538SAndroid Build Coastguard Worker         bool protect_secure_cookies;
2081*6777b538SAndroid Build Coastguard Worker       } kPurgeRounds[] = {
2082*6777b538SAndroid Build Coastguard Worker           // 1.  Low-priority non-secure cookies.
2083*6777b538SAndroid Build Coastguard Worker           {COOKIE_PRIORITY_LOW, true},
2084*6777b538SAndroid Build Coastguard Worker           // 2.  Low-priority secure cookies.
2085*6777b538SAndroid Build Coastguard Worker           {COOKIE_PRIORITY_LOW, false},
2086*6777b538SAndroid Build Coastguard Worker           // 3.  Medium-priority non-secure cookies.
2087*6777b538SAndroid Build Coastguard Worker           {COOKIE_PRIORITY_MEDIUM, true},
2088*6777b538SAndroid Build Coastguard Worker           // 4.  High-priority non-secure cookies.
2089*6777b538SAndroid Build Coastguard Worker           {COOKIE_PRIORITY_HIGH, true},
2090*6777b538SAndroid Build Coastguard Worker           // 5.  Medium-priority secure cookies.
2091*6777b538SAndroid Build Coastguard Worker           {COOKIE_PRIORITY_MEDIUM, false},
2092*6777b538SAndroid Build Coastguard Worker           // 6.  High-priority secure cookies.
2093*6777b538SAndroid Build Coastguard Worker           {COOKIE_PRIORITY_HIGH, false},
2094*6777b538SAndroid Build Coastguard Worker       };
2095*6777b538SAndroid Build Coastguard Worker 
2096*6777b538SAndroid Build Coastguard Worker       size_t quota = 0;
2097*6777b538SAndroid Build Coastguard Worker       for (const auto& purge_round : kPurgeRounds) {
2098*6777b538SAndroid Build Coastguard Worker         // Adjust quota according to the priority of cookies. Each round should
2099*6777b538SAndroid Build Coastguard Worker         // protect certain number of cookies in order to avoid starvation.
2100*6777b538SAndroid Build Coastguard Worker         // For example, when each round starts to remove cookies, the number of
2101*6777b538SAndroid Build Coastguard Worker         // cookies of that priority are counted and a decision whether they
2102*6777b538SAndroid Build Coastguard Worker         // should be deleted or not is made. If yes, some number of cookies of
2103*6777b538SAndroid Build Coastguard Worker         // that priority are deleted considering the quota.
2104*6777b538SAndroid Build Coastguard Worker         switch (purge_round.priority) {
2105*6777b538SAndroid Build Coastguard Worker           case COOKIE_PRIORITY_LOW:
2106*6777b538SAndroid Build Coastguard Worker             quota = kDomainCookiesQuotaLow;
2107*6777b538SAndroid Build Coastguard Worker             break;
2108*6777b538SAndroid Build Coastguard Worker           case COOKIE_PRIORITY_MEDIUM:
2109*6777b538SAndroid Build Coastguard Worker             quota = kDomainCookiesQuotaMedium;
2110*6777b538SAndroid Build Coastguard Worker             break;
2111*6777b538SAndroid Build Coastguard Worker           case COOKIE_PRIORITY_HIGH:
2112*6777b538SAndroid Build Coastguard Worker             quota = kDomainCookiesQuotaHigh;
2113*6777b538SAndroid Build Coastguard Worker             break;
2114*6777b538SAndroid Build Coastguard Worker         }
2115*6777b538SAndroid Build Coastguard Worker         size_t just_deleted = 0u;
2116*6777b538SAndroid Build Coastguard Worker         // Purge up to |purge_goal| for all cookies at the given priority.  This
2117*6777b538SAndroid Build Coastguard Worker         // path will be taken only if the initial non-secure purge did not evict
2118*6777b538SAndroid Build Coastguard Worker         // enough cookies.
2119*6777b538SAndroid Build Coastguard Worker         if (purge_goal > 0) {
2120*6777b538SAndroid Build Coastguard Worker           if (obc_behavior_enabled) {
2121*6777b538SAndroid Build Coastguard Worker             just_deleted = PurgeLeastRecentMatchesForOBC(
2122*6777b538SAndroid Build Coastguard Worker                 &cookie_it_list, purge_round.priority, quota, purge_goal,
2123*6777b538SAndroid Build Coastguard Worker                 !purge_round.protect_secure_cookies);
2124*6777b538SAndroid Build Coastguard Worker           } else {
2125*6777b538SAndroid Build Coastguard Worker             just_deleted = PurgeLeastRecentMatches(
2126*6777b538SAndroid Build Coastguard Worker                 cookie_its, purge_round.priority, quota, purge_goal,
2127*6777b538SAndroid Build Coastguard Worker                 purge_round.protect_secure_cookies);
2128*6777b538SAndroid Build Coastguard Worker           }
2129*6777b538SAndroid Build Coastguard Worker           DCHECK_LE(just_deleted, purge_goal);
2130*6777b538SAndroid Build Coastguard Worker           purge_goal -= just_deleted;
2131*6777b538SAndroid Build Coastguard Worker           num_deleted += just_deleted;
2132*6777b538SAndroid Build Coastguard Worker         }
2133*6777b538SAndroid Build Coastguard Worker       }
2134*6777b538SAndroid Build Coastguard Worker 
2135*6777b538SAndroid Build Coastguard Worker       DCHECK_EQ(0u, purge_goal);
2136*6777b538SAndroid Build Coastguard Worker     }
2137*6777b538SAndroid Build Coastguard Worker   }
2138*6777b538SAndroid Build Coastguard Worker 
2139*6777b538SAndroid Build Coastguard Worker   // Collect garbage for everything. With firefox style we want to preserve
2140*6777b538SAndroid Build Coastguard Worker   // cookies accessed in kSafeFromGlobalPurgeDays, otherwise evict.
2141*6777b538SAndroid Build Coastguard Worker   if (cookies_.size() > kMaxCookies && earliest_access_time_ < safe_date) {
2142*6777b538SAndroid Build Coastguard Worker     DVLOG(net::cookie_util::kVlogGarbageCollection)
2143*6777b538SAndroid Build Coastguard Worker         << "GarbageCollect() everything";
2144*6777b538SAndroid Build Coastguard Worker     CookieItVector cookie_its;
2145*6777b538SAndroid Build Coastguard Worker 
2146*6777b538SAndroid Build Coastguard Worker     num_deleted += GarbageCollectExpired(
2147*6777b538SAndroid Build Coastguard Worker         current, CookieMapItPair(cookies_.begin(), cookies_.end()),
2148*6777b538SAndroid Build Coastguard Worker         &cookie_its);
2149*6777b538SAndroid Build Coastguard Worker 
2150*6777b538SAndroid Build Coastguard Worker     if (cookie_its.size() > kMaxCookies) {
2151*6777b538SAndroid Build Coastguard Worker       DVLOG(net::cookie_util::kVlogGarbageCollection)
2152*6777b538SAndroid Build Coastguard Worker           << "Deep Garbage Collect everything.";
2153*6777b538SAndroid Build Coastguard Worker       size_t purge_goal = cookie_its.size() - (kMaxCookies - kPurgeCookies);
2154*6777b538SAndroid Build Coastguard Worker       DCHECK(purge_goal > kPurgeCookies);
2155*6777b538SAndroid Build Coastguard Worker 
2156*6777b538SAndroid Build Coastguard Worker       CookieItVector secure_cookie_its;
2157*6777b538SAndroid Build Coastguard Worker       CookieItVector non_secure_cookie_its;
2158*6777b538SAndroid Build Coastguard Worker       SplitCookieVectorIntoSecureAndNonSecure(cookie_its, &secure_cookie_its,
2159*6777b538SAndroid Build Coastguard Worker                                               &non_secure_cookie_its);
2160*6777b538SAndroid Build Coastguard Worker       size_t non_secure_purge_goal =
2161*6777b538SAndroid Build Coastguard Worker           std::min<size_t>(purge_goal, non_secure_cookie_its.size());
2162*6777b538SAndroid Build Coastguard Worker 
2163*6777b538SAndroid Build Coastguard Worker       base::Time earliest_non_secure_access_time;
2164*6777b538SAndroid Build Coastguard Worker       size_t just_deleted = GarbageCollectLeastRecentlyAccessed(
2165*6777b538SAndroid Build Coastguard Worker           current, safe_date, non_secure_purge_goal, non_secure_cookie_its,
2166*6777b538SAndroid Build Coastguard Worker           &earliest_non_secure_access_time);
2167*6777b538SAndroid Build Coastguard Worker       num_deleted += just_deleted;
2168*6777b538SAndroid Build Coastguard Worker 
2169*6777b538SAndroid Build Coastguard Worker       if (secure_cookie_its.size() == 0) {
2170*6777b538SAndroid Build Coastguard Worker         // This case is unlikely, but should still update
2171*6777b538SAndroid Build Coastguard Worker         // |earliest_access_time_| if only have non-secure cookies.
2172*6777b538SAndroid Build Coastguard Worker         earliest_access_time_ = earliest_non_secure_access_time;
2173*6777b538SAndroid Build Coastguard Worker         // Garbage collection can't delete all cookies.
2174*6777b538SAndroid Build Coastguard Worker         DCHECK(!earliest_access_time_.is_null());
2175*6777b538SAndroid Build Coastguard Worker       } else if (just_deleted < purge_goal) {
2176*6777b538SAndroid Build Coastguard Worker         size_t secure_purge_goal = std::min<size_t>(purge_goal - just_deleted,
2177*6777b538SAndroid Build Coastguard Worker                                                     secure_cookie_its.size());
2178*6777b538SAndroid Build Coastguard Worker         base::Time earliest_secure_access_time;
2179*6777b538SAndroid Build Coastguard Worker         num_deleted += GarbageCollectLeastRecentlyAccessed(
2180*6777b538SAndroid Build Coastguard Worker             current, safe_date, secure_purge_goal, secure_cookie_its,
2181*6777b538SAndroid Build Coastguard Worker             &earliest_secure_access_time);
2182*6777b538SAndroid Build Coastguard Worker 
2183*6777b538SAndroid Build Coastguard Worker         if (!earliest_non_secure_access_time.is_null() &&
2184*6777b538SAndroid Build Coastguard Worker             earliest_non_secure_access_time < earliest_secure_access_time) {
2185*6777b538SAndroid Build Coastguard Worker           earliest_access_time_ = earliest_non_secure_access_time;
2186*6777b538SAndroid Build Coastguard Worker         } else {
2187*6777b538SAndroid Build Coastguard Worker           earliest_access_time_ = earliest_secure_access_time;
2188*6777b538SAndroid Build Coastguard Worker         }
2189*6777b538SAndroid Build Coastguard Worker 
2190*6777b538SAndroid Build Coastguard Worker         // Garbage collection can't delete all cookies.
2191*6777b538SAndroid Build Coastguard Worker         DCHECK(!earliest_access_time_.is_null());
2192*6777b538SAndroid Build Coastguard Worker       }
2193*6777b538SAndroid Build Coastguard Worker 
2194*6777b538SAndroid Build Coastguard Worker       // If there are secure cookies, but deleting non-secure cookies was enough
2195*6777b538SAndroid Build Coastguard Worker       // to meet the purge goal, secure cookies are never examined, so
2196*6777b538SAndroid Build Coastguard Worker       // |earliest_access_time_| can't be determined. Leaving it alone will mean
2197*6777b538SAndroid Build Coastguard Worker       // it's no later than the real earliest last access time, so this won't
2198*6777b538SAndroid Build Coastguard Worker       // lead to any problems.
2199*6777b538SAndroid Build Coastguard Worker     }
2200*6777b538SAndroid Build Coastguard Worker   }
2201*6777b538SAndroid Build Coastguard Worker 
2202*6777b538SAndroid Build Coastguard Worker   return num_deleted;
2203*6777b538SAndroid Build Coastguard Worker }
2204*6777b538SAndroid Build Coastguard Worker 
GarbageCollectPartitionedCookies(const base::Time & current,const CookiePartitionKey & cookie_partition_key,const std::string & key)2205*6777b538SAndroid Build Coastguard Worker size_t CookieMonster::GarbageCollectPartitionedCookies(
2206*6777b538SAndroid Build Coastguard Worker     const base::Time& current,
2207*6777b538SAndroid Build Coastguard Worker     const CookiePartitionKey& cookie_partition_key,
2208*6777b538SAndroid Build Coastguard Worker     const std::string& key) {
2209*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2210*6777b538SAndroid Build Coastguard Worker 
2211*6777b538SAndroid Build Coastguard Worker   size_t num_deleted = 0;
2212*6777b538SAndroid Build Coastguard Worker   PartitionedCookieMap::iterator cookie_partition_it =
2213*6777b538SAndroid Build Coastguard Worker       partitioned_cookies_.find(cookie_partition_key);
2214*6777b538SAndroid Build Coastguard Worker 
2215*6777b538SAndroid Build Coastguard Worker   if (cookie_partition_it == partitioned_cookies_.end())
2216*6777b538SAndroid Build Coastguard Worker     return num_deleted;
2217*6777b538SAndroid Build Coastguard Worker 
2218*6777b538SAndroid Build Coastguard Worker   if (NumBytesInCookieMapForKey(*cookie_partition_it->second.get(), key) >
2219*6777b538SAndroid Build Coastguard Worker           kPerPartitionDomainMaxCookieBytes ||
2220*6777b538SAndroid Build Coastguard Worker       cookie_partition_it->second->count(key) > kPerPartitionDomainMaxCookies) {
2221*6777b538SAndroid Build Coastguard Worker     // TODO(crbug.com/1225444): Log garbage collection for partitioned cookies.
2222*6777b538SAndroid Build Coastguard Worker 
2223*6777b538SAndroid Build Coastguard Worker     CookieItVector non_expired_cookie_its;
2224*6777b538SAndroid Build Coastguard Worker     num_deleted += GarbageCollectExpiredPartitionedCookies(
2225*6777b538SAndroid Build Coastguard Worker         current, cookie_partition_it,
2226*6777b538SAndroid Build Coastguard Worker         cookie_partition_it->second->equal_range(key), &non_expired_cookie_its);
2227*6777b538SAndroid Build Coastguard Worker 
2228*6777b538SAndroid Build Coastguard Worker     size_t bytes_used = NumBytesInCookieItVector(non_expired_cookie_its);
2229*6777b538SAndroid Build Coastguard Worker 
2230*6777b538SAndroid Build Coastguard Worker     if (bytes_used > kPerPartitionDomainMaxCookieBytes ||
2231*6777b538SAndroid Build Coastguard Worker         non_expired_cookie_its.size() > kPerPartitionDomainMaxCookies) {
2232*6777b538SAndroid Build Coastguard Worker       // TODO(crbug.com/1225444): Log deep garbage collection for partitioned
2233*6777b538SAndroid Build Coastguard Worker       // cookies.
2234*6777b538SAndroid Build Coastguard Worker       std::sort(non_expired_cookie_its.begin(), non_expired_cookie_its.end(),
2235*6777b538SAndroid Build Coastguard Worker                 LRACookieSorter);
2236*6777b538SAndroid Build Coastguard Worker 
2237*6777b538SAndroid Build Coastguard Worker       for (size_t i = 0;
2238*6777b538SAndroid Build Coastguard Worker            bytes_used > kPerPartitionDomainMaxCookieBytes ||
2239*6777b538SAndroid Build Coastguard Worker            non_expired_cookie_its.size() - i > kPerPartitionDomainMaxCookies;
2240*6777b538SAndroid Build Coastguard Worker            ++i) {
2241*6777b538SAndroid Build Coastguard Worker         bytes_used -= NameValueSizeBytes(*non_expired_cookie_its[i]->second);
2242*6777b538SAndroid Build Coastguard Worker         InternalDeletePartitionedCookie(
2243*6777b538SAndroid Build Coastguard Worker             cookie_partition_it, non_expired_cookie_its[i], true,
2244*6777b538SAndroid Build Coastguard Worker             DELETE_COOKIE_EVICTED_PER_PARTITION_DOMAIN);
2245*6777b538SAndroid Build Coastguard Worker         ++num_deleted;
2246*6777b538SAndroid Build Coastguard Worker       }
2247*6777b538SAndroid Build Coastguard Worker     }
2248*6777b538SAndroid Build Coastguard Worker   }
2249*6777b538SAndroid Build Coastguard Worker 
2250*6777b538SAndroid Build Coastguard Worker   // TODO(crbug.com/1225444): Enforce global limit on partitioned cookies.
2251*6777b538SAndroid Build Coastguard Worker 
2252*6777b538SAndroid Build Coastguard Worker   return num_deleted;
2253*6777b538SAndroid Build Coastguard Worker }
2254*6777b538SAndroid Build Coastguard Worker 
PurgeLeastRecentMatches(CookieItVector * cookies,CookiePriority priority,size_t to_protect,size_t purge_goal,bool protect_secure_cookies)2255*6777b538SAndroid Build Coastguard Worker size_t CookieMonster::PurgeLeastRecentMatches(CookieItVector* cookies,
2256*6777b538SAndroid Build Coastguard Worker                                               CookiePriority priority,
2257*6777b538SAndroid Build Coastguard Worker                                               size_t to_protect,
2258*6777b538SAndroid Build Coastguard Worker                                               size_t purge_goal,
2259*6777b538SAndroid Build Coastguard Worker                                               bool protect_secure_cookies) {
2260*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2261*6777b538SAndroid Build Coastguard Worker 
2262*6777b538SAndroid Build Coastguard Worker   // 1. Count number of the cookies at |priority|
2263*6777b538SAndroid Build Coastguard Worker   size_t cookies_count_possibly_to_be_deleted = CountCookiesForPossibleDeletion(
2264*6777b538SAndroid Build Coastguard Worker       priority, cookies, false /* count all cookies */);
2265*6777b538SAndroid Build Coastguard Worker 
2266*6777b538SAndroid Build Coastguard Worker   // 2. If |cookies_count_possibly_to_be_deleted| at |priority| is less than or
2267*6777b538SAndroid Build Coastguard Worker   // equal |to_protect|, skip round in order to preserve the quota. This
2268*6777b538SAndroid Build Coastguard Worker   // involves secure and non-secure cookies at |priority|.
2269*6777b538SAndroid Build Coastguard Worker   if (cookies_count_possibly_to_be_deleted <= to_protect)
2270*6777b538SAndroid Build Coastguard Worker     return 0u;
2271*6777b538SAndroid Build Coastguard Worker 
2272*6777b538SAndroid Build Coastguard Worker   // 3. Calculate number of secure cookies at |priority|
2273*6777b538SAndroid Build Coastguard Worker   // and number of cookies at |priority| that can possibly be deleted.
2274*6777b538SAndroid Build Coastguard Worker   // It is guaranteed we do not delete more than |purge_goal| even if
2275*6777b538SAndroid Build Coastguard Worker   // |cookies_count_possibly_to_be_deleted| is higher.
2276*6777b538SAndroid Build Coastguard Worker   size_t secure_cookies = 0u;
2277*6777b538SAndroid Build Coastguard Worker   if (protect_secure_cookies) {
2278*6777b538SAndroid Build Coastguard Worker     secure_cookies = CountCookiesForPossibleDeletion(
2279*6777b538SAndroid Build Coastguard Worker         priority, cookies, protect_secure_cookies /* count secure cookies */);
2280*6777b538SAndroid Build Coastguard Worker     cookies_count_possibly_to_be_deleted -=
2281*6777b538SAndroid Build Coastguard Worker         std::max(secure_cookies, to_protect);
2282*6777b538SAndroid Build Coastguard Worker   } else {
2283*6777b538SAndroid Build Coastguard Worker     cookies_count_possibly_to_be_deleted -= to_protect;
2284*6777b538SAndroid Build Coastguard Worker   }
2285*6777b538SAndroid Build Coastguard Worker 
2286*6777b538SAndroid Build Coastguard Worker   size_t removed = 0u;
2287*6777b538SAndroid Build Coastguard Worker   size_t current = 0u;
2288*6777b538SAndroid Build Coastguard Worker   while ((removed < purge_goal && current < cookies->size()) &&
2289*6777b538SAndroid Build Coastguard Worker          cookies_count_possibly_to_be_deleted > 0) {
2290*6777b538SAndroid Build Coastguard Worker     const CanonicalCookie* current_cookie = cookies->at(current)->second.get();
2291*6777b538SAndroid Build Coastguard Worker     // Only delete the current cookie if the priority is equal to
2292*6777b538SAndroid Build Coastguard Worker     // the current level.
2293*6777b538SAndroid Build Coastguard Worker     if (IsCookieEligibleForEviction(priority, protect_secure_cookies,
2294*6777b538SAndroid Build Coastguard Worker                                     current_cookie)) {
2295*6777b538SAndroid Build Coastguard Worker       InternalDeleteCookie(cookies->at(current), true,
2296*6777b538SAndroid Build Coastguard Worker                            DELETE_COOKIE_EVICTED_DOMAIN);
2297*6777b538SAndroid Build Coastguard Worker       cookies->erase(cookies->begin() + current);
2298*6777b538SAndroid Build Coastguard Worker       removed++;
2299*6777b538SAndroid Build Coastguard Worker       cookies_count_possibly_to_be_deleted--;
2300*6777b538SAndroid Build Coastguard Worker     } else {
2301*6777b538SAndroid Build Coastguard Worker       current++;
2302*6777b538SAndroid Build Coastguard Worker     }
2303*6777b538SAndroid Build Coastguard Worker   }
2304*6777b538SAndroid Build Coastguard Worker   return removed;
2305*6777b538SAndroid Build Coastguard Worker }
2306*6777b538SAndroid Build Coastguard Worker 
PurgeLeastRecentMatchesForOBC(CookieItList * cookies,CookiePriority priority,size_t to_protect,size_t purge_goal,bool delete_secure_cookies)2307*6777b538SAndroid Build Coastguard Worker size_t CookieMonster::PurgeLeastRecentMatchesForOBC(
2308*6777b538SAndroid Build Coastguard Worker     CookieItList* cookies,
2309*6777b538SAndroid Build Coastguard Worker     CookiePriority priority,
2310*6777b538SAndroid Build Coastguard Worker     size_t to_protect,
2311*6777b538SAndroid Build Coastguard Worker     size_t purge_goal,
2312*6777b538SAndroid Build Coastguard Worker     bool delete_secure_cookies) {
2313*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2314*6777b538SAndroid Build Coastguard Worker 
2315*6777b538SAndroid Build Coastguard Worker   // 1. Count number of the cookies at `priority`. Includes both secure and
2316*6777b538SAndroid Build Coastguard Worker   // non-secure cookies.
2317*6777b538SAndroid Build Coastguard Worker   DeletionCookieLists could_be_deleted;
2318*6777b538SAndroid Build Coastguard Worker   size_t total_could_be_deleted_for_priority =
2319*6777b538SAndroid Build Coastguard Worker       CountCookiesAndGenerateListsForPossibleDeletion(
2320*6777b538SAndroid Build Coastguard Worker           priority, could_be_deleted, cookies, delete_secure_cookies);
2321*6777b538SAndroid Build Coastguard Worker 
2322*6777b538SAndroid Build Coastguard Worker   // 2. If we have fewer cookies at this priority than we intend to keep/protect
2323*6777b538SAndroid Build Coastguard Worker   // then just skip this round entirely.
2324*6777b538SAndroid Build Coastguard Worker   if (total_could_be_deleted_for_priority <= to_protect) {
2325*6777b538SAndroid Build Coastguard Worker     return 0u;
2326*6777b538SAndroid Build Coastguard Worker   }
2327*6777b538SAndroid Build Coastguard Worker 
2328*6777b538SAndroid Build Coastguard Worker   // 3. Calculate the number of cookies that could be deleted for this round.
2329*6777b538SAndroid Build Coastguard Worker   // This number is the lesser of either: The number of cookies that exist at
2330*6777b538SAndroid Build Coastguard Worker   // this {priority, secureness} tuple, or the number of cookies at this
2331*6777b538SAndroid Build Coastguard Worker   // priority less the number to protect. We won't exceed the `purge_goal` even
2332*6777b538SAndroid Build Coastguard Worker   // if this resulting value is larger.
2333*6777b538SAndroid Build Coastguard Worker   size_t total_deletable = could_be_deleted.host_cookies.size() +
2334*6777b538SAndroid Build Coastguard Worker                            could_be_deleted.domain_cookies.size();
2335*6777b538SAndroid Build Coastguard Worker   size_t max_cookies_to_delete_this_round = std::min(
2336*6777b538SAndroid Build Coastguard Worker       total_deletable, total_could_be_deleted_for_priority - to_protect);
2337*6777b538SAndroid Build Coastguard Worker 
2338*6777b538SAndroid Build Coastguard Worker   // 4. Remove domain cookies. As per "Origin-Bound Cookies" behavior, domain
2339*6777b538SAndroid Build Coastguard Worker   // cookies should always be deleted before host cookies.
2340*6777b538SAndroid Build Coastguard Worker   size_t removed = 0u;
2341*6777b538SAndroid Build Coastguard Worker   // At this point we have 3 layers of iterators to consider:
2342*6777b538SAndroid Build Coastguard Worker   // * The `could_be_deleted` list's iterator, which points to...
2343*6777b538SAndroid Build Coastguard Worker   // * The `cookies` list's iterator, which points to...
2344*6777b538SAndroid Build Coastguard Worker   // * The CookieMap's iterator which is used to delete the actual cookie from
2345*6777b538SAndroid Build Coastguard Worker   // the backend.
2346*6777b538SAndroid Build Coastguard Worker   // For each cookie deleted all three of these will need to erased, in a bottom
2347*6777b538SAndroid Build Coastguard Worker   // up approach.
2348*6777b538SAndroid Build Coastguard Worker   for (auto domain_list_it = could_be_deleted.domain_cookies.begin();
2349*6777b538SAndroid Build Coastguard Worker        domain_list_it != could_be_deleted.domain_cookies.end() &&
2350*6777b538SAndroid Build Coastguard Worker        removed < purge_goal && max_cookies_to_delete_this_round > 0;) {
2351*6777b538SAndroid Build Coastguard Worker     auto cookies_list_it = *domain_list_it;
2352*6777b538SAndroid Build Coastguard Worker     auto cookie_map_it = *cookies_list_it;
2353*6777b538SAndroid Build Coastguard Worker     // Delete from the cookie store.
2354*6777b538SAndroid Build Coastguard Worker     InternalDeleteCookie(cookie_map_it, /*sync_to_store=*/true,
2355*6777b538SAndroid Build Coastguard Worker                          DELETE_COOKIE_EVICTED_DOMAIN);
2356*6777b538SAndroid Build Coastguard Worker     // Delete from `cookies`.
2357*6777b538SAndroid Build Coastguard Worker     cookies->erase(cookies_list_it);
2358*6777b538SAndroid Build Coastguard Worker     // Delete from `could_be_deleted`.
2359*6777b538SAndroid Build Coastguard Worker     domain_list_it = could_be_deleted.domain_cookies.erase(domain_list_it);
2360*6777b538SAndroid Build Coastguard Worker 
2361*6777b538SAndroid Build Coastguard Worker     max_cookies_to_delete_this_round--;
2362*6777b538SAndroid Build Coastguard Worker     removed++;
2363*6777b538SAndroid Build Coastguard Worker   }
2364*6777b538SAndroid Build Coastguard Worker 
2365*6777b538SAndroid Build Coastguard Worker   // 5. Remove host cookies
2366*6777b538SAndroid Build Coastguard Worker   for (auto host_list_it = could_be_deleted.host_cookies.begin();
2367*6777b538SAndroid Build Coastguard Worker        host_list_it != could_be_deleted.host_cookies.end() &&
2368*6777b538SAndroid Build Coastguard Worker        removed < purge_goal && max_cookies_to_delete_this_round > 0;) {
2369*6777b538SAndroid Build Coastguard Worker     auto cookies_list_it = *host_list_it;
2370*6777b538SAndroid Build Coastguard Worker     auto cookie_map_it = *cookies_list_it;
2371*6777b538SAndroid Build Coastguard Worker     // Delete from the cookie store.
2372*6777b538SAndroid Build Coastguard Worker     InternalDeleteCookie(cookie_map_it, /*sync_to_store=*/true,
2373*6777b538SAndroid Build Coastguard Worker                          DELETE_COOKIE_EVICTED_DOMAIN);
2374*6777b538SAndroid Build Coastguard Worker     // Delete from `cookies`.
2375*6777b538SAndroid Build Coastguard Worker     cookies->erase(cookies_list_it);
2376*6777b538SAndroid Build Coastguard Worker     // Delete from `could_be_deleted`.
2377*6777b538SAndroid Build Coastguard Worker     host_list_it = could_be_deleted.host_cookies.erase(host_list_it);
2378*6777b538SAndroid Build Coastguard Worker 
2379*6777b538SAndroid Build Coastguard Worker     max_cookies_to_delete_this_round--;
2380*6777b538SAndroid Build Coastguard Worker     removed++;
2381*6777b538SAndroid Build Coastguard Worker   }
2382*6777b538SAndroid Build Coastguard Worker   return removed;
2383*6777b538SAndroid Build Coastguard Worker }
2384*6777b538SAndroid Build Coastguard Worker 
GarbageCollectExpired(const Time & current,const CookieMapItPair & itpair,CookieItVector * cookie_its)2385*6777b538SAndroid Build Coastguard Worker size_t CookieMonster::GarbageCollectExpired(const Time& current,
2386*6777b538SAndroid Build Coastguard Worker                                             const CookieMapItPair& itpair,
2387*6777b538SAndroid Build Coastguard Worker                                             CookieItVector* cookie_its) {
2388*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2389*6777b538SAndroid Build Coastguard Worker 
2390*6777b538SAndroid Build Coastguard Worker   int num_deleted = 0;
2391*6777b538SAndroid Build Coastguard Worker   for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) {
2392*6777b538SAndroid Build Coastguard Worker     auto curit = it;
2393*6777b538SAndroid Build Coastguard Worker     ++it;
2394*6777b538SAndroid Build Coastguard Worker 
2395*6777b538SAndroid Build Coastguard Worker     if (curit->second->IsExpired(current)) {
2396*6777b538SAndroid Build Coastguard Worker       InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
2397*6777b538SAndroid Build Coastguard Worker       ++num_deleted;
2398*6777b538SAndroid Build Coastguard Worker     } else if (cookie_its) {
2399*6777b538SAndroid Build Coastguard Worker       cookie_its->push_back(curit);
2400*6777b538SAndroid Build Coastguard Worker     }
2401*6777b538SAndroid Build Coastguard Worker   }
2402*6777b538SAndroid Build Coastguard Worker 
2403*6777b538SAndroid Build Coastguard Worker   return num_deleted;
2404*6777b538SAndroid Build Coastguard Worker }
2405*6777b538SAndroid Build Coastguard Worker 
GarbageCollectExpiredPartitionedCookies(const Time & current,const PartitionedCookieMap::iterator & cookie_partition_it,const CookieMapItPair & itpair,CookieItVector * cookie_its)2406*6777b538SAndroid Build Coastguard Worker size_t CookieMonster::GarbageCollectExpiredPartitionedCookies(
2407*6777b538SAndroid Build Coastguard Worker     const Time& current,
2408*6777b538SAndroid Build Coastguard Worker     const PartitionedCookieMap::iterator& cookie_partition_it,
2409*6777b538SAndroid Build Coastguard Worker     const CookieMapItPair& itpair,
2410*6777b538SAndroid Build Coastguard Worker     CookieItVector* cookie_its) {
2411*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2412*6777b538SAndroid Build Coastguard Worker 
2413*6777b538SAndroid Build Coastguard Worker   int num_deleted = 0;
2414*6777b538SAndroid Build Coastguard Worker   for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) {
2415*6777b538SAndroid Build Coastguard Worker     auto curit = it;
2416*6777b538SAndroid Build Coastguard Worker     ++it;
2417*6777b538SAndroid Build Coastguard Worker 
2418*6777b538SAndroid Build Coastguard Worker     if (curit->second->IsExpired(current)) {
2419*6777b538SAndroid Build Coastguard Worker       InternalDeletePartitionedCookie(cookie_partition_it, curit, true,
2420*6777b538SAndroid Build Coastguard Worker                                       DELETE_COOKIE_EXPIRED);
2421*6777b538SAndroid Build Coastguard Worker       ++num_deleted;
2422*6777b538SAndroid Build Coastguard Worker     } else if (cookie_its) {
2423*6777b538SAndroid Build Coastguard Worker       cookie_its->push_back(curit);
2424*6777b538SAndroid Build Coastguard Worker     }
2425*6777b538SAndroid Build Coastguard Worker   }
2426*6777b538SAndroid Build Coastguard Worker 
2427*6777b538SAndroid Build Coastguard Worker   return num_deleted;
2428*6777b538SAndroid Build Coastguard Worker }
2429*6777b538SAndroid Build Coastguard Worker 
GarbageCollectAllExpiredPartitionedCookies(const Time & current)2430*6777b538SAndroid Build Coastguard Worker void CookieMonster::GarbageCollectAllExpiredPartitionedCookies(
2431*6777b538SAndroid Build Coastguard Worker     const Time& current) {
2432*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2433*6777b538SAndroid Build Coastguard Worker   for (auto it = partitioned_cookies_.begin();
2434*6777b538SAndroid Build Coastguard Worker        it != partitioned_cookies_.end();) {
2435*6777b538SAndroid Build Coastguard Worker     // GarbageCollectExpiredPartitionedCookies calls
2436*6777b538SAndroid Build Coastguard Worker     // InternalDeletePartitionedCookie which may invalidate
2437*6777b538SAndroid Build Coastguard Worker     // |cur_cookie_partition_it|.
2438*6777b538SAndroid Build Coastguard Worker     auto cur_cookie_partition_it = it;
2439*6777b538SAndroid Build Coastguard Worker     ++it;
2440*6777b538SAndroid Build Coastguard Worker     GarbageCollectExpiredPartitionedCookies(
2441*6777b538SAndroid Build Coastguard Worker         current, cur_cookie_partition_it,
2442*6777b538SAndroid Build Coastguard Worker         CookieMapItPair(cur_cookie_partition_it->second->begin(),
2443*6777b538SAndroid Build Coastguard Worker                         cur_cookie_partition_it->second->end()),
2444*6777b538SAndroid Build Coastguard Worker         nullptr /*cookie_its*/);
2445*6777b538SAndroid Build Coastguard Worker   }
2446*6777b538SAndroid Build Coastguard Worker }
2447*6777b538SAndroid Build Coastguard Worker 
GarbageCollectDeleteRange(const Time & current,DeletionCause cause,CookieItVector::iterator it_begin,CookieItVector::iterator it_end)2448*6777b538SAndroid Build Coastguard Worker size_t CookieMonster::GarbageCollectDeleteRange(
2449*6777b538SAndroid Build Coastguard Worker     const Time& current,
2450*6777b538SAndroid Build Coastguard Worker     DeletionCause cause,
2451*6777b538SAndroid Build Coastguard Worker     CookieItVector::iterator it_begin,
2452*6777b538SAndroid Build Coastguard Worker     CookieItVector::iterator it_end) {
2453*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2454*6777b538SAndroid Build Coastguard Worker 
2455*6777b538SAndroid Build Coastguard Worker   for (auto it = it_begin; it != it_end; it++) {
2456*6777b538SAndroid Build Coastguard Worker     InternalDeleteCookie((*it), true, cause);
2457*6777b538SAndroid Build Coastguard Worker   }
2458*6777b538SAndroid Build Coastguard Worker   return it_end - it_begin;
2459*6777b538SAndroid Build Coastguard Worker }
2460*6777b538SAndroid Build Coastguard Worker 
GarbageCollectLeastRecentlyAccessed(const base::Time & current,const base::Time & safe_date,size_t purge_goal,CookieItVector cookie_its,base::Time * earliest_time)2461*6777b538SAndroid Build Coastguard Worker size_t CookieMonster::GarbageCollectLeastRecentlyAccessed(
2462*6777b538SAndroid Build Coastguard Worker     const base::Time& current,
2463*6777b538SAndroid Build Coastguard Worker     const base::Time& safe_date,
2464*6777b538SAndroid Build Coastguard Worker     size_t purge_goal,
2465*6777b538SAndroid Build Coastguard Worker     CookieItVector cookie_its,
2466*6777b538SAndroid Build Coastguard Worker     base::Time* earliest_time) {
2467*6777b538SAndroid Build Coastguard Worker   DCHECK_LE(purge_goal, cookie_its.size());
2468*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2469*6777b538SAndroid Build Coastguard Worker 
2470*6777b538SAndroid Build Coastguard Worker   // Sorts up to *and including* |cookie_its[purge_goal]| (if it exists), so
2471*6777b538SAndroid Build Coastguard Worker   // |earliest_time| will be properly assigned even if
2472*6777b538SAndroid Build Coastguard Worker   // |global_purge_it| == |cookie_its.begin() + purge_goal|.
2473*6777b538SAndroid Build Coastguard Worker   SortLeastRecentlyAccessed(
2474*6777b538SAndroid Build Coastguard Worker       cookie_its.begin(), cookie_its.end(),
2475*6777b538SAndroid Build Coastguard Worker       cookie_its.size() < purge_goal ? purge_goal + 1 : purge_goal);
2476*6777b538SAndroid Build Coastguard Worker   // Find boundary to cookies older than safe_date.
2477*6777b538SAndroid Build Coastguard Worker   auto global_purge_it = LowerBoundAccessDate(
2478*6777b538SAndroid Build Coastguard Worker       cookie_its.begin(), cookie_its.begin() + purge_goal, safe_date);
2479*6777b538SAndroid Build Coastguard Worker   // Only delete the old cookies and delete non-secure ones first.
2480*6777b538SAndroid Build Coastguard Worker   size_t num_deleted =
2481*6777b538SAndroid Build Coastguard Worker       GarbageCollectDeleteRange(current, DELETE_COOKIE_EVICTED_GLOBAL,
2482*6777b538SAndroid Build Coastguard Worker                                 cookie_its.begin(), global_purge_it);
2483*6777b538SAndroid Build Coastguard Worker   if (global_purge_it != cookie_its.end())
2484*6777b538SAndroid Build Coastguard Worker     *earliest_time = (*global_purge_it)->second->LastAccessDate();
2485*6777b538SAndroid Build Coastguard Worker   return num_deleted;
2486*6777b538SAndroid Build Coastguard Worker }
2487*6777b538SAndroid Build Coastguard Worker 
2488*6777b538SAndroid Build Coastguard Worker // A wrapper around registry_controlled_domains::GetDomainAndRegistry
2489*6777b538SAndroid Build Coastguard Worker // to make clear we're creating a key for our local map or for the persistent
2490*6777b538SAndroid Build Coastguard Worker // store's use. Here and in FindCookiesForRegistryControlledHost() are the only
2491*6777b538SAndroid Build Coastguard Worker // two places where we need to conditionalize based on key type.
2492*6777b538SAndroid Build Coastguard Worker //
2493*6777b538SAndroid Build Coastguard Worker // Note that this key algorithm explicitly ignores the scheme.  This is
2494*6777b538SAndroid Build Coastguard Worker // because when we're entering cookies into the map from the backing store,
2495*6777b538SAndroid Build Coastguard Worker // we in general won't have the scheme at that point.
2496*6777b538SAndroid Build Coastguard Worker // In practical terms, this means that file cookies will be stored
2497*6777b538SAndroid Build Coastguard Worker // in the map either by an empty string or by UNC name (and will be
2498*6777b538SAndroid Build Coastguard Worker // limited by kMaxCookiesPerHost), and extension cookies will be stored
2499*6777b538SAndroid Build Coastguard Worker // based on the single extension id, as the extension id won't have the
2500*6777b538SAndroid Build Coastguard Worker // form of a DNS host and hence GetKey() will return it unchanged.
2501*6777b538SAndroid Build Coastguard Worker //
2502*6777b538SAndroid Build Coastguard Worker // Arguably the right thing to do here is to make the key
2503*6777b538SAndroid Build Coastguard Worker // algorithm dependent on the scheme, and make sure that the scheme is
2504*6777b538SAndroid Build Coastguard Worker // available everywhere the key must be obtained (specfically at backing
2505*6777b538SAndroid Build Coastguard Worker // store load time).  This would require either changing the backing store
2506*6777b538SAndroid Build Coastguard Worker // database schema to include the scheme (far more trouble than it's worth), or
2507*6777b538SAndroid Build Coastguard Worker // separating out file cookies into their own CookieMonster instance and
2508*6777b538SAndroid Build Coastguard Worker // thus restricting each scheme to a single cookie monster (which might
2509*6777b538SAndroid Build Coastguard Worker // be worth it, but is still too much trouble to solve what is currently a
2510*6777b538SAndroid Build Coastguard Worker // non-problem).
2511*6777b538SAndroid Build Coastguard Worker //
2512*6777b538SAndroid Build Coastguard Worker // static
GetKey(std::string_view domain)2513*6777b538SAndroid Build Coastguard Worker std::string CookieMonster::GetKey(std::string_view domain) {
2514*6777b538SAndroid Build Coastguard Worker   std::string effective_domain(
2515*6777b538SAndroid Build Coastguard Worker       registry_controlled_domains::GetDomainAndRegistry(
2516*6777b538SAndroid Build Coastguard Worker           domain, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES));
2517*6777b538SAndroid Build Coastguard Worker   if (effective_domain.empty())
2518*6777b538SAndroid Build Coastguard Worker     effective_domain = std::string(domain);
2519*6777b538SAndroid Build Coastguard Worker 
2520*6777b538SAndroid Build Coastguard Worker   return cookie_util::CookieDomainAsHost(effective_domain);
2521*6777b538SAndroid Build Coastguard Worker }
2522*6777b538SAndroid Build Coastguard Worker 
HasCookieableScheme(const GURL & url)2523*6777b538SAndroid Build Coastguard Worker bool CookieMonster::HasCookieableScheme(const GURL& url) {
2524*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2525*6777b538SAndroid Build Coastguard Worker 
2526*6777b538SAndroid Build Coastguard Worker   // Make sure the request is on a cookie-able url scheme.
2527*6777b538SAndroid Build Coastguard Worker   bool is_cookieable = base::ranges::any_of(
2528*6777b538SAndroid Build Coastguard Worker       cookieable_schemes_, [&url](const std::string& cookieable_scheme) {
2529*6777b538SAndroid Build Coastguard Worker         return url.SchemeIs(cookieable_scheme.c_str());
2530*6777b538SAndroid Build Coastguard Worker       });
2531*6777b538SAndroid Build Coastguard Worker 
2532*6777b538SAndroid Build Coastguard Worker   if (!is_cookieable) {
2533*6777b538SAndroid Build Coastguard Worker     // The scheme didn't match any in our allowed list.
2534*6777b538SAndroid Build Coastguard Worker     DVLOG(net::cookie_util::kVlogPerCookieMonster)
2535*6777b538SAndroid Build Coastguard Worker         << "WARNING: Unsupported cookie scheme: " << url.scheme();
2536*6777b538SAndroid Build Coastguard Worker   }
2537*6777b538SAndroid Build Coastguard Worker   return is_cookieable;
2538*6777b538SAndroid Build Coastguard Worker }
2539*6777b538SAndroid Build Coastguard Worker 
GetAccessSemanticsForCookie(const CanonicalCookie & cookie) const2540*6777b538SAndroid Build Coastguard Worker CookieAccessSemantics CookieMonster::GetAccessSemanticsForCookie(
2541*6777b538SAndroid Build Coastguard Worker     const CanonicalCookie& cookie) const {
2542*6777b538SAndroid Build Coastguard Worker   if (cookie_access_delegate())
2543*6777b538SAndroid Build Coastguard Worker     return cookie_access_delegate()->GetAccessSemantics(cookie);
2544*6777b538SAndroid Build Coastguard Worker   return CookieAccessSemantics::UNKNOWN;
2545*6777b538SAndroid Build Coastguard Worker }
2546*6777b538SAndroid Build Coastguard Worker 
2547*6777b538SAndroid Build Coastguard Worker // Test to see if stats should be recorded, and record them if so.
2548*6777b538SAndroid Build Coastguard Worker // The goal here is to get sampling for the average browser-hour of
2549*6777b538SAndroid Build Coastguard Worker // activity.  We won't take samples when the web isn't being surfed,
2550*6777b538SAndroid Build Coastguard Worker // and when the web is being surfed, we'll take samples about every
2551*6777b538SAndroid Build Coastguard Worker // kRecordStatisticsIntervalSeconds.
2552*6777b538SAndroid Build Coastguard Worker // last_statistic_record_time_ is initialized to Now() rather than null
2553*6777b538SAndroid Build Coastguard Worker // in the constructor so that we won't take statistics right after
2554*6777b538SAndroid Build Coastguard Worker // startup, to avoid bias from browsers that are started but not used.
RecordPeriodicStats(const base::Time & current_time)2555*6777b538SAndroid Build Coastguard Worker void CookieMonster::RecordPeriodicStats(const base::Time& current_time) {
2556*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2557*6777b538SAndroid Build Coastguard Worker 
2558*6777b538SAndroid Build Coastguard Worker   const base::TimeDelta kRecordStatisticsIntervalTime(
2559*6777b538SAndroid Build Coastguard Worker       base::Seconds(kRecordStatisticsIntervalSeconds));
2560*6777b538SAndroid Build Coastguard Worker 
2561*6777b538SAndroid Build Coastguard Worker   // If we've taken statistics recently, return.
2562*6777b538SAndroid Build Coastguard Worker   if (current_time - last_statistic_record_time_ <=
2563*6777b538SAndroid Build Coastguard Worker       kRecordStatisticsIntervalTime) {
2564*6777b538SAndroid Build Coastguard Worker     return;
2565*6777b538SAndroid Build Coastguard Worker   }
2566*6777b538SAndroid Build Coastguard Worker 
2567*6777b538SAndroid Build Coastguard Worker   if (DoRecordPeriodicStats())
2568*6777b538SAndroid Build Coastguard Worker     last_statistic_record_time_ = current_time;
2569*6777b538SAndroid Build Coastguard Worker }
2570*6777b538SAndroid Build Coastguard Worker 
DoRecordPeriodicStats()2571*6777b538SAndroid Build Coastguard Worker bool CookieMonster::DoRecordPeriodicStats() {
2572*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2573*6777b538SAndroid Build Coastguard Worker 
2574*6777b538SAndroid Build Coastguard Worker   SCOPED_UMA_HISTOGRAM_TIMER("Cookie.TimeToRecordPeriodicStats");
2575*6777b538SAndroid Build Coastguard Worker 
2576*6777b538SAndroid Build Coastguard Worker   // These values are all bogus if we have only partially loaded the cookies.
2577*6777b538SAndroid Build Coastguard Worker   if (started_fetching_all_cookies_ && !finished_fetching_all_cookies_)
2578*6777b538SAndroid Build Coastguard Worker     return false;
2579*6777b538SAndroid Build Coastguard Worker 
2580*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramCounts100000("Cookie.Count2", cookies_.size());
2581*6777b538SAndroid Build Coastguard Worker 
2582*6777b538SAndroid Build Coastguard Worker   if (cookie_access_delegate()) {
2583*6777b538SAndroid Build Coastguard Worker     std::vector<SchemefulSite> sites;
2584*6777b538SAndroid Build Coastguard Worker     for (const auto& entry : cookies_) {
2585*6777b538SAndroid Build Coastguard Worker       sites.emplace_back(
2586*6777b538SAndroid Build Coastguard Worker           GURL(base::StrCat({url::kHttpsScheme, "://", entry.first})));
2587*6777b538SAndroid Build Coastguard Worker     }
2588*6777b538SAndroid Build Coastguard Worker     for (const auto& [partition_key, cookie_map] : partitioned_cookies_) {
2589*6777b538SAndroid Build Coastguard Worker       for (const auto& [domain, unused_cookie] : *cookie_map) {
2590*6777b538SAndroid Build Coastguard Worker         sites.emplace_back(
2591*6777b538SAndroid Build Coastguard Worker             GURL(base::StrCat({url::kHttpsScheme, "://", domain})));
2592*6777b538SAndroid Build Coastguard Worker       }
2593*6777b538SAndroid Build Coastguard Worker     }
2594*6777b538SAndroid Build Coastguard Worker     std::optional<base::flat_map<SchemefulSite, FirstPartySetEntry>>
2595*6777b538SAndroid Build Coastguard Worker         maybe_sets = cookie_access_delegate()->FindFirstPartySetEntries(
2596*6777b538SAndroid Build Coastguard Worker             sites,
2597*6777b538SAndroid Build Coastguard Worker             base::BindOnce(&CookieMonster::RecordPeriodicFirstPartySetsStats,
2598*6777b538SAndroid Build Coastguard Worker                            weak_ptr_factory_.GetWeakPtr()));
2599*6777b538SAndroid Build Coastguard Worker     if (maybe_sets.has_value())
2600*6777b538SAndroid Build Coastguard Worker       RecordPeriodicFirstPartySetsStats(maybe_sets.value());
2601*6777b538SAndroid Build Coastguard Worker   }
2602*6777b538SAndroid Build Coastguard Worker 
2603*6777b538SAndroid Build Coastguard Worker   // Can be up to kMaxCookies.
2604*6777b538SAndroid Build Coastguard Worker   UMA_HISTOGRAM_COUNTS_10000("Cookie.NumKeys", num_keys_);
2605*6777b538SAndroid Build Coastguard Worker 
2606*6777b538SAndroid Build Coastguard Worker   std::map<std::string, size_t> n_same_site_none_cookies;
2607*6777b538SAndroid Build Coastguard Worker   size_t n_bytes = 0;
2608*6777b538SAndroid Build Coastguard Worker   std::map<std::string, size_t> n_bytes_per_key;
2609*6777b538SAndroid Build Coastguard Worker 
2610*6777b538SAndroid Build Coastguard Worker   for (const auto& [host_key, host_cookie] : cookies_) {
2611*6777b538SAndroid Build Coastguard Worker     size_t cookie_n_bytes = NameValueSizeBytes(*host_cookie);
2612*6777b538SAndroid Build Coastguard Worker     n_bytes += cookie_n_bytes;
2613*6777b538SAndroid Build Coastguard Worker     n_bytes_per_key[host_key] += cookie_n_bytes;
2614*6777b538SAndroid Build Coastguard Worker 
2615*6777b538SAndroid Build Coastguard Worker     if (!host_cookie || !host_cookie->IsEffectivelySameSiteNone())
2616*6777b538SAndroid Build Coastguard Worker       continue;
2617*6777b538SAndroid Build Coastguard Worker     n_same_site_none_cookies[host_key]++;
2618*6777b538SAndroid Build Coastguard Worker   }
2619*6777b538SAndroid Build Coastguard Worker 
2620*6777b538SAndroid Build Coastguard Worker   size_t max_n_cookies = 0;
2621*6777b538SAndroid Build Coastguard Worker   for (const auto& entry : n_same_site_none_cookies) {
2622*6777b538SAndroid Build Coastguard Worker     max_n_cookies = std::max(max_n_cookies, entry.second);
2623*6777b538SAndroid Build Coastguard Worker   }
2624*6777b538SAndroid Build Coastguard Worker   size_t max_n_bytes = 0;
2625*6777b538SAndroid Build Coastguard Worker   for (const auto& entry : n_bytes_per_key) {
2626*6777b538SAndroid Build Coastguard Worker     max_n_bytes = std::max(max_n_bytes, entry.second);
2627*6777b538SAndroid Build Coastguard Worker   }
2628*6777b538SAndroid Build Coastguard Worker 
2629*6777b538SAndroid Build Coastguard Worker   // Can be up to 180 cookies, the max per-domain.
2630*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramCounts1000("Cookie.MaxSameSiteNoneCookiesPerKey",
2631*6777b538SAndroid Build Coastguard Worker                                max_n_cookies);
2632*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramCounts100000("Cookie.CookieJarSize", n_bytes >> 10);
2633*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramCounts100000(
2634*6777b538SAndroid Build Coastguard Worker       "Cookie.AvgCookieJarSizePerKey",
2635*6777b538SAndroid Build Coastguard Worker       (n_bytes >> 10) / std::max(num_keys_, static_cast<size_t>(1)));
2636*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramCounts100000("Cookie.MaxCookieJarSizePerKey",
2637*6777b538SAndroid Build Coastguard Worker                                  max_n_bytes >> 10);
2638*6777b538SAndroid Build Coastguard Worker 
2639*6777b538SAndroid Build Coastguard Worker   // Collect stats for partitioned cookies.
2640*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramCounts1000("Cookie.PartitionCount",
2641*6777b538SAndroid Build Coastguard Worker                                partitioned_cookies_.size());
2642*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramCounts100000("Cookie.PartitionedCookieCount",
2643*6777b538SAndroid Build Coastguard Worker                                  num_partitioned_cookies_);
2644*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramCounts100000("Cookie.PartitionedCookieCount.Nonced",
2645*6777b538SAndroid Build Coastguard Worker                                  num_nonced_partitioned_cookies_);
2646*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramCounts100000(
2647*6777b538SAndroid Build Coastguard Worker       "Cookie.PartitionedCookieCount.Unnonced",
2648*6777b538SAndroid Build Coastguard Worker       num_partitioned_cookies_ - num_nonced_partitioned_cookies_);
2649*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramCounts100000("Cookie.PartitionedCookieJarSizeKibibytes",
2650*6777b538SAndroid Build Coastguard Worker                                  num_partitioned_cookies_bytes_ >> 10);
2651*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramCounts100000(
2652*6777b538SAndroid Build Coastguard Worker       "Cookie.PartitionedCookieJarSizeKibibytes.Nonced",
2653*6777b538SAndroid Build Coastguard Worker       num_nonced_partitioned_cookie_bytes_ >> 10);
2654*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramCounts100000(
2655*6777b538SAndroid Build Coastguard Worker       "Cookie.PartitionedCookieJarSizeKibibytes.Unnonced",
2656*6777b538SAndroid Build Coastguard Worker       (num_partitioned_cookies_bytes_ - num_nonced_partitioned_cookie_bytes_) >>
2657*6777b538SAndroid Build Coastguard Worker           10);
2658*6777b538SAndroid Build Coastguard Worker 
2659*6777b538SAndroid Build Coastguard Worker   for (const auto& it : bytes_per_cookie_partition_) {
2660*6777b538SAndroid Build Coastguard Worker     base::UmaHistogramCounts100000("Cookie.CookiePartitionSizeKibibytes",
2661*6777b538SAndroid Build Coastguard Worker                                    it.second >> 10);
2662*6777b538SAndroid Build Coastguard Worker   }
2663*6777b538SAndroid Build Coastguard Worker 
2664*6777b538SAndroid Build Coastguard Worker   return true;
2665*6777b538SAndroid Build Coastguard Worker }
2666*6777b538SAndroid Build Coastguard Worker 
RecordPeriodicFirstPartySetsStats(base::flat_map<SchemefulSite,FirstPartySetEntry> sets) const2667*6777b538SAndroid Build Coastguard Worker void CookieMonster::RecordPeriodicFirstPartySetsStats(
2668*6777b538SAndroid Build Coastguard Worker     base::flat_map<SchemefulSite, FirstPartySetEntry> sets) const {
2669*6777b538SAndroid Build Coastguard Worker   base::flat_map<SchemefulSite, std::set<SchemefulSite>> grouped_by_owner;
2670*6777b538SAndroid Build Coastguard Worker   for (const auto& [site, entry] : sets) {
2671*6777b538SAndroid Build Coastguard Worker     grouped_by_owner[entry.primary()].insert(site);
2672*6777b538SAndroid Build Coastguard Worker   }
2673*6777b538SAndroid Build Coastguard Worker   for (const auto& set : grouped_by_owner) {
2674*6777b538SAndroid Build Coastguard Worker     int sample = std::accumulate(
2675*6777b538SAndroid Build Coastguard Worker         set.second.begin(), set.second.end(), 0,
2676*6777b538SAndroid Build Coastguard Worker         [this](int acc, const net::SchemefulSite& site) -> int {
2677*6777b538SAndroid Build Coastguard Worker           DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2678*6777b538SAndroid Build Coastguard Worker           if (!site.has_registrable_domain_or_host())
2679*6777b538SAndroid Build Coastguard Worker             return acc;
2680*6777b538SAndroid Build Coastguard Worker           return acc + cookies_.count(GetKey(site.GetURL().host()));
2681*6777b538SAndroid Build Coastguard Worker         });
2682*6777b538SAndroid Build Coastguard Worker     base::UmaHistogramCustomCounts("Cookie.PerFirstPartySetCount", sample, 0,
2683*6777b538SAndroid Build Coastguard Worker                                    4000, 50);
2684*6777b538SAndroid Build Coastguard Worker   }
2685*6777b538SAndroid Build Coastguard Worker }
2686*6777b538SAndroid Build Coastguard Worker 
DoCookieCallback(base::OnceClosure callback)2687*6777b538SAndroid Build Coastguard Worker void CookieMonster::DoCookieCallback(base::OnceClosure callback) {
2688*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2689*6777b538SAndroid Build Coastguard Worker 
2690*6777b538SAndroid Build Coastguard Worker   MarkCookieStoreAsInitialized();
2691*6777b538SAndroid Build Coastguard Worker   FetchAllCookiesIfNecessary();
2692*6777b538SAndroid Build Coastguard Worker   seen_global_task_ = true;
2693*6777b538SAndroid Build Coastguard Worker 
2694*6777b538SAndroid Build Coastguard Worker   if (!finished_fetching_all_cookies_ && store_.get()) {
2695*6777b538SAndroid Build Coastguard Worker     tasks_pending_.push_back(std::move(callback));
2696*6777b538SAndroid Build Coastguard Worker     return;
2697*6777b538SAndroid Build Coastguard Worker   }
2698*6777b538SAndroid Build Coastguard Worker 
2699*6777b538SAndroid Build Coastguard Worker   std::move(callback).Run();
2700*6777b538SAndroid Build Coastguard Worker }
2701*6777b538SAndroid Build Coastguard Worker 
DoCookieCallbackForURL(base::OnceClosure callback,const GURL & url)2702*6777b538SAndroid Build Coastguard Worker void CookieMonster::DoCookieCallbackForURL(base::OnceClosure callback,
2703*6777b538SAndroid Build Coastguard Worker                                            const GURL& url) {
2704*6777b538SAndroid Build Coastguard Worker   DoCookieCallbackForHostOrDomain(std::move(callback), url.host_piece());
2705*6777b538SAndroid Build Coastguard Worker }
2706*6777b538SAndroid Build Coastguard Worker 
DoCookieCallbackForHostOrDomain(base::OnceClosure callback,std::string_view host_or_domain)2707*6777b538SAndroid Build Coastguard Worker void CookieMonster::DoCookieCallbackForHostOrDomain(
2708*6777b538SAndroid Build Coastguard Worker     base::OnceClosure callback,
2709*6777b538SAndroid Build Coastguard Worker     std::string_view host_or_domain) {
2710*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2711*6777b538SAndroid Build Coastguard Worker   MarkCookieStoreAsInitialized();
2712*6777b538SAndroid Build Coastguard Worker   FetchAllCookiesIfNecessary();
2713*6777b538SAndroid Build Coastguard Worker 
2714*6777b538SAndroid Build Coastguard Worker   // If cookies for the requested domain key (eTLD+1) have been loaded from DB
2715*6777b538SAndroid Build Coastguard Worker   // then run the task, otherwise load from DB.
2716*6777b538SAndroid Build Coastguard Worker   if (!finished_fetching_all_cookies_ && store_.get()) {
2717*6777b538SAndroid Build Coastguard Worker     // If a global task has been previously seen, queue the task as a global
2718*6777b538SAndroid Build Coastguard Worker     // task. Note that the CookieMonster may be in the middle of executing
2719*6777b538SAndroid Build Coastguard Worker     // the global queue, |tasks_pending_| may be empty, which is why another
2720*6777b538SAndroid Build Coastguard Worker     // bool is needed.
2721*6777b538SAndroid Build Coastguard Worker     if (seen_global_task_) {
2722*6777b538SAndroid Build Coastguard Worker       tasks_pending_.push_back(std::move(callback));
2723*6777b538SAndroid Build Coastguard Worker       return;
2724*6777b538SAndroid Build Coastguard Worker     }
2725*6777b538SAndroid Build Coastguard Worker 
2726*6777b538SAndroid Build Coastguard Worker     // Checks if the domain key has been loaded.
2727*6777b538SAndroid Build Coastguard Worker     std::string key = GetKey(host_or_domain);
2728*6777b538SAndroid Build Coastguard Worker     if (keys_loaded_.find(key) == keys_loaded_.end()) {
2729*6777b538SAndroid Build Coastguard Worker       auto it = tasks_pending_for_key_.find(key);
2730*6777b538SAndroid Build Coastguard Worker       if (it == tasks_pending_for_key_.end()) {
2731*6777b538SAndroid Build Coastguard Worker         store_->LoadCookiesForKey(
2732*6777b538SAndroid Build Coastguard Worker             key, base::BindOnce(&CookieMonster::OnKeyLoaded,
2733*6777b538SAndroid Build Coastguard Worker                                 weak_ptr_factory_.GetWeakPtr(), key));
2734*6777b538SAndroid Build Coastguard Worker         it = tasks_pending_for_key_
2735*6777b538SAndroid Build Coastguard Worker                  .emplace(key, base::circular_deque<base::OnceClosure>())
2736*6777b538SAndroid Build Coastguard Worker                  .first;
2737*6777b538SAndroid Build Coastguard Worker       }
2738*6777b538SAndroid Build Coastguard Worker       it->second.push_back(std::move(callback));
2739*6777b538SAndroid Build Coastguard Worker       return;
2740*6777b538SAndroid Build Coastguard Worker     }
2741*6777b538SAndroid Build Coastguard Worker   }
2742*6777b538SAndroid Build Coastguard Worker 
2743*6777b538SAndroid Build Coastguard Worker   std::move(callback).Run();
2744*6777b538SAndroid Build Coastguard Worker }
2745*6777b538SAndroid Build Coastguard Worker 
2746*6777b538SAndroid Build Coastguard Worker CookieMonster::CookieSentToSamePort
IsCookieSentToSamePortThatSetIt(const GURL & destination,int source_port,CookieSourceScheme source_scheme)2747*6777b538SAndroid Build Coastguard Worker CookieMonster::IsCookieSentToSamePortThatSetIt(
2748*6777b538SAndroid Build Coastguard Worker     const GURL& destination,
2749*6777b538SAndroid Build Coastguard Worker     int source_port,
2750*6777b538SAndroid Build Coastguard Worker     CookieSourceScheme source_scheme) {
2751*6777b538SAndroid Build Coastguard Worker   if (source_port == url::PORT_UNSPECIFIED)
2752*6777b538SAndroid Build Coastguard Worker     return CookieSentToSamePort::kSourcePortUnspecified;
2753*6777b538SAndroid Build Coastguard Worker 
2754*6777b538SAndroid Build Coastguard Worker   if (source_port == url::PORT_INVALID)
2755*6777b538SAndroid Build Coastguard Worker     return CookieSentToSamePort::kInvalid;
2756*6777b538SAndroid Build Coastguard Worker 
2757*6777b538SAndroid Build Coastguard Worker   int destination_port = destination.EffectiveIntPort();
2758*6777b538SAndroid Build Coastguard Worker   if (source_port == destination_port)
2759*6777b538SAndroid Build Coastguard Worker     return CookieSentToSamePort::kYes;
2760*6777b538SAndroid Build Coastguard Worker 
2761*6777b538SAndroid Build Coastguard Worker   const std::string& destination_scheme = destination.scheme();
2762*6777b538SAndroid Build Coastguard Worker   bool destination_port_is_default =
2763*6777b538SAndroid Build Coastguard Worker       url::DefaultPortForScheme(destination_scheme.c_str(),
2764*6777b538SAndroid Build Coastguard Worker                                 destination_scheme.length()) ==
2765*6777b538SAndroid Build Coastguard Worker       destination_port;
2766*6777b538SAndroid Build Coastguard Worker 
2767*6777b538SAndroid Build Coastguard Worker   // Since the source port has to be specified if we got to this point, that
2768*6777b538SAndroid Build Coastguard Worker   // means this is a newer cookie that therefore has its scheme set as well.
2769*6777b538SAndroid Build Coastguard Worker   DCHECK(source_scheme != CookieSourceScheme::kUnset);
2770*6777b538SAndroid Build Coastguard Worker   std::string source_scheme_string =
2771*6777b538SAndroid Build Coastguard Worker       source_scheme == CookieSourceScheme::kSecure
2772*6777b538SAndroid Build Coastguard Worker           ? url::kHttpsScheme
2773*6777b538SAndroid Build Coastguard Worker           : url::kHttpScheme;  // wss/ws have the same default port values as
2774*6777b538SAndroid Build Coastguard Worker                                // https/http, so it's ok that we use these.
2775*6777b538SAndroid Build Coastguard Worker 
2776*6777b538SAndroid Build Coastguard Worker   bool source_port_is_default =
2777*6777b538SAndroid Build Coastguard Worker       url::DefaultPortForScheme(source_scheme_string.c_str(),
2778*6777b538SAndroid Build Coastguard Worker                                 source_scheme_string.length()) == source_port;
2779*6777b538SAndroid Build Coastguard Worker 
2780*6777b538SAndroid Build Coastguard Worker   if (destination_port_is_default && source_port_is_default)
2781*6777b538SAndroid Build Coastguard Worker     return CookieSentToSamePort::kNoButDefault;
2782*6777b538SAndroid Build Coastguard Worker 
2783*6777b538SAndroid Build Coastguard Worker   return CookieSentToSamePort::kNo;
2784*6777b538SAndroid Build Coastguard Worker }
2785*6777b538SAndroid Build Coastguard Worker 
SiteHasCookieInOtherPartition(const net::SchemefulSite & site,const std::optional<CookiePartitionKey> & partition_key) const2786*6777b538SAndroid Build Coastguard Worker std::optional<bool> CookieMonster::SiteHasCookieInOtherPartition(
2787*6777b538SAndroid Build Coastguard Worker     const net::SchemefulSite& site,
2788*6777b538SAndroid Build Coastguard Worker     const std::optional<CookiePartitionKey>& partition_key) const {
2789*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
2790*6777b538SAndroid Build Coastguard Worker   // If the partition key is null, it implies the partitioned cookies feature is
2791*6777b538SAndroid Build Coastguard Worker   // not enabled.
2792*6777b538SAndroid Build Coastguard Worker   if (!partition_key)
2793*6777b538SAndroid Build Coastguard Worker     return std::nullopt;
2794*6777b538SAndroid Build Coastguard Worker 
2795*6777b538SAndroid Build Coastguard Worker   std::string domain = site.GetURL().host();
2796*6777b538SAndroid Build Coastguard Worker   if (store_ && !finished_fetching_all_cookies_ &&
2797*6777b538SAndroid Build Coastguard Worker       !keys_loaded_.count(domain)) {
2798*6777b538SAndroid Build Coastguard Worker     return std::nullopt;
2799*6777b538SAndroid Build Coastguard Worker   }
2800*6777b538SAndroid Build Coastguard Worker 
2801*6777b538SAndroid Build Coastguard Worker   for (const auto& it : partitioned_cookies_) {
2802*6777b538SAndroid Build Coastguard Worker     if (it.first == partition_key || CookiePartitionKey::HasNonce(it.first))
2803*6777b538SAndroid Build Coastguard Worker       continue;
2804*6777b538SAndroid Build Coastguard Worker     if (it.second->find(domain) != it.second->end()) {
2805*6777b538SAndroid Build Coastguard Worker       return true;
2806*6777b538SAndroid Build Coastguard Worker     }
2807*6777b538SAndroid Build Coastguard Worker   }
2808*6777b538SAndroid Build Coastguard Worker   return false;
2809*6777b538SAndroid Build Coastguard Worker }
2810*6777b538SAndroid Build Coastguard Worker 
2811*6777b538SAndroid Build Coastguard Worker }  // namespace net
2812