blob: 5772e2ac6eb7754ee5eb78bafb31cfc34e396b89 [file] [log] [blame]
[email protected]8e1583672012-02-11 04:39:411// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit586acc5fe2008-07-26 22:42:524
5// Portions of this code based on Mozilla:
6// (netwerk/cookie/src/nsCookieService.cpp)
7/* ***** BEGIN LICENSE BLOCK *****
8 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
9 *
10 * The contents of this file are subject to the Mozilla Public License Version
11 * 1.1 (the "License"); you may not use this file except in compliance with
12 * the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
14 *
15 * Software distributed under the License is distributed on an "AS IS" basis,
16 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
17 * for the specific language governing rights and limitations under the
18 * License.
19 *
20 * The Original Code is mozilla.org code.
21 *
22 * The Initial Developer of the Original Code is
23 * Netscape Communications Corporation.
24 * Portions created by the Initial Developer are Copyright (C) 2003
25 * the Initial Developer. All Rights Reserved.
26 *
27 * Contributor(s):
28 * Daniel Witte ([email protected])
29 * Michiel van Leeuwen ([email protected])
30 *
31 * Alternatively, the contents of this file may be used under the terms of
32 * either the GNU General Public License Version 2 or later (the "GPL"), or
33 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
34 * in which case the provisions of the GPL or the LGPL are applicable instead
35 * of those above. If you wish to allow use of your version of this file only
36 * under the terms of either the GPL or the LGPL, and not to allow others to
37 * use your version of this file under the terms of the MPL, indicate your
38 * decision by deleting the provisions above and replace them with the notice
39 * and other provisions required by the GPL or the LGPL. If you do not delete
40 * the provisions above, a recipient may use your version of this file under
41 * the terms of any one of the MPL, the GPL or the LGPL.
42 *
43 * ***** END LICENSE BLOCK ***** */
44
[email protected]63ee33bd2012-03-15 09:29:5845#include "net/cookies/cookie_monster.h"
initial.commit586acc5fe2008-07-26 22:42:5246
[email protected]8ad5d462013-05-02 08:45:2647#include <functional>
[email protected]09666482011-07-12 12:50:4048#include <set>
initial.commit586acc5fe2008-07-26 22:42:5249
[email protected]218aa6a12011-09-13 17:38:3850#include "base/bind.h"
[email protected]85620342011-10-17 17:35:0451#include "base/callback.h"
Lily Chen8a648cb72019-04-25 20:29:1552#include "base/feature_list.h"
skyostil4891b25b2015-06-11 11:43:4553#include "base/location.h"
initial.commit586acc5fe2008-07-26 22:42:5254#include "base/logging.h"
Avi Drissman13fc8932015-12-20 04:40:4655#include "base/macros.h"
erikchen1dd72a72015-05-06 20:45:0556#include "base/metrics/field_trial.h"
[email protected]835d7c82010-10-14 04:38:3857#include "base/metrics/histogram.h"
Ken Rockotc2048612018-03-29 01:43:3258#include "base/metrics/histogram_macros.h"
anujk.sharmaafc45172015-05-15 00:50:3459#include "base/single_thread_task_runner.h"
tripta.gdda72022017-06-19 05:16:2360#include "base/stl_util.h"
Maks Orlovich323efaf2018-03-06 02:56:3961#include "base/strings/string_piece.h"
[email protected]4b355212013-06-11 10:35:1962#include "base/strings/string_util.h"
63#include "base/strings/stringprintf.h"
gabf767595f2016-05-11 18:50:3564#include "base/threading/thread_task_runner_handle.h"
Maks Orlovich5cf437b02018-03-27 04:40:4265#include "base/trace_event/process_memory_dump.h"
Lily Chen8a648cb72019-04-25 20:29:1566#include "net/base/features.h"
[email protected]be28b5f42012-07-20 11:31:2567#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
[email protected]4b355212013-06-11 10:35:1968#include "net/cookies/canonical_cookie.h"
Victor Costan14f47c12018-03-01 08:02:2469#include "net/cookies/cookie_monster_change_dispatcher.h"
Helen Licd0fab862018-08-13 16:07:5370#include "net/cookies/cookie_monster_netlog_params.h"
[email protected]63ee33bd2012-03-15 09:29:5871#include "net/cookies/cookie_util.h"
[email protected]ebfe3172012-07-12 12:21:4172#include "net/cookies/parsed_cookie.h"
Helen Licd0fab862018-08-13 16:07:5373#include "net/log/net_log.h"
mkwst8241a122015-10-20 07:15:1074#include "url/origin.h"
initial.commit586acc5fe2008-07-26 22:42:5275
[email protected]e1acf6f2008-10-27 20:43:3376using base::Time;
77using base::TimeDelta;
[email protected]7a964a72010-09-07 19:33:2678using base::TimeTicks;
Chris Mumfordd8ed9f82018-05-01 15:43:1379using TimeRange = net::CookieDeletionInfo::TimeRange;
[email protected]e1acf6f2008-10-27 20:43:3380
[email protected]85620342011-10-17 17:35:0481// In steady state, most cookie requests can be satisfied by the in memory
erikchen1dd72a72015-05-06 20:45:0582// cookie monster store. If the cookie request cannot be satisfied by the in
83// memory store, the relevant cookies must be fetched from the persistent
84// store. The task is queued in CookieMonster::tasks_pending_ if it requires
85// all cookies to be loaded from the backend, or tasks_pending_for_key_ if it
86// only requires all cookies associated with an eTLD+1.
[email protected]85620342011-10-17 17:35:0487//
88// On the browser critical paths (e.g. for loading initial web pages in a
89// session restore) it may take too long to wait for the full load. If a cookie
rdsmithe5c701d2017-07-12 21:50:0090// request is for a specific URL, DoCookieCallbackForURL is called, which
91// triggers a priority load if the key is not loaded yet by calling
92// PersistentCookieStore::LoadCookiesForKey. The request is queued in
[email protected]0184df32013-05-14 00:53:5593// CookieMonster::tasks_pending_for_key_ and executed upon receiving
94// notification of key load completion via CookieMonster::OnKeyLoaded(). If
95// multiple requests for the same eTLD+1 are received before key load
96// completion, only the first request calls
[email protected]85620342011-10-17 17:35:0497// PersistentCookieStore::LoadCookiesForKey, all subsequent requests are queued
[email protected]0184df32013-05-14 00:53:5598// in CookieMonster::tasks_pending_for_key_ and executed upon receiving
99// notification of key load completion triggered by the first request for the
100// same eTLD+1.
[email protected]85620342011-10-17 17:35:04101
[email protected]c4058fb2010-06-22 17:25:26102static const int kMinutesInTenYears = 10 * 365 * 24 * 60;
103
erikchen1dd72a72015-05-06 20:45:05104namespace {
105
Maks Orlovichf97d1b92018-03-06 17:25:39106void MaybeRunDeleteCallback(base::WeakPtr<net::CookieMonster> cookie_monster,
107 base::OnceClosure callback) {
rdsmithe5c701d2017-07-12 21:50:00108 if (cookie_monster && callback)
109 std::move(callback).Run();
110}
111
rdsmithe5c701d2017-07-12 21:50:00112template <typename T>
113void MaybeRunCookieCallback(base::OnceCallback<void(const T&)> callback,
114 const T& result) {
115 if (callback)
116 std::move(callback).Run(result);
117}
118
Aaron Tagliaboschia4c64b52019-01-25 03:28:49119template <typename T, typename U>
120void MaybeRunCookieCallback(
121 base::OnceCallback<void(const T&, const U&)> callback,
122 const T& first,
123 const U& second) {
124 if (callback)
125 std::move(callback).Run(first, second);
126}
127
rdsmithe5c701d2017-07-12 21:50:00128template <typename T>
129void MaybeRunCookieCallback(base::OnceCallback<void(T)> callback,
130 const T& result) {
131 if (callback)
132 std::move(callback).Run(result);
133}
134
erikchen1dd72a72015-05-06 20:45:05135} // namespace
136
[email protected]8ac1a752008-07-31 19:40:37137namespace net {
138
[email protected]7a964a72010-09-07 19:33:26139// See comments at declaration of these variables in cookie_monster.h
140// for details.
mkwstbe84af312015-02-20 08:52:45141const size_t CookieMonster::kDomainMaxCookies = 180;
142const size_t CookieMonster::kDomainPurgeCookies = 30;
143const size_t CookieMonster::kMaxCookies = 3300;
144const size_t CookieMonster::kPurgeCookies = 300;
[email protected]8ad5d462013-05-02 08:45:26145
mkwst87734352016-03-03 17:36:23146const size_t CookieMonster::kDomainCookiesQuotaLow = 30;
147const size_t CookieMonster::kDomainCookiesQuotaMedium = 50;
148const size_t CookieMonster::kDomainCookiesQuotaHigh =
149 kDomainMaxCookies - kDomainPurgeCookies - kDomainCookiesQuotaLow -
150 kDomainCookiesQuotaMedium;
[email protected]8ad5d462013-05-02 08:45:26151
mkwstbe84af312015-02-20 08:52:45152const int CookieMonster::kSafeFromGlobalPurgeDays = 30;
[email protected]297a4ed02010-02-12 08:12:52153
[email protected]7a964a72010-09-07 19:33:26154namespace {
[email protected]e32306c52008-11-06 16:59:05155
[email protected]6210ce52013-09-20 03:33:14156bool ContainsControlCharacter(const std::string& s) {
157 for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
158 if ((*i >= 0) && (*i <= 31))
159 return true;
160 }
161
162 return false;
163}
164
[email protected]5b9bc352012-07-18 13:13:34165typedef std::vector<CanonicalCookie*> CanonicalCookieVector;
[email protected]34a160d2011-05-12 22:12:49166
[email protected]77e0a462008-11-01 00:43:35167// Default minimum delay after updating a cookie's LastAccessDate before we
168// will update it again.
[email protected]297a4ed02010-02-12 08:12:52169const int kDefaultAccessUpdateThresholdSeconds = 60;
170
171// Comparator to sort cookies from highest creation date to lowest
172// creation date.
173struct OrderByCreationTimeDesc {
174 bool operator()(const CookieMonster::CookieMap::iterator& a,
175 const CookieMonster::CookieMap::iterator& b) const {
176 return a->second->CreationDate() > b->second->CreationDate();
177 }
178};
179
[email protected]f48b9432011-01-11 07:25:40180// Mozilla sorts on the path length (longest first), and then it
181// sorts by creation time (oldest first).
182// The RFC says the sort order for the domain attribute is undefined.
[email protected]5b9bc352012-07-18 13:13:34183bool CookieSorter(CanonicalCookie* cc1, CanonicalCookie* cc2) {
[email protected]f48b9432011-01-11 07:25:40184 if (cc1->Path().length() == cc2->Path().length())
185 return cc1->CreationDate() < cc2->CreationDate();
186 return cc1->Path().length() > cc2->Path().length();
initial.commit586acc5fe2008-07-26 22:42:52187}
188
[email protected]8ad5d462013-05-02 08:45:26189bool LRACookieSorter(const CookieMonster::CookieMap::iterator& it1,
[email protected]f48b9432011-01-11 07:25:40190 const CookieMonster::CookieMap::iterator& it2) {
[email protected]f48b9432011-01-11 07:25:40191 if (it1->second->LastAccessDate() != it2->second->LastAccessDate())
192 return it1->second->LastAccessDate() < it2->second->LastAccessDate();
initial.commit586acc5fe2008-07-26 22:42:52193
mkwste079ac412016-03-11 09:04:06194 // Ensure stability for == last access times by falling back to creation.
[email protected]f48b9432011-01-11 07:25:40195 return it1->second->CreationDate() < it2->second->CreationDate();
[email protected]297a4ed02010-02-12 08:12:52196}
197
198// Our strategy to find duplicates is:
199// (1) Build a map from (cookiename, cookiepath) to
200// {list of cookies with this signature, sorted by creation time}.
201// (2) For each list with more than 1 entry, keep the cookie having the
202// most recent creation time, and delete the others.
[email protected]f48b9432011-01-11 07:25:40203//
[email protected]1655ba342010-07-14 18:17:42204// Two cookies are considered equivalent if they have the same domain,
205// name, and path.
206struct CookieSignature {
207 public:
[email protected]dedec0b2013-02-28 04:50:10208 CookieSignature(const std::string& name,
209 const std::string& domain,
[email protected]1655ba342010-07-14 18:17:42210 const std::string& path)
mkwstbe84af312015-02-20 08:52:45211 : name(name), domain(domain), path(path) {}
[email protected]1655ba342010-07-14 18:17:42212
213 // To be a key for a map this class needs to be assignable, copyable,
214 // and have an operator<. The default assignment operator
215 // and copy constructor are exactly what we want.
216
217 bool operator<(const CookieSignature& cs) const {
218 // Name compare dominates, then domain, then path.
219 int diff = name.compare(cs.name);
220 if (diff != 0)
221 return diff < 0;
222
223 diff = domain.compare(cs.domain);
224 if (diff != 0)
225 return diff < 0;
226
227 return path.compare(cs.path) < 0;
228 }
229
230 std::string name;
231 std::string domain;
232 std::string path;
233};
[email protected]f48b9432011-01-11 07:25:40234
[email protected]8ad5d462013-05-02 08:45:26235// For a CookieItVector iterator range [|it_begin|, |it_end|),
mmenkef4721d992017-06-07 17:13:59236// sorts the first |num_sort| elements by LastAccessDate().
mkwstbe84af312015-02-20 08:52:45237void SortLeastRecentlyAccessed(CookieMonster::CookieItVector::iterator it_begin,
238 CookieMonster::CookieItVector::iterator it_end,
239 size_t num_sort) {
mmenkef4721d992017-06-07 17:13:59240 DCHECK_LE(static_cast<int>(num_sort), it_end - it_begin);
241 std::partial_sort(it_begin, it_begin + num_sort, it_end, LRACookieSorter);
[email protected]8ad5d462013-05-02 08:45:26242}
[email protected]f48b9432011-01-11 07:25:40243
jww82d99c12015-11-25 18:39:53244// Given a single cookie vector |cookie_its|, pushs all of the secure cookies in
245// |cookie_its| into |secure_cookie_its| and all of the non-secure cookies into
246// |non_secure_cookie_its|. Both |secure_cookie_its| and |non_secure_cookie_its|
247// must be non-NULL.
248void SplitCookieVectorIntoSecureAndNonSecure(
249 const CookieMonster::CookieItVector& cookie_its,
250 CookieMonster::CookieItVector* secure_cookie_its,
251 CookieMonster::CookieItVector* non_secure_cookie_its) {
252 DCHECK(secure_cookie_its && non_secure_cookie_its);
253 for (const auto& curit : cookie_its) {
254 if (curit->second->IsSecure())
255 secure_cookie_its->push_back(curit);
256 else
257 non_secure_cookie_its->push_back(curit);
258 }
259}
260
mkwstbe84af312015-02-20 08:52:45261bool LowerBoundAccessDateComparator(const CookieMonster::CookieMap::iterator it,
262 const Time& access_date) {
[email protected]8ad5d462013-05-02 08:45:26263 return it->second->LastAccessDate() < access_date;
264}
265
266// For a CookieItVector iterator range [|it_begin|, |it_end|)
267// from a CookieItVector sorted by LastAccessDate(), returns the
268// first iterator with access date >= |access_date|, or cookie_its_end if this
269// holds for all.
270CookieMonster::CookieItVector::iterator LowerBoundAccessDate(
271 const CookieMonster::CookieItVector::iterator its_begin,
272 const CookieMonster::CookieItVector::iterator its_end,
273 const Time& access_date) {
274 return std::lower_bound(its_begin, its_end, access_date,
275 LowerBoundAccessDateComparator);
[email protected]7a964a72010-09-07 19:33:26276}
277
Victor Costan14f47c12018-03-01 08:02:24278// Mapping between DeletionCause and CookieChangeCause; the
[email protected]7c4b66b2014-01-04 12:28:13279// mapping also provides a boolean that specifies whether or not an
Victor Costan14f47c12018-03-01 08:02:24280// OnCookieChange notification ought to be generated.
[email protected]8bb846f2011-03-23 12:08:18281typedef struct ChangeCausePair_struct {
Victor Costan14f47c12018-03-01 08:02:24282 CookieChangeCause cause;
[email protected]8bb846f2011-03-23 12:08:18283 bool notify;
284} ChangeCausePair;
nharper352933e2016-09-30 18:24:57285const ChangeCausePair kChangeCauseMapping[] = {
mkwstbe84af312015-02-20 08:52:45286 // DELETE_COOKIE_EXPLICIT
Victor Costan14f47c12018-03-01 08:02:24287 {CookieChangeCause::EXPLICIT, true},
mkwstbe84af312015-02-20 08:52:45288 // DELETE_COOKIE_OVERWRITE
Victor Costan14f47c12018-03-01 08:02:24289 {CookieChangeCause::OVERWRITE, true},
mkwstbe84af312015-02-20 08:52:45290 // DELETE_COOKIE_EXPIRED
Victor Costan14f47c12018-03-01 08:02:24291 {CookieChangeCause::EXPIRED, true},
mkwstbe84af312015-02-20 08:52:45292 // DELETE_COOKIE_EVICTED
Victor Costan14f47c12018-03-01 08:02:24293 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45294 // DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE
Victor Costan14f47c12018-03-01 08:02:24295 {CookieChangeCause::EXPLICIT, false},
mkwstbe84af312015-02-20 08:52:45296 // DELETE_COOKIE_DONT_RECORD
Victor Costan14f47c12018-03-01 08:02:24297 {CookieChangeCause::EXPLICIT, false},
mkwstbe84af312015-02-20 08:52:45298 // DELETE_COOKIE_EVICTED_DOMAIN
Victor Costan14f47c12018-03-01 08:02:24299 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45300 // DELETE_COOKIE_EVICTED_GLOBAL
Victor Costan14f47c12018-03-01 08:02:24301 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45302 // DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE
Victor Costan14f47c12018-03-01 08:02:24303 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45304 // DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE
Victor Costan14f47c12018-03-01 08:02:24305 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45306 // DELETE_COOKIE_EXPIRED_OVERWRITE
Victor Costan14f47c12018-03-01 08:02:24307 {CookieChangeCause::EXPIRED_OVERWRITE, true},
mkwstbe84af312015-02-20 08:52:45308 // DELETE_COOKIE_CONTROL_CHAR
Victor Costan14f47c12018-03-01 08:02:24309 {CookieChangeCause::EVICTED, true},
jww82d99c12015-11-25 18:39:53310 // DELETE_COOKIE_NON_SECURE
Victor Costan14f47c12018-03-01 08:02:24311 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45312 // DELETE_COOKIE_LAST_ENTRY
Victor Costan14f47c12018-03-01 08:02:24313 {CookieChangeCause::EXPLICIT, false}};
ellyjones399e35a22014-10-27 11:09:56314
jwwc00ac712016-05-05 22:21:44315bool IsCookieEligibleForEviction(CookiePriority current_priority_level,
316 bool protect_secure_cookies,
317 const CanonicalCookie* cookie) {
mmenke645ca6772016-06-17 18:46:43318 if (cookie->Priority() == current_priority_level && protect_secure_cookies)
319 return !cookie->IsSecure();
jwwc00ac712016-05-05 22:21:44320
mmenke645ca6772016-06-17 18:46:43321 return cookie->Priority() == current_priority_level;
322}
jwwc00ac712016-05-05 22:21:44323
mmenke645ca6772016-06-17 18:46:43324size_t CountCookiesForPossibleDeletion(
325 CookiePriority priority,
326 const CookieMonster::CookieItVector* cookies,
327 bool protect_secure_cookies) {
328 size_t cookies_count = 0U;
329 for (const auto& cookie : *cookies) {
330 if (cookie->second->Priority() == priority) {
331 if (!protect_secure_cookies || cookie->second->IsSecure())
332 cookies_count++;
333 }
334 }
335 return cookies_count;
jwwc00ac712016-05-05 22:21:44336}
337
[email protected]f48b9432011-01-11 07:25:40338} // namespace
339
Pritam8354cf702018-03-10 08:55:41340CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
Helen Lifb313a92018-08-14 15:46:44341 NetLog* net_log)
Randy Smithb78e0922018-03-01 21:19:54342 : CookieMonster(
Pritam8354cf702018-03-10 08:55:41343 std::move(store),
Helen Lifb313a92018-08-14 15:46:44344 base::TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds),
345 net_log) {}
Randy Smithb78e0922018-03-01 21:19:54346
Pritam8354cf702018-03-10 08:55:41347CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
Helen Lifb313a92018-08-14 15:46:44348 base::TimeDelta last_access_threshold,
349 NetLog* net_log)
[email protected]f48b9432011-01-11 07:25:40350 : initialized_(false),
erikchen1dd72a72015-05-06 20:45:05351 started_fetching_all_cookies_(false),
352 finished_fetching_all_cookies_(false),
mmenkef49fca0e2016-03-08 12:46:24353 seen_global_task_(false),
Helen Lifb313a92018-08-14 15:46:44354 net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::COOKIE_STORE)),
Pritam8354cf702018-03-10 08:55:41355 store_(std::move(store)),
shessf0bc1182016-05-19 04:35:58356 last_access_threshold_(last_access_threshold),
[email protected]82388662011-03-10 21:04:06357 last_statistic_record_time_(base::Time::Now()),
mmenkebe0910d2016-03-01 19:09:09358 persist_session_cookies_(false),
359 weak_ptr_factory_(this) {
[email protected]f48b9432011-01-11 07:25:40360 InitializeHistograms();
mmenke18dd8ba2016-02-01 18:42:10361 cookieable_schemes_.insert(
362 cookieable_schemes_.begin(), kDefaultCookieableSchemes,
363 kDefaultCookieableSchemes + kDefaultCookieableSchemesCount);
Helen Licd0fab862018-08-13 16:07:53364 net_log_.BeginEvent(
365 NetLogEventType::COOKIE_STORE_ALIVE,
366 base::BindRepeating(&NetLogCookieMonsterConstructorCallback,
Nick Harper57142b1c2019-03-14 21:03:59367 store != nullptr));
initial.commit586acc5fe2008-07-26 22:42:52368}
369
[email protected]218aa6a12011-09-13 17:38:38370// Asynchronous CookieMonster API
371
rdsmith7ac81712017-06-22 17:09:54372void CookieMonster::FlushStore(base::OnceClosure callback) {
mmenkebe0910d2016-03-01 19:09:09373 DCHECK(thread_checker_.CalledOnValidThread());
mmenke606c59c2016-03-07 18:20:55374
nharper2b0ad9a2017-05-22 18:33:45375 if (initialized_ && store_.get()) {
rdsmith7ac81712017-06-22 17:09:54376 store_->Flush(std::move(callback));
rdsmithe5c701d2017-07-12 21:50:00377 } else if (callback) {
rdsmith7ac81712017-06-22 17:09:54378 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
379 std::move(callback));
nharper2b0ad9a2017-05-22 18:33:45380 }
mmenke74bcbd52016-01-21 17:17:56381}
382
mmenkeded79da2016-02-06 08:28:51383void CookieMonster::SetForceKeepSessionState() {
mmenkebe0910d2016-03-01 19:09:09384 DCHECK(thread_checker_.CalledOnValidThread());
mmenke606c59c2016-03-07 18:20:55385
mmenkeded79da2016-02-06 08:28:51386 if (store_)
387 store_->SetForceKeepSessionState();
388}
389
drogerd5d1278c2015-03-17 19:21:51390void CookieMonster::SetAllCookiesAsync(const CookieList& list,
rdsmith7ac81712017-06-22 17:09:54391 SetCookiesCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00392 DoCookieCallback(base::BindOnce(
393 // base::Unretained is safe as DoCookieCallbackForURL stores
394 // the callback on |*this|, so the callback will not outlive
395 // the object.
396 &CookieMonster::SetAllCookies, base::Unretained(this), list,
397 std::move(callback)));
drogerd5d1278c2015-03-17 19:21:51398}
399
rdsmitha6ce4442017-06-21 17:11:05400void CookieMonster::SetCanonicalCookieAsync(
401 std::unique_ptr<CanonicalCookie> cookie,
Maks Orlovich44525ce2019-02-25 14:17:58402 std::string source_scheme,
Maks Orlovichfdbc8be2019-03-18 18:34:52403 const CookieOptions& options,
rdsmith7ac81712017-06-22 17:09:54404 SetCookiesCallback callback) {
rdsmitha6ce4442017-06-21 17:11:05405 DCHECK(cookie->IsCanonical());
rdsmitha6ce4442017-06-21 17:11:05406
Maks Orlovich323efaf2018-03-06 02:56:39407 std::string domain = cookie->Domain();
408 DoCookieCallbackForHostOrDomain(
409 base::BindOnce(
410 // base::Unretained is safe as DoCookieCallbackForURL stores
411 // the callback on |*this|, so the callback will not outlive
412 // the object.
413 &CookieMonster::SetCanonicalCookie, base::Unretained(this),
Maks Orlovichfdbc8be2019-03-18 18:34:52414 std::move(cookie), std::move(source_scheme), options,
Maks Orlovich323efaf2018-03-06 02:56:39415 std::move(callback)),
416 domain);
rdsmitha6ce4442017-06-21 17:11:05417}
418
rdsmith7ac81712017-06-22 17:09:54419void CookieMonster::SetCookieWithOptionsAsync(const GURL& url,
420 const std::string& cookie_line,
421 const CookieOptions& options,
422 SetCookiesCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00423 DoCookieCallbackForURL(
424 base::BindOnce(
425 // base::Unretained is safe as DoCookieCallbackForURL stores
426 // the callback on |*this|, so the callback will not outlive
427 // the object.
428 &CookieMonster::SetCookieWithOptions, base::Unretained(this), url,
429 cookie_line, options, std::move(callback)),
430 url);
[email protected]218aa6a12011-09-13 17:38:38431}
432
mkwstc611e6d2016-02-23 15:45:55433void CookieMonster::GetCookieListWithOptionsAsync(
mmenke74bcbd52016-01-21 17:17:56434 const GURL& url,
mkwstc611e6d2016-02-23 15:45:55435 const CookieOptions& options,
rdsmith7ac81712017-06-22 17:09:54436 GetCookieListCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00437 DoCookieCallbackForURL(
Ken Rockotec216e3dd2019-02-20 00:43:59438 base::BindOnce(
rdsmithe5c701d2017-07-12 21:50:00439 // base::Unretained is safe as DoCookieCallbackForURL stores
440 // the callback on |*this|, so the callback will not outlive
441 // the object.
442 &CookieMonster::GetCookieListWithOptions, base::Unretained(this), url,
Ken Rockotec216e3dd2019-02-20 00:43:59443 options, std::move(callback)),
rdsmithe5c701d2017-07-12 21:50:00444 url);
mmenke74bcbd52016-01-21 17:17:56445}
446
rdsmith7ac81712017-06-22 17:09:54447void CookieMonster::GetAllCookiesAsync(GetCookieListCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00448 DoCookieCallback(base::BindOnce(
449 // base::Unretained is safe as DoCookieCallbackForURL stores
450 // the callback on |*this|, so the callback will not outlive
451 // the object.
452 &CookieMonster::GetAllCookies, base::Unretained(this),
453 std::move(callback)));
mmenke9fa44f2d2016-01-22 23:36:39454}
455
mmenke24379d52016-02-05 23:50:17456void CookieMonster::DeleteCanonicalCookieAsync(const CanonicalCookie& cookie,
rdsmith7ac81712017-06-22 17:09:54457 DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00458 DoCookieCallback(base::BindOnce(
459 // base::Unretained is safe as DoCookieCallbackForURL stores
460 // the callback on |*this|, so the callback will not outlive
461 // the object.
462 &CookieMonster::DeleteCanonicalCookie, base::Unretained(this), cookie,
463 std::move(callback)));
mmenke24379d52016-02-05 23:50:17464}
465
Chris Mumford800caa62018-04-20 19:34:44466void CookieMonster::DeleteAllCreatedInTimeRangeAsync(
467 const TimeRange& creation_range,
468 DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00469 DoCookieCallback(base::BindOnce(
470 // base::Unretained is safe as DoCookieCallbackForURL stores
471 // the callback on |*this|, so the callback will not outlive
472 // the object.
Chris Mumford800caa62018-04-20 19:34:44473 &CookieMonster::DeleteAllCreatedInTimeRange, base::Unretained(this),
474 creation_range, std::move(callback)));
mmenke74bcbd52016-01-21 17:17:56475}
476
Chris Mumford800caa62018-04-20 19:34:44477void CookieMonster::DeleteAllMatchingInfoAsync(CookieDeletionInfo delete_info,
478 DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00479 DoCookieCallback(base::BindOnce(
480 // base::Unretained is safe as DoCookieCallbackForURL stores
481 // the callback on |*this|, so the callback will not outlive
482 // the object.
Chris Mumford800caa62018-04-20 19:34:44483 &CookieMonster::DeleteAllMatchingInfo, base::Unretained(this),
484 std::move(delete_info), std::move(callback)));
mmenke74bcbd52016-01-21 17:17:56485}
486
[email protected]264807b2012-04-25 14:49:37487void CookieMonster::DeleteSessionCookiesAsync(
rdsmith7ac81712017-06-22 17:09:54488 CookieStore::DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00489 DoCookieCallback(base::BindOnce(
490 // base::Unretained is safe as DoCookieCallbackForURL stores
491 // the callback on |*this|, so the callback will not outlive
492 // the object.
493 &CookieMonster::DeleteSessionCookies, base::Unretained(this),
494 std::move(callback)));
[email protected]264807b2012-04-25 14:49:37495}
496
mmenke18dd8ba2016-02-01 18:42:10497void CookieMonster::SetCookieableSchemes(
Nate Fischerc6fb6cf2019-03-27 00:39:49498 const std::vector<std::string>& schemes,
499 SetCookieableSchemesCallback callback) {
mmenkebe0910d2016-03-01 19:09:09500 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56501
502 // Calls to this method will have no effect if made after a WebView or
503 // CookieManager instance has been created.
Nate Fischerc6fb6cf2019-03-27 00:39:49504 if (initialized_) {
505 MaybeRunCookieCallback(std::move(callback), false);
mmenke74bcbd52016-01-21 17:17:56506 return;
Nate Fischerc6fb6cf2019-03-27 00:39:49507 }
mmenke74bcbd52016-01-21 17:17:56508
mmenke18dd8ba2016-02-01 18:42:10509 cookieable_schemes_ = schemes;
Nate Fischerc6fb6cf2019-03-27 00:39:49510 MaybeRunCookieCallback(std::move(callback), true);
mmenke74bcbd52016-01-21 17:17:56511}
512
mmenke74bcbd52016-01-21 17:17:56513// This function must be called before the CookieMonster is used.
514void CookieMonster::SetPersistSessionCookies(bool persist_session_cookies) {
mmenkebe0910d2016-03-01 19:09:09515 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56516 DCHECK(!initialized_);
Helen Licd0fab862018-08-13 16:07:53517 net_log_.AddEvent(
518 NetLogEventType::COOKIE_STORE_SESSION_PERSISTENCE,
519 NetLog::BoolCallback("persistence", persist_session_cookies));
mmenke74bcbd52016-01-21 17:17:56520 persist_session_cookies_ = persist_session_cookies;
521}
522
523bool CookieMonster::IsCookieableScheme(const std::string& scheme) {
mmenkebe0910d2016-03-01 19:09:09524 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56525
tripta.gdda72022017-06-19 05:16:23526 return base::ContainsValue(cookieable_schemes_, scheme);
mmenke74bcbd52016-01-21 17:17:56527}
528
mmenke18dd8ba2016-02-01 18:42:10529const char* const CookieMonster::kDefaultCookieableSchemes[] = {"http", "https",
530 "ws", "wss"};
mmenke74bcbd52016-01-21 17:17:56531const int CookieMonster::kDefaultCookieableSchemesCount =
Ryan Sleevi435a3a22018-05-15 02:16:07532 base::size(kDefaultCookieableSchemes);
mmenke74bcbd52016-01-21 17:17:56533
Victor Costan14f47c12018-03-01 08:02:24534CookieChangeDispatcher& CookieMonster::GetChangeDispatcher() {
535 return change_dispatcher_;
Randy Smithd32dc8c2017-08-30 18:03:40536}
537
Maks Orlovich5cf437b02018-03-27 04:40:42538void CookieMonster::DumpMemoryStats(
539 base::trace_event::ProcessMemoryDump* pmd,
540 const std::string& parent_absolute_name) const {
541 const char kRelPath[] = "/cookie_monster";
542
543 pmd->CreateAllocatorDump(parent_absolute_name + kRelPath + "/cookies")
544 ->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
545 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
546 cookies_.size());
547
548 pmd->CreateAllocatorDump(parent_absolute_name + kRelPath +
549 "/tasks_pending_global")
550 ->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
551 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
552 tasks_pending_.size());
553
554 size_t total_pending_for_key = 0;
555 for (const auto& kv : tasks_pending_for_key_)
556 total_pending_for_key += kv.second.size();
557 pmd->CreateAllocatorDump(parent_absolute_name + kRelPath +
558 "/tasks_pending_for_key")
559 ->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
560 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
561 total_pending_for_key);
562}
563
mmenke74bcbd52016-01-21 17:17:56564CookieMonster::~CookieMonster() {
mmenkebe0910d2016-03-01 19:09:09565 DCHECK(thread_checker_.CalledOnValidThread());
mmenke05255cf2016-02-03 15:49:31566
Randy Smith0a522662017-08-30 19:35:34567 // TODO(mmenke): Does it really make sense to run
mmenke606c59c2016-03-07 18:20:55568 // CookieChanged callbacks when the CookieStore is destroyed?
jdoerrie22a91d8b92018-10-05 08:43:26569 for (auto cookie_it = cookies_.begin(); cookie_it != cookies_.end();) {
570 auto current_cookie_it = cookie_it;
mmenke05255cf2016-02-03 15:49:31571 ++cookie_it;
572 InternalDeleteCookie(current_cookie_it, false /* sync_to_store */,
573 DELETE_COOKIE_DONT_RECORD);
574 }
Helen Licd0fab862018-08-13 16:07:53575 net_log_.EndEvent(NetLogEventType::COOKIE_STORE_ALIVE);
[email protected]85620342011-10-17 17:35:04576}
577
rdsmithe5c701d2017-07-12 21:50:00578void CookieMonster::GetAllCookies(GetCookieListCallback callback) {
mmenkebe0910d2016-03-01 19:09:09579 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40580
581 // This function is being called to scrape the cookie list for management UI
582 // or similar. We shouldn't show expired cookies in this list since it will
583 // just be confusing to users, and this function is called rarely enough (and
584 // is already slow enough) that it's OK to take the time to garbage collect
585 // the expired cookies now.
586 //
587 // Note that this does not prune cookies to be below our limits (if we've
588 // exceeded them) the way that calling GarbageCollect() would.
mkwstbe84af312015-02-20 08:52:45589 GarbageCollectExpired(
Raul Tambre94493c652019-03-11 17:18:35590 Time::Now(), CookieMapItPair(cookies_.begin(), cookies_.end()), nullptr);
[email protected]f48b9432011-01-11 07:25:40591
592 // Copy the CanonicalCookie pointers from the map so that we can use the same
593 // sorter as elsewhere, then copy the result out.
594 std::vector<CanonicalCookie*> cookie_ptrs;
595 cookie_ptrs.reserve(cookies_.size());
avie7cd11a2016-10-11 02:00:35596 for (const auto& cookie : cookies_)
597 cookie_ptrs.push_back(cookie.second.get());
[email protected]f48b9432011-01-11 07:25:40598 std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
599
600 CookieList cookie_list;
601 cookie_list.reserve(cookie_ptrs.size());
vmpstr6d9996c82017-02-23 00:43:25602 for (auto* cookie_ptr : cookie_ptrs)
avie7cd11a2016-10-11 02:00:35603 cookie_list.push_back(*cookie_ptr);
[email protected]f48b9432011-01-11 07:25:40604
Aaron Tagliaboschia4c64b52019-01-25 03:28:49605 MaybeRunCookieCallback(std::move(callback), cookie_list, CookieStatusList());
[email protected]f325f1e12010-04-30 22:38:55606}
607
rdsmithe5c701d2017-07-12 21:50:00608void CookieMonster::GetCookieListWithOptions(const GURL& url,
609 const CookieOptions& options,
610 GetCookieListCallback callback) {
mmenkebe0910d2016-03-01 19:09:09611 DCHECK(thread_checker_.CalledOnValidThread());
initial.commit586acc5fe2008-07-26 22:42:52612
mkwstc611e6d2016-02-23 15:45:55613 CookieList cookies;
Aaron Tagliaboschia4c64b52019-01-25 03:28:49614 CookieStatusList excluded_cookies;
rdsmithe5c701d2017-07-12 21:50:00615 if (HasCookieableScheme(url)) {
616 std::vector<CanonicalCookie*> cookie_ptrs;
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:52617 FindCookiesForRegistryControlledHost(url, &cookie_ptrs);
Aaron Tagliaboschi29033b7f2019-01-31 19:58:20618 std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
mkwstc611e6d2016-02-23 15:45:55619
rdsmithe5c701d2017-07-12 21:50:00620 cookies.reserve(cookie_ptrs.size());
Aaron Tagliaboschi29033b7f2019-01-31 19:58:20621 std::vector<CanonicalCookie*> included_cookie_ptrs;
622 FilterCookiesWithOptions(url, options, &cookie_ptrs, &included_cookie_ptrs,
623 &excluded_cookies);
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:52624
Aaron Tagliaboschi29033b7f2019-01-31 19:58:20625 for (auto* cookie : included_cookie_ptrs) {
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:52626 cookies.push_back(*cookie);
627 }
rdsmithe5c701d2017-07-12 21:50:00628 }
Aaron Tagliaboschi29033b7f2019-01-31 19:58:20629
Aaron Tagliaboschia4c64b52019-01-25 03:28:49630 MaybeRunCookieCallback(std::move(callback), cookies, excluded_cookies);
initial.commit586acc5fe2008-07-26 22:42:52631}
632
Chris Mumford800caa62018-04-20 19:34:44633void CookieMonster::DeleteAllCreatedInTimeRange(const TimeRange& creation_range,
634 DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09635 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]d0980332010-11-16 17:08:53636
rdsmitha5beda162017-07-08 13:55:42637 uint32_t num_deleted = 0;
jdoerrie22a91d8b92018-10-05 08:43:26638 for (auto it = cookies_.begin(); it != cookies_.end();) {
639 auto curit = it;
avie7cd11a2016-10-11 02:00:35640 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:40641 ++it;
[email protected]d0980332010-11-16 17:08:53642
Chris Mumford800caa62018-04-20 19:34:44643 if (creation_range.Contains(cc->CreationDate())) {
mkwstbe84af312015-02-20 08:52:45644 InternalDeleteCookie(curit, true, /*sync_to_store*/
Nick Harper7a6683a2018-01-30 20:42:52645 DELETE_COOKIE_EXPLICIT);
[email protected]f48b9432011-01-11 07:25:40646 ++num_deleted;
initial.commit586acc5fe2008-07-26 22:42:52647 }
648 }
649
rdsmithe5c701d2017-07-12 21:50:00650 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39651 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00652 callback ? base::BindOnce(std::move(callback), num_deleted)
653 : base::OnceClosure()));
[email protected]f48b9432011-01-11 07:25:40654}
655
Chris Mumford800caa62018-04-20 19:34:44656void CookieMonster::DeleteAllMatchingInfo(CookieDeletionInfo delete_info,
657 DeleteCallback callback) {
rdsmitha5beda162017-07-08 13:55:42658 uint32_t num_deleted = 0;
jdoerrie22a91d8b92018-10-05 08:43:26659 for (auto it = cookies_.begin(); it != cookies_.end();) {
660 auto curit = it;
avie7cd11a2016-10-11 02:00:35661 CanonicalCookie* cc = curit->second.get();
dmurphfaea244c2016-04-09 00:42:30662 ++it;
[email protected]f48b9432011-01-11 07:25:40663
Chris Mumford800caa62018-04-20 19:34:44664 if (delete_info.Matches(*cc)) {
dmurphfaea244c2016-04-09 00:42:30665 InternalDeleteCookie(curit, true, /*sync_to_store*/
Nick Harper7a6683a2018-01-30 20:42:52666 DELETE_COOKIE_EXPLICIT);
dmurphfaea244c2016-04-09 00:42:30667 ++num_deleted;
[email protected]f48b9432011-01-11 07:25:40668 }
669 }
dmurphfaea244c2016-04-09 00:42:30670
rdsmithe5c701d2017-07-12 21:50:00671 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39672 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00673 callback ? base::BindOnce(std::move(callback), num_deleted)
674 : base::OnceClosure()));
[email protected]f48b9432011-01-11 07:25:40675}
676
rdsmithe5c701d2017-07-12 21:50:00677void CookieMonster::SetCookieWithOptions(const GURL& url,
[email protected]f48b9432011-01-11 07:25:40678 const std::string& cookie_line,
rdsmithe5c701d2017-07-12 21:50:00679 const CookieOptions& options,
680 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:09681 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40682
683 if (!HasCookieableScheme(url)) {
Aaron Tagliaboschi29764f52019-02-21 17:19:59684 MaybeRunCookieCallback(
685 std::move(callback),
686 CanonicalCookie::CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME);
rdsmithe5c701d2017-07-12 21:50:00687 return;
[email protected]f48b9432011-01-11 07:25:40688 }
689
Maks Orlovich35d74c042019-04-18 16:38:01690 DVLOG(net::cookie_util::kVlogSetCookies)
Oscar Johansson63e83cf2018-07-02 08:47:26691 << "SetCookie() line: " << cookie_line;
Maks Orlovicha61ed022018-03-01 18:24:24692
Aaron Tagliaboschi29764f52019-02-21 17:19:59693 CanonicalCookie::CookieInclusionStatus status;
Maks Orlovicha61ed022018-03-01 18:24:24694
Aaron Tagliaboschi29764f52019-02-21 17:19:59695 std::unique_ptr<CanonicalCookie> cc(
696 CanonicalCookie::Create(url, cookie_line, Time::Now(), options, &status));
697
698 if (status != CanonicalCookie::CookieInclusionStatus::INCLUDE) {
699 DCHECK(!cc);
Maks Orlovich35d74c042019-04-18 16:38:01700 DVLOG(net::cookie_util::kVlogSetCookies)
Oscar Johansson63e83cf2018-07-02 08:47:26701 << "WARNING: Failed to allocate CanonicalCookie";
Aaron Tagliaboschi29764f52019-02-21 17:19:59702 MaybeRunCookieCallback(std::move(callback), status);
Maks Orlovicha61ed022018-03-01 18:24:24703 return;
704 }
Aaron Tagliaboschi29764f52019-02-21 17:19:59705
706 DCHECK(cc);
Maks Orlovichfdbc8be2019-03-18 18:34:52707 SetCanonicalCookie(std::move(cc), url.scheme(), options, std::move(callback));
[email protected]f48b9432011-01-11 07:25:40708}
709
rdsmithe5c701d2017-07-12 21:50:00710void CookieMonster::DeleteCanonicalCookie(const CanonicalCookie& cookie,
711 DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09712 DCHECK(thread_checker_.CalledOnValidThread());
mmenke24379d52016-02-05 23:50:17713
rdsmithe5c701d2017-07-12 21:50:00714 uint32_t result = 0u;
mmenke24379d52016-02-05 23:50:17715 for (CookieMapItPair its = cookies_.equal_range(GetKey(cookie.Domain()));
716 its.first != its.second; ++its.first) {
Maks Orlovich2896ec3f2018-04-06 13:34:27717 const std::unique_ptr<CanonicalCookie>& candidate = its.first->second;
718 // Historically, this has refused modification if the cookie has changed
719 // value in between the CanonicalCookie object was returned by a getter
720 // and when this ran. The later parts of the conditional (everything but
721 // the equivalence check) attempt to preserve this behavior.
722 if (candidate->IsEquivalent(cookie) &&
Maks Orlovich2896ec3f2018-04-06 13:34:27723 candidate->Value() == cookie.Value()) {
Nick Harper7a6683a2018-01-30 20:42:52724 InternalDeleteCookie(its.first, true, DELETE_COOKIE_EXPLICIT);
rdsmithe5c701d2017-07-12 21:50:00725 result = 1u;
726 break;
mmenke24379d52016-02-05 23:50:17727 }
728 }
rdsmithe5c701d2017-07-12 21:50:00729 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39730 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00731 callback ? base::BindOnce(std::move(callback), result)
732 : base::OnceClosure()));
mmenke24379d52016-02-05 23:50:17733}
734
rdsmithe5c701d2017-07-12 21:50:00735void CookieMonster::DeleteSessionCookies(DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09736 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]264807b2012-04-25 14:49:37737
rdsmitha5beda162017-07-08 13:55:42738 uint32_t num_deleted = 0;
jdoerrie22a91d8b92018-10-05 08:43:26739 for (auto it = cookies_.begin(); it != cookies_.end();) {
740 auto curit = it;
avie7cd11a2016-10-11 02:00:35741 CanonicalCookie* cc = curit->second.get();
[email protected]264807b2012-04-25 14:49:37742 ++it;
743
744 if (!cc->IsPersistent()) {
mkwstbe84af312015-02-20 08:52:45745 InternalDeleteCookie(curit, true, /*sync_to_store*/
[email protected]264807b2012-04-25 14:49:37746 DELETE_COOKIE_EXPIRED);
747 ++num_deleted;
748 }
749 }
750
rdsmithe5c701d2017-07-12 21:50:00751 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39752 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00753 callback ? base::BindOnce(std::move(callback), num_deleted)
754 : base::OnceClosure()));
[email protected]264807b2012-04-25 14:49:37755}
756
erikchen1dd72a72015-05-06 20:45:05757void CookieMonster::MarkCookieStoreAsInitialized() {
mmenkebe0910d2016-03-01 19:09:09758 DCHECK(thread_checker_.CalledOnValidThread());
erikchen1dd72a72015-05-06 20:45:05759 initialized_ = true;
760}
761
762void CookieMonster::FetchAllCookiesIfNecessary() {
mmenkebe0910d2016-03-01 19:09:09763 DCHECK(thread_checker_.CalledOnValidThread());
erikchen1dd72a72015-05-06 20:45:05764 if (store_.get() && !started_fetching_all_cookies_) {
765 started_fetching_all_cookies_ = true;
766 FetchAllCookies();
767 }
768}
769
mmenke74bcbd52016-01-21 17:17:56770void CookieMonster::FetchAllCookies() {
mmenkebe0910d2016-03-01 19:09:09771 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56772 DCHECK(store_.get()) << "Store must exist to initialize";
773 DCHECK(!finished_fetching_all_cookies_)
774 << "All cookies have already been fetched.";
775
776 // We bind in the current time so that we can report the wall-clock time for
777 // loading cookies.
Maks Orlovich108cb4c2019-03-26 20:24:57778 store_->Load(base::BindOnce(&CookieMonster::OnLoaded,
779 weak_ptr_factory_.GetWeakPtr(), TimeTicks::Now()),
Helen Li92a29f102018-08-15 23:02:26780 net_log_);
mmenke74bcbd52016-01-21 17:17:56781}
782
avie7cd11a2016-10-11 02:00:35783void CookieMonster::OnLoaded(
784 TimeTicks beginning_time,
785 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:09786 DCHECK(thread_checker_.CalledOnValidThread());
avie7cd11a2016-10-11 02:00:35787 StoreLoadedCookies(std::move(cookies));
[email protected]c7593fb22011-11-14 23:54:27788 histogram_time_blocked_on_load_->AddTime(TimeTicks::Now() - beginning_time);
[email protected]218aa6a12011-09-13 17:38:38789
790 // Invoke the task queue of cookie request.
791 InvokeQueue();
792}
793
avie7cd11a2016-10-11 02:00:35794void CookieMonster::OnKeyLoaded(
795 const std::string& key,
796 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:09797 DCHECK(thread_checker_.CalledOnValidThread());
798
avie7cd11a2016-10-11 02:00:35799 StoreLoadedCookies(std::move(cookies));
[email protected]85620342011-10-17 17:35:04800
mmenkebe0910d2016-03-01 19:09:09801 auto tasks_pending_for_key = tasks_pending_for_key_.find(key);
[email protected]85620342011-10-17 17:35:04802
mmenkebe0910d2016-03-01 19:09:09803 // TODO(mmenke): Can this be turned into a DCHECK?
804 if (tasks_pending_for_key == tasks_pending_for_key_.end())
805 return;
[email protected]bab72ec2013-10-30 20:50:02806
mmenkebe0910d2016-03-01 19:09:09807 // Run all tasks for the key. Note that running a task can result in multiple
808 // tasks being added to the back of the deque.
809 while (!tasks_pending_for_key->second.empty()) {
rdsmithe5c701d2017-07-12 21:50:00810 base::OnceClosure task = std::move(tasks_pending_for_key->second.front());
mmenkebe0910d2016-03-01 19:09:09811 tasks_pending_for_key->second.pop_front();
rdsmithe5c701d2017-07-12 21:50:00812 std::move(task).Run();
[email protected]85620342011-10-17 17:35:04813 }
mmenkebe0910d2016-03-01 19:09:09814
815 tasks_pending_for_key_.erase(tasks_pending_for_key);
816
817 // This has to be done last, in case running a task queues a new task for the
818 // key, to ensure tasks are run in the correct order.
819 keys_loaded_.insert(key);
[email protected]85620342011-10-17 17:35:04820}
821
[email protected]218aa6a12011-09-13 17:38:38822void CookieMonster::StoreLoadedCookies(
avie7cd11a2016-10-11 02:00:35823 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:09824 DCHECK(thread_checker_.CalledOnValidThread());
825
mmenkebe0910d2016-03-01 19:09:09826 // Even if a key is expired, insert it so it can be garbage collected,
827 // removed, and sync'd.
[email protected]6210ce52013-09-20 03:33:14828 CookieItVector cookies_with_control_chars;
829
avie7cd11a2016-10-11 02:00:35830 for (auto& cookie : cookies) {
Maks Orlovich2b0d5b12018-04-10 19:33:47831 CanonicalCookie* cookie_ptr = cookie.get();
jdoerrie22a91d8b92018-10-05 08:43:26832 auto inserted = InternalInsertCookie(GetKey(cookie_ptr->Domain()),
833 std::move(cookie), false);
Maks Orlovich2b0d5b12018-04-10 19:33:47834 const Time cookie_access_time(cookie_ptr->LastAccessDate());
835 if (earliest_access_time_.is_null() ||
Helen Lid84010b2018-08-22 16:27:44836 cookie_access_time < earliest_access_time_) {
Maks Orlovich2b0d5b12018-04-10 19:33:47837 earliest_access_time_ = cookie_access_time;
Helen Lid84010b2018-08-22 16:27:44838 }
[email protected]f48b9432011-01-11 07:25:40839
Maks Orlovich2b0d5b12018-04-10 19:33:47840 if (ContainsControlCharacter(cookie_ptr->Name()) ||
841 ContainsControlCharacter(cookie_ptr->Value())) {
842 cookies_with_control_chars.push_back(inserted);
[email protected]f48b9432011-01-11 07:25:40843 }
844 }
[email protected]f48b9432011-01-11 07:25:40845
[email protected]6210ce52013-09-20 03:33:14846 // Any cookies that contain control characters that we have loaded from the
847 // persistent store should be deleted. See http://crbug.com/238041.
jdoerrie22a91d8b92018-10-05 08:43:26848 for (auto it = cookies_with_control_chars.begin();
[email protected]6210ce52013-09-20 03:33:14849 it != cookies_with_control_chars.end();) {
jdoerrie22a91d8b92018-10-05 08:43:26850 auto curit = it;
[email protected]6210ce52013-09-20 03:33:14851 ++it;
852
853 InternalDeleteCookie(*curit, true, DELETE_COOKIE_CONTROL_CHAR);
854 }
855
[email protected]f48b9432011-01-11 07:25:40856 // After importing cookies from the PersistentCookieStore, verify that
857 // none of our other constraints are violated.
[email protected]f48b9432011-01-11 07:25:40858 // In particular, the backing store might have given us duplicate cookies.
[email protected]85620342011-10-17 17:35:04859
860 // This method could be called multiple times due to priority loading, thus
861 // cookies loaded in previous runs will be validated again, but this is OK
862 // since they are expected to be much fewer than total DB.
[email protected]f48b9432011-01-11 07:25:40863 EnsureCookiesMapIsValid();
[email protected]218aa6a12011-09-13 17:38:38864}
[email protected]f48b9432011-01-11 07:25:40865
[email protected]218aa6a12011-09-13 17:38:38866void CookieMonster::InvokeQueue() {
mmenkebe0910d2016-03-01 19:09:09867 DCHECK(thread_checker_.CalledOnValidThread());
868
mmenkef49fca0e2016-03-08 12:46:24869 // Move all per-key tasks into the global queue, if there are any. This is
870 // protection about a race where the store learns about all cookies loading
871 // before it learned about the cookies for a key loading.
872
873 // Needed to prevent any recursively queued tasks from going back into the
874 // per-key queues.
875 seen_global_task_ = true;
rdsmithe5c701d2017-07-12 21:50:00876 for (auto& tasks_for_key : tasks_pending_for_key_) {
877 tasks_pending_.insert(tasks_pending_.begin(),
878 std::make_move_iterator(tasks_for_key.second.begin()),
879 std::make_move_iterator(tasks_for_key.second.end()));
mmenkef49fca0e2016-03-08 12:46:24880 }
881 tasks_pending_for_key_.clear();
882
mmenkebe0910d2016-03-01 19:09:09883 while (!tasks_pending_.empty()) {
rdsmithe5c701d2017-07-12 21:50:00884 base::OnceClosure request_task = std::move(tasks_pending_.front());
mmenkef49fca0e2016-03-08 12:46:24885 tasks_pending_.pop_front();
rdsmithe5c701d2017-07-12 21:50:00886 std::move(request_task).Run();
[email protected]218aa6a12011-09-13 17:38:38887 }
mmenkebe0910d2016-03-01 19:09:09888
mmenkef49fca0e2016-03-08 12:46:24889 DCHECK(tasks_pending_for_key_.empty());
890
mmenkebe0910d2016-03-01 19:09:09891 finished_fetching_all_cookies_ = true;
mmenkebe0910d2016-03-01 19:09:09892 keys_loaded_.clear();
[email protected]f48b9432011-01-11 07:25:40893}
894
895void CookieMonster::EnsureCookiesMapIsValid() {
mmenkebe0910d2016-03-01 19:09:09896 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40897
[email protected]f48b9432011-01-11 07:25:40898 // Iterate through all the of the cookies, grouped by host.
jdoerrie22a91d8b92018-10-05 08:43:26899 auto prev_range_end = cookies_.begin();
[email protected]f48b9432011-01-11 07:25:40900 while (prev_range_end != cookies_.end()) {
jdoerrie22a91d8b92018-10-05 08:43:26901 auto cur_range_begin = prev_range_end;
[email protected]f48b9432011-01-11 07:25:40902 const std::string key = cur_range_begin->first; // Keep a copy.
jdoerrie22a91d8b92018-10-05 08:43:26903 auto cur_range_end = cookies_.upper_bound(key);
[email protected]f48b9432011-01-11 07:25:40904 prev_range_end = cur_range_end;
905
906 // Ensure no equivalent cookies for this host.
ellyjonescabf57422015-08-21 18:44:51907 TrimDuplicateCookiesForKey(key, cur_range_begin, cur_range_end);
[email protected]f48b9432011-01-11 07:25:40908 }
[email protected]f48b9432011-01-11 07:25:40909}
910
ellyjonescabf57422015-08-21 18:44:51911void CookieMonster::TrimDuplicateCookiesForKey(const std::string& key,
912 CookieMap::iterator begin,
913 CookieMap::iterator end) {
mmenkebe0910d2016-03-01 19:09:09914 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40915
916 // Set of cookies ordered by creation time.
Maks Orlovich2b0d5b12018-04-10 19:33:47917 typedef std::multiset<CookieMap::iterator, OrderByCreationTimeDesc> CookieSet;
[email protected]f48b9432011-01-11 07:25:40918
919 // Helper map we populate to find the duplicates.
920 typedef std::map<CookieSignature, CookieSet> EquivalenceMap;
921 EquivalenceMap equivalent_cookies;
922
923 // The number of duplicate cookies that have been found.
924 int num_duplicates = 0;
925
926 // Iterate through all of the cookies in our range, and insert them into
927 // the equivalence map.
jdoerrie22a91d8b92018-10-05 08:43:26928 for (auto it = begin; it != end; ++it) {
[email protected]f48b9432011-01-11 07:25:40929 DCHECK_EQ(key, it->first);
avie7cd11a2016-10-11 02:00:35930 CanonicalCookie* cookie = it->second.get();
[email protected]f48b9432011-01-11 07:25:40931
mkwstbe84af312015-02-20 08:52:45932 CookieSignature signature(cookie->Name(), cookie->Domain(), cookie->Path());
[email protected]f48b9432011-01-11 07:25:40933 CookieSet& set = equivalent_cookies[signature];
934
935 // We found a duplicate!
936 if (!set.empty())
937 num_duplicates++;
938
939 // We save the iterator into |cookies_| rather than the actual cookie
940 // pointer, since we may need to delete it later.
Maks Orlovich2b0d5b12018-04-10 19:33:47941 set.insert(it);
[email protected]f48b9432011-01-11 07:25:40942 }
943
944 // If there were no duplicates, we are done!
945 if (num_duplicates == 0)
ellyjonescabf57422015-08-21 18:44:51946 return;
[email protected]f48b9432011-01-11 07:25:40947
948 // Make sure we find everything below that we did above.
949 int num_duplicates_found = 0;
950
951 // Otherwise, delete all the duplicate cookies, both from our in-memory store
952 // and from the backing store.
jdoerrie22a91d8b92018-10-05 08:43:26953 for (auto it = equivalent_cookies.begin(); it != equivalent_cookies.end();
954 ++it) {
[email protected]f48b9432011-01-11 07:25:40955 const CookieSignature& signature = it->first;
956 CookieSet& dupes = it->second;
957
958 if (dupes.size() <= 1)
959 continue; // This cookiename/path has no duplicates.
960 num_duplicates_found += dupes.size() - 1;
961
Maks Orlovich2b0d5b12018-04-10 19:33:47962 // Since |dupes| is sorted by creation time (descending), the first cookie
963 // is the most recent one (or tied for it), so we will keep it. The rest are
964 // duplicates.
[email protected]f48b9432011-01-11 07:25:40965 dupes.erase(dupes.begin());
966
967 LOG(ERROR) << base::StringPrintf(
968 "Found %d duplicate cookies for host='%s', "
969 "with {name='%s', domain='%s', path='%s'}",
mkwstbe84af312015-02-20 08:52:45970 static_cast<int>(dupes.size()), key.c_str(), signature.name.c_str(),
971 signature.domain.c_str(), signature.path.c_str());
[email protected]f48b9432011-01-11 07:25:40972
973 // Remove all the cookies identified by |dupes|. It is valid to delete our
974 // list of iterators one at a time, since |cookies_| is a multimap (they
975 // don't invalidate existing iterators following deletion).
jdoerrie22a91d8b92018-10-05 08:43:26976 for (auto dupes_it = dupes.begin(); dupes_it != dupes.end(); ++dupes_it) {
[email protected]218aa6a12011-09-13 17:38:38977 InternalDeleteCookie(*dupes_it, true,
[email protected]f48b9432011-01-11 07:25:40978 DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE);
979 }
980 }
981 DCHECK_EQ(num_duplicates, num_duplicates_found);
[email protected]f48b9432011-01-11 07:25:40982}
983
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:52984void CookieMonster::FindCookiesForRegistryControlledHost(
[email protected]f48b9432011-01-11 07:25:40985 const GURL& url,
[email protected]f48b9432011-01-11 07:25:40986 std::vector<CanonicalCookie*>* cookies) {
mmenkebe0910d2016-03-01 19:09:09987 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40988
Maks Orlovichc86cf292019-02-11 19:25:17989 Time current_time = Time::Now();
[email protected]f48b9432011-01-11 07:25:40990
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:52991 // Retrieve all cookies for a given key
Maks Orlovich323efaf2018-03-06 02:56:39992 const std::string key(GetKey(url.host_piece()));
Aaron Tagliaboschi9e1de1b2019-01-15 14:40:06993
[email protected]f48b9432011-01-11 07:25:40994 for (CookieMapItPair its = cookies_.equal_range(key);
mkwstbe84af312015-02-20 08:52:45995 its.first != its.second;) {
jdoerrie22a91d8b92018-10-05 08:43:26996 auto curit = its.first;
avie7cd11a2016-10-11 02:00:35997 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:40998 ++its.first;
999
1000 // If the cookie is expired, delete it.
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521001 if (cc->IsExpired(current_time)) {
[email protected]f48b9432011-01-11 07:25:401002 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
1003 continue;
1004 }
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521005 cookies->push_back(cc);
Aaron Tagliaboschi9e1de1b2019-01-15 14:40:061006 }
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521007}
[email protected]f48b9432011-01-11 07:25:401008
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521009void CookieMonster::FilterCookiesWithOptions(
1010 const GURL url,
1011 const CookieOptions options,
1012 std::vector<CanonicalCookie*>* cookie_ptrs,
Aaron Tagliaboschi29033b7f2019-01-31 19:58:201013 std::vector<CanonicalCookie*>* included_cookie_ptrs,
1014 CookieStatusList* excluded_cookies) {
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521015 DCHECK(thread_checker_.CalledOnValidThread());
1016
1017 // Probe to save statistics relatively frequently. We do it here rather
1018 // than in the set path as many websites won't set cookies, and we
1019 // want to collect statistics whenever the browser's being used.
Maks Orlovichc86cf292019-02-11 19:25:171020 Time current_time = Time::Now();
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521021 RecordPeriodicStats(current_time);
1022
1023 for (std::vector<CanonicalCookie*>::iterator it = cookie_ptrs->begin();
1024 it != cookie_ptrs->end(); it++) {
[email protected]65f4e7e2012-12-12 21:56:541025 // Filter out cookies that should not be included for a request to the
1026 // given |url|. HTTP only cookies are filtered depending on the passed
1027 // cookie |options|.
Aaron Tagliaboschi29033b7f2019-01-31 19:58:201028 CanonicalCookie::CookieInclusionStatus status =
1029 (*it)->IncludeForRequestURL(url, options);
1030
1031 if (status != CanonicalCookie::CookieInclusionStatus::INCLUDE) {
1032 if (options.return_excluded_cookies())
1033 excluded_cookies->push_back({**it, status});
[email protected]f48b9432011-01-11 07:25:401034 continue;
[email protected]f48b9432011-01-11 07:25:401035 }
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521036
1037 if (options.update_access_time())
1038 InternalUpdateCookieAccessTime(*it, current_time);
1039
Aaron Tagliaboschi29033b7f2019-01-31 19:58:201040 included_cookie_ptrs->push_back(*it);
[email protected]f48b9432011-01-11 07:25:401041 }
1042}
1043
Aaron Tagliaboschi29764f52019-02-21 17:19:591044CanonicalCookie::CookieInclusionStatus CookieMonster::DeleteAnyEquivalentCookie(
Mike Westc4a777b2017-10-06 14:04:201045 const std::string& key,
1046 const CanonicalCookie& ecc,
1047 bool source_secure,
1048 bool skip_httponly,
1049 bool already_expired,
1050 base::Time* creation_date_to_inherit) {
mmenkebe0910d2016-03-01 19:09:091051 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401052
1053 bool found_equivalent_cookie = false;
1054 bool skipped_httponly = false;
jww601411a2015-11-20 19:46:571055 bool skipped_secure_cookie = false;
jww31e32632015-12-16 23:38:341056
1057 histogram_cookie_delete_equivalent_->Add(COOKIE_DELETE_EQUIVALENT_ATTEMPT);
1058
Lily Chen22707642b2018-10-02 17:27:211059 CookieMap::iterator cookie_it_to_possibly_delete = cookies_.end();
1060 CanonicalCookie* cc_skipped_secure = nullptr;
[email protected]f48b9432011-01-11 07:25:401061 for (CookieMapItPair its = cookies_.equal_range(key);
mkwstbe84af312015-02-20 08:52:451062 its.first != its.second;) {
jdoerrie22a91d8b92018-10-05 08:43:261063 auto curit = its.first;
avie7cd11a2016-10-11 02:00:351064 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:401065 ++its.first;
1066
jwwa26e439d2017-01-27 18:17:271067 // If the cookie is being set from an insecure scheme, then if a cookie
1068 // already exists with the same name and it is Secure, then the cookie
1069 // should *not* be updated if they domain-match and ignoring the path
1070 // attribute.
jww601411a2015-11-20 19:46:571071 //
jwwa26e439d2017-01-27 18:17:271072 // See: https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone
rdsmith2709eee2017-06-20 22:43:271073 if (cc->IsSecure() && !source_secure &&
mmenke2830b0722016-07-20 16:02:501074 ecc.IsEquivalentForSecureCookieMatching(*cc)) {
jww601411a2015-11-20 19:46:571075 skipped_secure_cookie = true;
Lily Chen22707642b2018-10-02 17:27:211076 cc_skipped_secure = cc;
jww31e32632015-12-16 23:38:341077 histogram_cookie_delete_equivalent_->Add(
1078 COOKIE_DELETE_EQUIVALENT_SKIPPING_SECURE);
Helen Licd0fab862018-08-13 16:07:531079 net_log_.AddEvent(
1080 NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_SECURE,
1081 base::BindRepeating(&NetLogCookieMonsterCookieRejectedSecure, cc,
1082 &ecc));
jww31e32632015-12-16 23:38:341083 // If the cookie is equivalent to the new cookie and wouldn't have been
1084 // skipped for being HTTP-only, record that it is a skipped secure cookie
1085 // that would have been deleted otherwise.
1086 if (ecc.IsEquivalent(*cc)) {
jwwa9a0d482015-12-16 18:19:411087 found_equivalent_cookie = true;
jww31e32632015-12-16 23:38:341088
1089 if (!skip_httponly || !cc->IsHttpOnly()) {
1090 histogram_cookie_delete_equivalent_->Add(
1091 COOKIE_DELETE_EQUIVALENT_WOULD_HAVE_DELETED);
1092 }
1093 }
jww601411a2015-11-20 19:46:571094 } else if (ecc.IsEquivalent(*cc)) {
[email protected]f48b9432011-01-11 07:25:401095 // We should never have more than one equivalent cookie, since they should
jww601411a2015-11-20 19:46:571096 // overwrite each other, unless secure cookies require secure scheme is
1097 // being enforced. In that case, cookies with different paths might exist
1098 // and be considered equivalent.
mkwstbe84af312015-02-20 08:52:451099 CHECK(!found_equivalent_cookie)
1100 << "Duplicate equivalent cookies found, cookie store is corrupted.";
Lily Chen22707642b2018-10-02 17:27:211101 DCHECK(cookie_it_to_possibly_delete == cookies_.end());
[email protected]f48b9432011-01-11 07:25:401102 if (skip_httponly && cc->IsHttpOnly()) {
1103 skipped_httponly = true;
Helen Licd0fab862018-08-13 16:07:531104 net_log_.AddEvent(
1105 NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_HTTPONLY,
1106 base::BindRepeating(&NetLogCookieMonsterCookieRejectedHttponly, cc,
1107 &ecc));
[email protected]f48b9432011-01-11 07:25:401108 } else {
Lily Chen22707642b2018-10-02 17:27:211109 cookie_it_to_possibly_delete = curit;
[email protected]f48b9432011-01-11 07:25:401110 }
1111 found_equivalent_cookie = true;
1112 }
1113 }
Lily Chen22707642b2018-10-02 17:27:211114
1115 if (cookie_it_to_possibly_delete != cookies_.end()) {
1116 CanonicalCookie* cc_to_possibly_delete =
1117 cookie_it_to_possibly_delete->second.get();
1118 // If a secure cookie was encountered (and left alone), don't actually
1119 // modify any of the pre-existing cookies. Only delete if no secure cookies
1120 // were skipped.
1121 if (!skipped_secure_cookie) {
1122 histogram_cookie_delete_equivalent_->Add(COOKIE_DELETE_EQUIVALENT_FOUND);
1123 if (cc_to_possibly_delete->Value() == ecc.Value()) {
1124 *creation_date_to_inherit = cc_to_possibly_delete->CreationDate();
1125 histogram_cookie_delete_equivalent_->Add(
1126 COOKIE_DELETE_EQUIVALENT_FOUND_WITH_SAME_VALUE);
1127 }
1128 InternalDeleteCookie(cookie_it_to_possibly_delete, true,
1129 already_expired ? DELETE_COOKIE_EXPIRED_OVERWRITE
1130 : DELETE_COOKIE_OVERWRITE);
1131 } else {
1132 // If any secure cookie was skipped, preserve the pre-existing cookie.
1133 DCHECK(cc_skipped_secure);
1134 net_log_.AddEvent(
1135 NetLogEventType::COOKIE_STORE_COOKIE_PRESERVED_SKIPPED_SECURE,
1136 base::BindRepeating(&NetLogCookieMonsterCookiePreservedSkippedSecure,
1137 cc_skipped_secure, cc_to_possibly_delete, &ecc));
1138 }
1139 }
1140
Aaron Tagliaboschi29764f52019-02-21 17:19:591141 if (skipped_httponly)
1142 return CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY;
1143
1144 if (skipped_secure_cookie)
1145 return CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE;
1146
1147 return CanonicalCookie::CookieInclusionStatus::INCLUDE;
[email protected]f48b9432011-01-11 07:25:401148}
1149
[email protected]6210ce52013-09-20 03:33:141150CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie(
1151 const std::string& key,
avie7cd11a2016-10-11 02:00:351152 std::unique_ptr<CanonicalCookie> cc,
[email protected]6210ce52013-09-20 03:33:141153 bool sync_to_store) {
mmenkebe0910d2016-03-01 19:09:091154 DCHECK(thread_checker_.CalledOnValidThread());
avie7cd11a2016-10-11 02:00:351155 CanonicalCookie* cc_ptr = cc.get();
mmenkebe0910d2016-03-01 19:09:091156
Helen Licd0fab862018-08-13 16:07:531157 net_log_.AddEvent(NetLogEventType::COOKIE_STORE_COOKIE_ADDED,
1158 base::BindRepeating(&NetLogCookieMonsterCookieAdded,
1159 cc.get(), sync_to_store));
avie7cd11a2016-10-11 02:00:351160 if ((cc_ptr->IsPersistent() || persist_session_cookies_) && store_.get() &&
Helen Lid84010b2018-08-22 16:27:441161 sync_to_store) {
avie7cd11a2016-10-11 02:00:351162 store_->AddCookie(*cc_ptr);
Helen Lid84010b2018-08-22 16:27:441163 }
jdoerrie22a91d8b92018-10-05 08:43:261164 auto inserted = cookies_.insert(CookieMap::value_type(key, std::move(cc)));
mkwstc1aa4cc2015-04-03 19:57:451165
1166 // See InitializeHistograms() for details.
Lily Chenf93d43e2019-04-18 20:22:021167 int32_t type_sample =
1168 cc_ptr->GetEffectiveSameSite() != CookieSameSite::NO_RESTRICTION
1169 ? 1 << COOKIE_TYPE_SAME_SITE
1170 : 0;
avie7cd11a2016-10-11 02:00:351171 type_sample |= cc_ptr->IsHttpOnly() ? 1 << COOKIE_TYPE_HTTPONLY : 0;
1172 type_sample |= cc_ptr->IsSecure() ? 1 << COOKIE_TYPE_SECURE : 0;
mkwst46549412016-02-01 10:05:371173 histogram_cookie_type_->Add(type_sample);
estark7feb65c2b2015-08-21 23:38:201174
Victor Costan14f47c12018-03-01 08:02:241175 change_dispatcher_.DispatchChange(*cc_ptr, CookieChangeCause::INSERTED, true);
[email protected]6210ce52013-09-20 03:33:141176
1177 return inserted;
[email protected]f48b9432011-01-11 07:25:401178}
1179
rdsmithe5c701d2017-07-12 21:50:001180void CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc,
Maks Orlovich44525ce2019-02-25 14:17:581181 std::string source_scheme,
Maks Orlovichfdbc8be2019-03-18 18:34:521182 const CookieOptions& options,
rdsmithe5c701d2017-07-12 21:50:001183 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:091184 DCHECK(thread_checker_.CalledOnValidThread());
1185
Maks Orlovich44525ce2019-02-25 14:17:581186 std::string scheme_lower = base::ToLowerASCII(source_scheme);
1187 bool secure_source = GURL::SchemeIsCryptographic(scheme_lower);
Aaron Tagliaboschi29764f52019-02-21 17:19:591188 if ((cc->IsSecure() && !secure_source)) {
1189 MaybeRunCookieCallback(
1190 std::move(callback),
1191 CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY);
1192 return;
1193 }
1194
Maks Orlovich8a3e4132019-04-23 16:59:241195 CanonicalCookie::CookieInclusionStatus status =
1196 cc->IsSetPermittedInContext(options);
1197 if (status != CanonicalCookie::CookieInclusionStatus::INCLUDE) {
1198 // IsSetPermittedInContext already logs if it rejects a cookie, so
1199 // CookieMonster doesn't need to.
1200 MaybeRunCookieCallback(std::move(callback), status);
rdsmithe5c701d2017-07-12 21:50:001201 return;
1202 }
rdsmith2709eee2017-06-20 22:43:271203
Maks Orlovich44525ce2019-02-25 14:17:581204 if (!IsCookieableScheme(scheme_lower)) {
1205 MaybeRunCookieCallback(
1206 std::move(callback),
1207 CanonicalCookie::CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME);
1208 return;
1209 }
1210
Lily Chen8a648cb72019-04-25 20:29:151211 // If both SameSiteByDefaultCookies and CookiesWithoutSameSiteMustBeSecure
1212 // are enabled, non-SameSite cookies without the Secure attribute will be
Lily Chend3bf638d2019-05-03 16:54:251213 // rejected.
Lily Chen8a648cb72019-04-25 20:29:151214 if (base::FeatureList::IsEnabled(features::kSameSiteByDefaultCookies) &&
1215 base::FeatureList::IsEnabled(
1216 features::kCookiesWithoutSameSiteMustBeSecure) &&
1217 cc->GetEffectiveSameSite() == CookieSameSite::NO_RESTRICTION &&
1218 !cc->IsSecure()) {
Lily Chen8a648cb72019-04-25 20:29:151219 DVLOG(net::cookie_util::kVlogSetCookies)
Lily Chend3bf638d2019-05-03 16:54:251220 << "SetCookie() rejecting insecure cookie with SameSite=None.";
1221 status =
1222 CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE;
1223 MaybeRunCookieCallback(std::move(callback), status);
1224 return;
Lily Chen8a648cb72019-04-25 20:29:151225 }
1226
mmenkeea4cd402016-02-02 04:03:101227 const std::string key(GetKey(cc->Domain()));
rdsmitha6ce4442017-06-21 17:11:051228
rdsmitha6ce4442017-06-21 17:11:051229 base::Time creation_date = cc->CreationDate();
1230 if (creation_date.is_null()) {
Maks Orlovichc86cf292019-02-11 19:25:171231 creation_date = Time::Now();
rdsmitha6ce4442017-06-21 17:11:051232 cc->SetCreationDate(creation_date);
rdsmitha6ce4442017-06-21 17:11:051233 }
1234 bool already_expired = cc->IsExpired(creation_date);
ellyjones399e35a22014-10-27 11:09:561235
Mike Westc4a777b2017-10-06 14:04:201236 base::Time creation_date_to_inherit;
Aaron Tagliaboschi29764f52019-02-21 17:19:591237
Maks Orlovich8a3e4132019-04-23 16:59:241238 status = DeleteAnyEquivalentCookie(
Maks Orlovichfdbc8be2019-03-18 18:34:521239 key, *cc, secure_source, options.exclude_httponly(), already_expired,
1240 &creation_date_to_inherit);
Aaron Tagliaboschi29764f52019-02-21 17:19:591241
1242 if (status != CanonicalCookie::CookieInclusionStatus::INCLUDE) {
jww601411a2015-11-20 19:46:571243 std::string error;
jwwa26e439d2017-01-27 18:17:271244 error =
1245 "SetCookie() not clobbering httponly cookie or secure cookie for "
1246 "insecure scheme";
jww601411a2015-11-20 19:46:571247
Maks Orlovich35d74c042019-04-18 16:38:011248 DVLOG(net::cookie_util::kVlogSetCookies) << error;
Aaron Tagliaboschi29764f52019-02-21 17:19:591249 MaybeRunCookieCallback(std::move(callback), status);
rdsmithe5c701d2017-07-12 21:50:001250 return;
[email protected]3a96c742008-11-19 19:46:271251 }
initial.commit586acc5fe2008-07-26 22:42:521252
Maks Orlovich35d74c042019-04-18 16:38:011253 DVLOG(net::cookie_util::kVlogSetCookies)
Oscar Johansson63e83cf2018-07-02 08:47:261254 << "SetCookie() key: " << key << " cc: " << cc->DebugString();
initial.commit586acc5fe2008-07-26 22:42:521255
1256 // Realize that we might be setting an expired cookie, and the only point
1257 // was to delete the cookie which we've already done.
mmenke3c79a652016-02-12 14:39:201258 if (!already_expired) {
[email protected]374f58b2010-07-20 15:29:261259 // See InitializeHistograms() for details.
mmenkeea4cd402016-02-02 04:03:101260 if (cc->IsPersistent()) {
[email protected]8475bee2011-03-17 18:40:241261 histogram_expiration_duration_minutes_->Add(
rdsmitha6ce4442017-06-21 17:11:051262 (cc->ExpiryDate() - creation_date).InMinutes());
[email protected]8475bee2011-03-17 18:40:241263 }
1264
rdsmith2709eee2017-06-20 22:43:271265 // Histogram the type of scheme used on URLs that set cookies. This
1266 // intentionally includes cookies that are set or overwritten by
1267 // http:// URLs, but not cookies that are cleared by http:// URLs, to
1268 // understand if the former behavior can be deprecated for Secure
1269 // cookies.
1270 CookieSource cookie_source_sample =
1271 (secure_source
1272 ? (cc->IsSecure()
1273 ? COOKIE_SOURCE_SECURE_COOKIE_CRYPTOGRAPHIC_SCHEME
1274 : COOKIE_SOURCE_NONSECURE_COOKIE_CRYPTOGRAPHIC_SCHEME)
1275 : (cc->IsSecure()
1276 ? COOKIE_SOURCE_SECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME
1277 : COOKIE_SOURCE_NONSECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME));
1278 histogram_cookie_source_scheme_->Add(cookie_source_sample);
1279
Mike Westc4a777b2017-10-06 14:04:201280 if (!creation_date_to_inherit.is_null()) {
1281 cc->SetCreationDate(creation_date_to_inherit);
Mike Westc4a777b2017-10-06 14:04:201282 }
1283
rdsmith2709eee2017-06-20 22:43:271284 InternalInsertCookie(key, std::move(cc), true);
[email protected]348dd662013-03-13 20:25:071285 } else {
Maks Orlovich35d74c042019-04-18 16:38:011286 DVLOG(net::cookie_util::kVlogSetCookies)
Oscar Johansson63e83cf2018-07-02 08:47:261287 << "SetCookie() not storing already expired cookie.";
[email protected]c4058fb2010-06-22 17:25:261288 }
initial.commit586acc5fe2008-07-26 22:42:521289
1290 // We assume that hopefully setting a cookie will be less common than
1291 // querying a cookie. Since setting a cookie can put us over our limits,
1292 // make sure that we garbage collect... We can also make the assumption that
1293 // if a cookie was set, in the common case it will be used soon after,
1294 // and we will purge the expired cookies in GetCookies().
rdsmitha6ce4442017-06-21 17:11:051295 GarbageCollect(creation_date, key);
initial.commit586acc5fe2008-07-26 22:42:521296
Aaron Tagliaboschi29764f52019-02-21 17:19:591297 MaybeRunCookieCallback(std::move(callback),
1298 CanonicalCookie::CookieInclusionStatus::INCLUDE);
initial.commit586acc5fe2008-07-26 22:42:521299}
1300
rdsmithe5c701d2017-07-12 21:50:001301void CookieMonster::SetAllCookies(CookieList list,
1302 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:091303 DCHECK(thread_checker_.CalledOnValidThread());
rdsmithe5c701d2017-07-12 21:50:001304
rdsmith0e84cea2017-07-13 03:09:531305 // Nuke the existing store.
1306 while (!cookies_.empty()) {
1307 // TODO(rdsmith): The CANONICAL is a lie.
Nick Harper7a6683a2018-01-30 20:42:521308 InternalDeleteCookie(cookies_.begin(), true, DELETE_COOKIE_EXPLICIT);
rdsmithe5c701d2017-07-12 21:50:001309 }
1310
rdsmith0e84cea2017-07-13 03:09:531311 // Set all passed in cookies.
mmenkeea4cd402016-02-02 04:03:101312 for (const auto& cookie : list) {
rdsmith2709eee2017-06-20 22:43:271313 const std::string key(GetKey(cookie.Domain()));
1314 Time creation_time = cookie.CreationDate();
rdsmith0e84cea2017-07-13 03:09:531315 if (cookie.IsExpired(creation_time))
rdsmith2709eee2017-06-20 22:43:271316 continue;
1317
1318 if (cookie.IsPersistent()) {
1319 histogram_expiration_duration_minutes_->Add(
1320 (cookie.ExpiryDate() - creation_time).InMinutes());
mmenkeea4cd402016-02-02 04:03:101321 }
rdsmith2709eee2017-06-20 22:43:271322
Jeremy Roman0579ed62017-08-29 15:56:191323 InternalInsertCookie(key, std::make_unique<CanonicalCookie>(cookie), true);
rdsmith2709eee2017-06-20 22:43:271324 GarbageCollect(creation_time, key);
drogerd5d1278c2015-03-17 19:21:511325 }
1326
rdsmith2709eee2017-06-20 22:43:271327 // TODO(rdsmith): If this function always returns the same value, it
1328 // shouldn't have a return value. But it should also be deleted (see
1329 // https://codereview.chromium.org/2882063002/#msg64), which would
1330 // solve the return value problem.
Aaron Tagliaboschi29764f52019-02-21 17:19:591331 MaybeRunCookieCallback(std::move(callback),
1332 CanonicalCookie::CookieInclusionStatus::INCLUDE);
drogerd5d1278c2015-03-17 19:21:511333}
1334
[email protected]7a964a72010-09-07 19:33:261335void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc,
1336 const Time& current) {
mmenkebe0910d2016-03-01 19:09:091337 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041338
[email protected]77e0a462008-11-01 00:43:351339 // Based off the Mozilla code. When a cookie has been accessed recently,
1340 // don't bother updating its access time again. This reduces the number of
1341 // updates we do during pageload, which in turn reduces the chance our storage
1342 // backend will hit its batch thresholds and be forced to update.
[email protected]77e0a462008-11-01 00:43:351343 if ((current - cc->LastAccessDate()) < last_access_threshold_)
1344 return;
1345
1346 cc->SetLastAccessDate(current);
[email protected]90499482013-06-01 00:39:501347 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get())
[email protected]77e0a462008-11-01 00:43:351348 store_->UpdateCookieAccessTime(*cc);
1349}
1350
[email protected]6210ce52013-09-20 03:33:141351// InternalDeleteCookies must not invalidate iterators other than the one being
1352// deleted.
initial.commit586acc5fe2008-07-26 22:42:521353void CookieMonster::InternalDeleteCookie(CookieMap::iterator it,
[email protected]c4058fb2010-06-22 17:25:261354 bool sync_to_store,
1355 DeletionCause deletion_cause) {
mmenkebe0910d2016-03-01 19:09:091356 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041357
nharper352933e2016-09-30 18:24:571358 // Ideally, this would be asserted up where we define kChangeCauseMapping,
[email protected]8bb846f2011-03-23 12:08:181359 // but DeletionCause's visibility (or lack thereof) forces us to make
1360 // this check here.
Ryan Sleevi435a3a22018-05-15 02:16:071361 static_assert(base::size(kChangeCauseMapping) == DELETE_COOKIE_LAST_ENTRY + 1,
nharper352933e2016-09-30 18:24:571362 "kChangeCauseMapping size should match DeletionCause size");
[email protected]8bb846f2011-03-23 12:08:181363
avie7cd11a2016-10-11 02:00:351364 CanonicalCookie* cc = it->second.get();
Maks Orlovich35d74c042019-04-18 16:38:011365 DVLOG(net::cookie_util::kVlogSetCookies)
Oscar Johansson63e83cf2018-07-02 08:47:261366 << "InternalDeleteCookie()"
1367 << ", cause:" << deletion_cause << ", cc: " << cc->DebugString();
[email protected]7a964a72010-09-07 19:33:261368
Helen Licd0fab862018-08-13 16:07:531369 ChangeCausePair mapping = kChangeCauseMapping[deletion_cause];
1370 if (deletion_cause != DELETE_COOKIE_DONT_RECORD) {
1371 net_log_.AddEvent(NetLogEventType::COOKIE_STORE_COOKIE_DELETED,
1372 base::BindRepeating(&NetLogCookieMonsterCookieDeleted, cc,
1373 mapping.cause, sync_to_store));
1374 }
1375
[email protected]90499482013-06-01 00:39:501376 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get() &&
Helen Lid84010b2018-08-22 16:27:441377 sync_to_store) {
initial.commit586acc5fe2008-07-26 22:42:521378 store_->DeleteCookie(*cc);
Helen Lid84010b2018-08-22 16:27:441379 }
Victor Costan14f47c12018-03-01 08:02:241380 change_dispatcher_.DispatchChange(*cc, mapping.cause, mapping.notify);
initial.commit586acc5fe2008-07-26 22:42:521381 cookies_.erase(it);
initial.commit586acc5fe2008-07-26 22:42:521382}
1383
[email protected]8807b322010-10-01 17:10:141384// Domain expiry behavior is unchanged by key/expiry scheme (the
[email protected]8ad5d462013-05-02 08:45:261385// meaning of the key is different, but that's not visible to this routine).
jww82d99c12015-11-25 18:39:531386size_t CookieMonster::GarbageCollect(const Time& current,
jwwa26e439d2017-01-27 18:17:271387 const std::string& key) {
mmenkebe0910d2016-03-01 19:09:091388 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041389
jww82d99c12015-11-25 18:39:531390 size_t num_deleted = 0;
mkwstbe84af312015-02-20 08:52:451391 Time safe_date(Time::Now() - TimeDelta::FromDays(kSafeFromGlobalPurgeDays));
initial.commit586acc5fe2008-07-26 22:42:521392
[email protected]8ad5d462013-05-02 08:45:261393 // Collect garbage for this key, minding cookie priorities.
[email protected]7a964a72010-09-07 19:33:261394 if (cookies_.count(key) > kDomainMaxCookies) {
Maks Orlovich35d74c042019-04-18 16:38:011395 DVLOG(net::cookie_util::kVlogGarbageCollection)
Oscar Johansson63e83cf2018-07-02 08:47:261396 << "GarbageCollect() key: " << key;
[email protected]7a964a72010-09-07 19:33:261397
mkwst87734352016-03-03 17:36:231398 CookieItVector* cookie_its;
jww601411a2015-11-20 19:46:571399
mkwst87734352016-03-03 17:36:231400 CookieItVector non_expired_cookie_its;
1401 cookie_its = &non_expired_cookie_its;
jww82d99c12015-11-25 18:39:531402 num_deleted +=
mkwst87734352016-03-03 17:36:231403 GarbageCollectExpired(current, cookies_.equal_range(key), cookie_its);
jww82d99c12015-11-25 18:39:531404
mkwst87734352016-03-03 17:36:231405 if (cookie_its->size() > kDomainMaxCookies) {
Maks Orlovich35d74c042019-04-18 16:38:011406 DVLOG(net::cookie_util::kVlogGarbageCollection)
Oscar Johansson63e83cf2018-07-02 08:47:261407 << "Deep Garbage Collect domain.";
[email protected]8ad5d462013-05-02 08:45:261408 size_t purge_goal =
mkwst87734352016-03-03 17:36:231409 cookie_its->size() - (kDomainMaxCookies - kDomainPurgeCookies);
[email protected]8ad5d462013-05-02 08:45:261410 DCHECK(purge_goal > kDomainPurgeCookies);
1411
mkwste079ac412016-03-11 09:04:061412 // Sort the cookies by access date, from least-recent to most-recent.
1413 std::sort(cookie_its->begin(), cookie_its->end(), LRACookieSorter);
[email protected]8ad5d462013-05-02 08:45:261414
mkwste079ac412016-03-11 09:04:061415 // Remove all but the kDomainCookiesQuotaLow most-recently accessed
1416 // cookies with low-priority. Then, if cookies still need to be removed,
1417 // bump the quota and remove low- and medium-priority. Then, if cookies
1418 // _still_ need to be removed, bump the quota and remove cookies with
1419 // any priority.
jwwc00ac712016-05-05 22:21:441420 //
1421 // 1. Low-priority non-secure cookies.
1422 // 2. Low-priority secure cookies.
1423 // 3. Medium-priority non-secure cookies.
1424 // 4. High-priority non-secure cookies.
1425 // 5. Medium-priority secure cookies.
1426 // 6. High-priority secure cookies.
1427 const static struct {
1428 CookiePriority priority;
1429 bool protect_secure_cookies;
1430 } purge_rounds[] = {
1431 // 1. Low-priority non-secure cookies.
1432 {COOKIE_PRIORITY_LOW, true},
1433 // 2. Low-priority secure cookies.
1434 {COOKIE_PRIORITY_LOW, false},
1435 // 3. Medium-priority non-secure cookies.
1436 {COOKIE_PRIORITY_MEDIUM, true},
1437 // 4. High-priority non-secure cookies.
1438 {COOKIE_PRIORITY_HIGH, true},
1439 // 5. Medium-priority secure cookies.
1440 {COOKIE_PRIORITY_MEDIUM, false},
1441 // 6. High-priority secure cookies.
1442 {COOKIE_PRIORITY_HIGH, false},
1443 };
1444
mkwste079ac412016-03-11 09:04:061445 size_t quota = 0;
jwwc00ac712016-05-05 22:21:441446 for (const auto& purge_round : purge_rounds) {
mmenke645ca6772016-06-17 18:46:431447 // Adjust quota according to the priority of cookies. Each round should
1448 // protect certain number of cookies in order to avoid starvation.
1449 // For example, when each round starts to remove cookies, the number of
1450 // cookies of that priority are counted and a decision whether they
1451 // should be deleted or not is made. If yes, some number of cookies of
1452 // that priority are deleted considering the quota.
jwwc00ac712016-05-05 22:21:441453 switch (purge_round.priority) {
1454 case COOKIE_PRIORITY_LOW:
mmenke645ca6772016-06-17 18:46:431455 quota = kDomainCookiesQuotaLow;
jwwc00ac712016-05-05 22:21:441456 break;
1457 case COOKIE_PRIORITY_MEDIUM:
mmenke645ca6772016-06-17 18:46:431458 quota = kDomainCookiesQuotaMedium;
jwwc00ac712016-05-05 22:21:441459 break;
1460 case COOKIE_PRIORITY_HIGH:
mmenke645ca6772016-06-17 18:46:431461 quota = kDomainCookiesQuotaHigh;
jwwc00ac712016-05-05 22:21:441462 break;
1463 }
jwwc00ac712016-05-05 22:21:441464 size_t just_deleted = 0u;
jwwa26e439d2017-01-27 18:17:271465 // Purge up to |purge_goal| for all cookies at the given priority. This
1466 // path will be taken only if the initial non-secure purge did not evict
1467 // enough cookies.
jwwc00ac712016-05-05 22:21:441468 if (purge_goal > 0) {
1469 just_deleted = PurgeLeastRecentMatches(
1470 cookie_its, purge_round.priority, quota, purge_goal,
1471 purge_round.protect_secure_cookies);
1472 DCHECK_LE(just_deleted, purge_goal);
1473 purge_goal -= just_deleted;
1474 num_deleted += just_deleted;
1475 }
mkwst162d2712016-02-18 18:21:291476 }
mkwste079ac412016-03-11 09:04:061477
jwwc00ac712016-05-05 22:21:441478 DCHECK_EQ(0u, purge_goal);
[email protected]8807b322010-10-01 17:10:141479 }
initial.commit586acc5fe2008-07-26 22:42:521480 }
1481
[email protected]8ad5d462013-05-02 08:45:261482 // Collect garbage for everything. With firefox style we want to preserve
1483 // cookies accessed in kSafeFromGlobalPurgeDays, otherwise evict.
mkwstbe84af312015-02-20 08:52:451484 if (cookies_.size() > kMaxCookies && earliest_access_time_ < safe_date) {
Maks Orlovich35d74c042019-04-18 16:38:011485 DVLOG(net::cookie_util::kVlogGarbageCollection)
Oscar Johansson63e83cf2018-07-02 08:47:261486 << "GarbageCollect() everything";
[email protected]8ad5d462013-05-02 08:45:261487 CookieItVector cookie_its;
jww82d99c12015-11-25 18:39:531488
[email protected]7a964a72010-09-07 19:33:261489 num_deleted += GarbageCollectExpired(
1490 current, CookieMapItPair(cookies_.begin(), cookies_.end()),
1491 &cookie_its);
jww82d99c12015-11-25 18:39:531492
[email protected]8ad5d462013-05-02 08:45:261493 if (cookie_its.size() > kMaxCookies) {
Maks Orlovich35d74c042019-04-18 16:38:011494 DVLOG(net::cookie_util::kVlogGarbageCollection)
Oscar Johansson63e83cf2018-07-02 08:47:261495 << "Deep Garbage Collect everything.";
[email protected]8ad5d462013-05-02 08:45:261496 size_t purge_goal = cookie_its.size() - (kMaxCookies - kPurgeCookies);
1497 DCHECK(purge_goal > kPurgeCookies);
jww82d99c12015-11-25 18:39:531498
jwwa26e439d2017-01-27 18:17:271499 CookieItVector secure_cookie_its;
1500 CookieItVector non_secure_cookie_its;
1501 SplitCookieVectorIntoSecureAndNonSecure(cookie_its, &secure_cookie_its,
1502 &non_secure_cookie_its);
1503 size_t non_secure_purge_goal =
mmenkef4721d992017-06-07 17:13:591504 std::min<size_t>(purge_goal, non_secure_cookie_its.size());
jww82d99c12015-11-25 18:39:531505
mmenkef4721d992017-06-07 17:13:591506 base::Time earliest_non_secure_access_time;
jwwa26e439d2017-01-27 18:17:271507 size_t just_deleted = GarbageCollectLeastRecentlyAccessed(
mmenkef4721d992017-06-07 17:13:591508 current, safe_date, non_secure_purge_goal, non_secure_cookie_its,
1509 &earliest_non_secure_access_time);
jwwa26e439d2017-01-27 18:17:271510 num_deleted += just_deleted;
jww82d99c12015-11-25 18:39:531511
mmenkef4721d992017-06-07 17:13:591512 if (secure_cookie_its.size() == 0) {
1513 // This case is unlikely, but should still update
1514 // |earliest_access_time_| if only have non-secure cookies.
1515 earliest_access_time_ = earliest_non_secure_access_time;
1516 // Garbage collection can't delete all cookies.
1517 DCHECK(!earliest_access_time_.is_null());
1518 } else if (just_deleted < purge_goal) {
1519 size_t secure_purge_goal = std::min<size_t>(purge_goal - just_deleted,
1520 secure_cookie_its.size());
1521 base::Time earliest_secure_access_time;
jww82d99c12015-11-25 18:39:531522 num_deleted += GarbageCollectLeastRecentlyAccessed(
mmenkef4721d992017-06-07 17:13:591523 current, safe_date, secure_purge_goal, secure_cookie_its,
1524 &earliest_secure_access_time);
1525
1526 if (!earliest_non_secure_access_time.is_null() &&
1527 earliest_non_secure_access_time < earliest_secure_access_time) {
1528 earliest_access_time_ = earliest_non_secure_access_time;
1529 } else {
1530 earliest_access_time_ = earliest_secure_access_time;
1531 }
1532
1533 // Garbage collection can't delete all cookies.
1534 DCHECK(!earliest_access_time_.is_null());
jww82d99c12015-11-25 18:39:531535 }
mmenkef4721d992017-06-07 17:13:591536
1537 // If there are secure cookies, but deleting non-secure cookies was enough
1538 // to meet the purge goal, secure cookies are never examined, so
1539 // |earliest_access_time_| can't be determined. Leaving it alone will mean
1540 // it's no later than the real earliest last access time, so this won't
1541 // lead to any problems.
[email protected]8807b322010-10-01 17:10:141542 }
[email protected]c890ed192008-10-30 23:45:531543 }
1544
1545 return num_deleted;
1546}
1547
mkwste079ac412016-03-11 09:04:061548size_t CookieMonster::PurgeLeastRecentMatches(CookieItVector* cookies,
1549 CookiePriority priority,
1550 size_t to_protect,
jwwc00ac712016-05-05 22:21:441551 size_t purge_goal,
1552 bool protect_secure_cookies) {
mkwste079ac412016-03-11 09:04:061553 DCHECK(thread_checker_.CalledOnValidThread());
1554
mmenke645ca6772016-06-17 18:46:431555 // 1. Count number of the cookies at |priority|
1556 size_t cookies_count_possibly_to_be_deleted = CountCookiesForPossibleDeletion(
1557 priority, cookies, false /* count all cookies */);
1558
1559 // 2. If |cookies_count_possibly_to_be_deleted| at |priority| is less than or
1560 // equal |to_protect|, skip round in order to preserve the quota. This
1561 // involves secure and non-secure cookies at |priority|.
1562 if (cookies_count_possibly_to_be_deleted <= to_protect)
1563 return 0u;
1564
1565 // 3. Calculate number of secure cookies at |priority|
1566 // and number of cookies at |priority| that can possibly be deleted.
1567 // It is guaranteed we do not delete more than |purge_goal| even if
1568 // |cookies_count_possibly_to_be_deleted| is higher.
1569 size_t secure_cookies = 0u;
jwwc00ac712016-05-05 22:21:441570 if (protect_secure_cookies) {
mmenke645ca6772016-06-17 18:46:431571 secure_cookies = CountCookiesForPossibleDeletion(
1572 priority, cookies, protect_secure_cookies /* count secure cookies */);
1573 cookies_count_possibly_to_be_deleted -=
1574 std::max(secure_cookies, to_protect - secure_cookies);
1575 } else {
1576 cookies_count_possibly_to_be_deleted -= to_protect;
jwwc00ac712016-05-05 22:21:441577 }
1578
mmenke645ca6772016-06-17 18:46:431579 size_t removed = 0u;
1580 size_t current = 0u;
1581 while ((removed < purge_goal && current < cookies->size()) &&
1582 cookies_count_possibly_to_be_deleted > 0) {
avie7cd11a2016-10-11 02:00:351583 const CanonicalCookie* current_cookie = cookies->at(current)->second.get();
mmenke645ca6772016-06-17 18:46:431584 // Only delete the current cookie if the priority is equal to
1585 // the current level.
jwwc00ac712016-05-05 22:21:441586 if (IsCookieEligibleForEviction(priority, protect_secure_cookies,
1587 current_cookie)) {
mkwstaa07ee82016-03-11 15:32:141588 InternalDeleteCookie(cookies->at(current), true,
1589 DELETE_COOKIE_EVICTED_DOMAIN);
mkwste079ac412016-03-11 09:04:061590 cookies->erase(cookies->begin() + current);
1591 removed++;
mmenke645ca6772016-06-17 18:46:431592 cookies_count_possibly_to_be_deleted--;
mkwste079ac412016-03-11 09:04:061593 } else {
1594 current++;
1595 }
1596 }
1597 return removed;
1598}
1599
jww82d99c12015-11-25 18:39:531600size_t CookieMonster::GarbageCollectExpired(const Time& current,
1601 const CookieMapItPair& itpair,
1602 CookieItVector* cookie_its) {
mmenkebe0910d2016-03-01 19:09:091603 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041604
[email protected]c890ed192008-10-30 23:45:531605 int num_deleted = 0;
1606 for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) {
jdoerrie22a91d8b92018-10-05 08:43:261607 auto curit = it;
[email protected]c890ed192008-10-30 23:45:531608 ++it;
1609
1610 if (curit->second->IsExpired(current)) {
[email protected]2f3f3592010-07-07 20:11:511611 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
[email protected]c890ed192008-10-30 23:45:531612 ++num_deleted;
1613 } else if (cookie_its) {
1614 cookie_its->push_back(curit);
1615 }
initial.commit586acc5fe2008-07-26 22:42:521616 }
1617
1618 return num_deleted;
1619}
1620
jww82d99c12015-11-25 18:39:531621size_t CookieMonster::GarbageCollectDeleteRange(
1622 const Time& current,
1623 DeletionCause cause,
1624 CookieItVector::iterator it_begin,
1625 CookieItVector::iterator it_end) {
mmenkebe0910d2016-03-01 19:09:091626 DCHECK(thread_checker_.CalledOnValidThread());
1627
jdoerrie22a91d8b92018-10-05 08:43:261628 for (auto it = it_begin; it != it_end; it++) {
[email protected]8ad5d462013-05-02 08:45:261629 InternalDeleteCookie((*it), true, cause);
[email protected]c10da4b02010-03-25 14:38:321630 }
[email protected]8ad5d462013-05-02 08:45:261631 return it_end - it_begin;
[email protected]c10da4b02010-03-25 14:38:321632}
1633
mmenke74bcbd52016-01-21 17:17:561634size_t CookieMonster::GarbageCollectLeastRecentlyAccessed(
1635 const base::Time& current,
1636 const base::Time& safe_date,
1637 size_t purge_goal,
mmenkef4721d992017-06-07 17:13:591638 CookieItVector cookie_its,
1639 base::Time* earliest_time) {
1640 DCHECK_LE(purge_goal, cookie_its.size());
mmenkebe0910d2016-03-01 19:09:091641 DCHECK(thread_checker_.CalledOnValidThread());
1642
mmenkef4721d992017-06-07 17:13:591643 // Sorts up to *and including* |cookie_its[purge_goal]| (if it exists), so
1644 // |earliest_time| will be properly assigned even if
mmenke74bcbd52016-01-21 17:17:561645 // |global_purge_it| == |cookie_its.begin() + purge_goal|.
mmenkef4721d992017-06-07 17:13:591646 SortLeastRecentlyAccessed(
1647 cookie_its.begin(), cookie_its.end(),
1648 cookie_its.size() < purge_goal ? purge_goal + 1 : purge_goal);
mmenke74bcbd52016-01-21 17:17:561649 // Find boundary to cookies older than safe_date.
jdoerrie22a91d8b92018-10-05 08:43:261650 auto global_purge_it = LowerBoundAccessDate(
mmenke74bcbd52016-01-21 17:17:561651 cookie_its.begin(), cookie_its.begin() + purge_goal, safe_date);
jwwa26e439d2017-01-27 18:17:271652 // Only delete the old cookies and delete non-secure ones first.
mmenke74bcbd52016-01-21 17:17:561653 size_t num_deleted =
1654 GarbageCollectDeleteRange(current, DELETE_COOKIE_EVICTED_GLOBAL,
1655 cookie_its.begin(), global_purge_it);
mmenkef4721d992017-06-07 17:13:591656 if (global_purge_it != cookie_its.end())
1657 *earliest_time = (*global_purge_it)->second->LastAccessDate();
mmenke74bcbd52016-01-21 17:17:561658 return num_deleted;
1659}
1660
[email protected]ed32c212013-05-14 20:49:291661// A wrapper around registry_controlled_domains::GetDomainAndRegistry
Maks Orlovich323efaf2018-03-06 02:56:391662// to make clear we're creating a key for our local map or for the persistent
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521663// store's use. Here and in FindCookiesForRegistryControlledHost() are the only
1664// two places where we need to conditionalize based on key type.
[email protected]f48b9432011-01-11 07:25:401665//
1666// Note that this key algorithm explicitly ignores the scheme. This is
1667// because when we're entering cookies into the map from the backing store,
1668// we in general won't have the scheme at that point.
1669// In practical terms, this means that file cookies will be stored
1670// in the map either by an empty string or by UNC name (and will be
1671// limited by kMaxCookiesPerHost), and extension cookies will be stored
1672// based on the single extension id, as the extension id won't have the
1673// form of a DNS host and hence GetKey() will return it unchanged.
1674//
1675// Arguably the right thing to do here is to make the key
1676// algorithm dependent on the scheme, and make sure that the scheme is
1677// available everywhere the key must be obtained (specfically at backing
1678// store load time). This would require either changing the backing store
1679// database schema to include the scheme (far more trouble than it's worth), or
1680// separating out file cookies into their own CookieMonster instance and
1681// thus restricting each scheme to a single cookie monster (which might
1682// be worth it, but is still too much trouble to solve what is currently a
1683// non-problem).
Maks Orlovich323efaf2018-03-06 02:56:391684//
1685// static
1686std::string CookieMonster::GetKey(base::StringPiece domain) {
[email protected]f48b9432011-01-11 07:25:401687 std::string effective_domain(
[email protected]ed32c212013-05-14 20:49:291688 registry_controlled_domains::GetDomainAndRegistry(
[email protected]aabe1792014-01-30 21:37:461689 domain, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES));
[email protected]f48b9432011-01-11 07:25:401690 if (effective_domain.empty())
Maks Orlovich323efaf2018-03-06 02:56:391691 domain.CopyToString(&effective_domain);
[email protected]f48b9432011-01-11 07:25:401692
1693 if (!effective_domain.empty() && effective_domain[0] == '.')
1694 return effective_domain.substr(1);
1695 return effective_domain;
1696}
1697
1698bool CookieMonster::HasCookieableScheme(const GURL& url) {
mmenkebe0910d2016-03-01 19:09:091699 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401700
1701 // Make sure the request is on a cookie-able url scheme.
1702 for (size_t i = 0; i < cookieable_schemes_.size(); ++i) {
1703 // We matched a scheme.
1704 if (url.SchemeIs(cookieable_schemes_[i].c_str())) {
1705 // We've matched a supported scheme.
initial.commit586acc5fe2008-07-26 22:42:521706 return true;
1707 }
1708 }
[email protected]f48b9432011-01-11 07:25:401709
1710 // The scheme didn't match any in our whitelist.
Maks Orlovich35d74c042019-04-18 16:38:011711 DVLOG(net::cookie_util::kVlogPerCookieMonster)
mkwstbe84af312015-02-20 08:52:451712 << "WARNING: Unsupported cookie scheme: " << url.scheme();
initial.commit586acc5fe2008-07-26 22:42:521713 return false;
1714}
1715
[email protected]c4058fb2010-06-22 17:25:261716// Test to see if stats should be recorded, and record them if so.
1717// The goal here is to get sampling for the average browser-hour of
1718// activity. We won't take samples when the web isn't being surfed,
1719// and when the web is being surfed, we'll take samples about every
1720// kRecordStatisticsIntervalSeconds.
1721// last_statistic_record_time_ is initialized to Now() rather than null
1722// in the constructor so that we won't take statistics right after
1723// startup, to avoid bias from browsers that are started but not used.
1724void CookieMonster::RecordPeriodicStats(const base::Time& current_time) {
mmenkebe0910d2016-03-01 19:09:091725 DCHECK(thread_checker_.CalledOnValidThread());
1726
[email protected]c4058fb2010-06-22 17:25:261727 const base::TimeDelta kRecordStatisticsIntervalTime(
1728 base::TimeDelta::FromSeconds(kRecordStatisticsIntervalSeconds));
1729
[email protected]7a964a72010-09-07 19:33:261730 // If we've taken statistics recently, return.
1731 if (current_time - last_statistic_record_time_ <=
[email protected]c4058fb2010-06-22 17:25:261732 kRecordStatisticsIntervalTime) {
[email protected]7a964a72010-09-07 19:33:261733 return;
[email protected]c4058fb2010-06-22 17:25:261734 }
[email protected]7a964a72010-09-07 19:33:261735
1736 // See InitializeHistograms() for details.
1737 histogram_count_->Add(cookies_.size());
1738
1739 // More detailed statistics on cookie counts at different granularities.
[email protected]7a964a72010-09-07 19:33:261740 last_statistic_record_time_ = current_time;
[email protected]c4058fb2010-06-22 17:25:261741}
1742
[email protected]f48b9432011-01-11 07:25:401743// Initialize all histogram counter variables used in this class.
1744//
1745// Normal histogram usage involves using the macros defined in
1746// histogram.h, which automatically takes care of declaring these
1747// variables (as statics), initializing them, and accumulating into
1748// them, all from a single entry point. Unfortunately, that solution
1749// doesn't work for the CookieMonster, as it's vulnerable to races between
1750// separate threads executing the same functions and hence initializing the
1751// same static variables. There isn't a race danger in the histogram
1752// accumulation calls; they are written to be resilient to simultaneous
1753// calls from multiple threads.
1754//
1755// The solution taken here is to have per-CookieMonster instance
1756// variables that are constructed during CookieMonster construction.
1757// Note that these variables refer to the same underlying histogram,
1758// so we still race (but safely) with other CookieMonster instances
1759// for accumulation.
1760//
1761// To do this we've expanded out the individual histogram macros calls,
1762// with declarations of the variables in the class decl, initialization here
1763// (done from the class constructor) and direct calls to the accumulation
1764// methods where needed. The specific histogram macro calls on which the
1765// initialization is based are included in comments below.
1766void CookieMonster::InitializeHistograms() {
mmenkebe0910d2016-03-01 19:09:091767 DCHECK(thread_checker_.CalledOnValidThread());
1768
[email protected]f48b9432011-01-11 07:25:401769 // From UMA_HISTOGRAM_CUSTOM_COUNTS
1770 histogram_expiration_duration_minutes_ = base::Histogram::FactoryGet(
mkwstbe84af312015-02-20 08:52:451771 "Cookie.ExpirationDurationMinutes", 1, kMinutesInTenYears, 50,
[email protected]f48b9432011-01-11 07:25:401772 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401773 histogram_count_ = base::Histogram::FactoryGet(
mkwstbe84af312015-02-20 08:52:451774 "Cookie.Count", 1, 4000, 50, base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401775
1776 // From UMA_HISTOGRAM_ENUMERATION
mkwstc1aa4cc2015-04-03 19:57:451777 histogram_cookie_type_ = base::LinearHistogram::FactoryGet(
mkwst87378d92015-04-10 21:22:111778 "Cookie.Type", 1, (1 << COOKIE_TYPE_LAST_ENTRY) - 1,
1779 1 << COOKIE_TYPE_LAST_ENTRY, base::Histogram::kUmaTargetedHistogramFlag);
estark7feb65c2b2015-08-21 23:38:201780 histogram_cookie_source_scheme_ = base::LinearHistogram::FactoryGet(
1781 "Cookie.CookieSourceScheme", 1, COOKIE_SOURCE_LAST_ENTRY - 1,
1782 COOKIE_SOURCE_LAST_ENTRY, base::Histogram::kUmaTargetedHistogramFlag);
jww31e32632015-12-16 23:38:341783 histogram_cookie_delete_equivalent_ = base::LinearHistogram::FactoryGet(
1784 "Cookie.CookieDeleteEquivalent", 1,
1785 COOKIE_DELETE_EQUIVALENT_LAST_ENTRY - 1,
1786 COOKIE_DELETE_EQUIVALENT_LAST_ENTRY,
1787 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401788
1789 // From UMA_HISTOGRAM_{CUSTOM_,}TIMES
[email protected]c7593fb22011-11-14 23:54:271790 histogram_time_blocked_on_load_ = base::Histogram::FactoryTimeGet(
mkwstbe84af312015-02-20 08:52:451791 "Cookie.TimeBlockedOnLoad", base::TimeDelta::FromMilliseconds(1),
1792 base::TimeDelta::FromMinutes(1), 50,
1793 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401794}
1795
rdsmithe5c701d2017-07-12 21:50:001796void CookieMonster::DoCookieCallback(base::OnceClosure callback) {
mmenkebe0910d2016-03-01 19:09:091797 DCHECK(thread_checker_.CalledOnValidThread());
1798
1799 MarkCookieStoreAsInitialized();
1800 FetchAllCookiesIfNecessary();
mmenkef49fca0e2016-03-08 12:46:241801 seen_global_task_ = true;
mmenkebe0910d2016-03-01 19:09:091802
1803 if (!finished_fetching_all_cookies_ && store_.get()) {
rdsmithe5c701d2017-07-12 21:50:001804 tasks_pending_.push_back(std::move(callback));
mmenkebe0910d2016-03-01 19:09:091805 return;
mmenke74bcbd52016-01-21 17:17:561806 }
1807
rdsmithe5c701d2017-07-12 21:50:001808 std::move(callback).Run();
mmenke74bcbd52016-01-21 17:17:561809}
1810
rdsmithe5c701d2017-07-12 21:50:001811void CookieMonster::DoCookieCallbackForURL(base::OnceClosure callback,
1812 const GURL& url) {
Maks Orlovich323efaf2018-03-06 02:56:391813 DoCookieCallbackForHostOrDomain(std::move(callback), url.host_piece());
1814}
1815
1816void CookieMonster::DoCookieCallbackForHostOrDomain(
1817 base::OnceClosure callback,
1818 base::StringPiece host_or_domain) {
mmenkebe0910d2016-03-01 19:09:091819 MarkCookieStoreAsInitialized();
erikchende4c39e2018-01-29 21:33:361820 FetchAllCookiesIfNecessary();
mmenkebe0910d2016-03-01 19:09:091821
1822 // If cookies for the requested domain key (eTLD+1) have been loaded from DB
1823 // then run the task, otherwise load from DB.
1824 if (!finished_fetching_all_cookies_ && store_.get()) {
mmenkef49fca0e2016-03-08 12:46:241825 // If a global task has been previously seen, queue the task as a global
1826 // task. Note that the CookieMonster may be in the middle of executing
1827 // the global queue, |tasks_pending_| may be empty, which is why another
1828 // bool is needed.
1829 if (seen_global_task_) {
rdsmithe5c701d2017-07-12 21:50:001830 tasks_pending_.push_back(std::move(callback));
mmenkef49fca0e2016-03-08 12:46:241831 return;
1832 }
1833
mmenkebe0910d2016-03-01 19:09:091834 // Checks if the domain key has been loaded.
Maks Orlovich323efaf2018-03-06 02:56:391835 std::string key = GetKey(host_or_domain);
mmenkebe0910d2016-03-01 19:09:091836 if (keys_loaded_.find(key) == keys_loaded_.end()) {
jdoerrie22a91d8b92018-10-05 08:43:261837 auto it = tasks_pending_for_key_.find(key);
mmenkebe0910d2016-03-01 19:09:091838 if (it == tasks_pending_for_key_.end()) {
1839 store_->LoadCookiesForKey(
Maks Orlovich108cb4c2019-03-26 20:24:571840 key, base::BindOnce(&CookieMonster::OnKeyLoaded,
1841 weak_ptr_factory_.GetWeakPtr(), key));
mmenkebe0910d2016-03-01 19:09:091842 it = tasks_pending_for_key_
Brett Wilsonc6a0c822017-09-12 00:04:291843 .insert(std::make_pair(
1844 key, base::circular_deque<base::OnceClosure>()))
mmenkebe0910d2016-03-01 19:09:091845 .first;
mmenke74bcbd52016-01-21 17:17:561846 }
rdsmithe5c701d2017-07-12 21:50:001847 it->second.push_back(std::move(callback));
mmenkebe0910d2016-03-01 19:09:091848 return;
mmenke74bcbd52016-01-21 17:17:561849 }
1850 }
mmenkebe0910d2016-03-01 19:09:091851
rdsmithe5c701d2017-07-12 21:50:001852 std::move(callback).Run();
mmenke74bcbd52016-01-21 17:17:561853}
1854
[email protected]63725312012-07-19 08:24:161855} // namespace net