blob: fccb34759c6673ddae73d90896bab45c83c64077 [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"
Ken Rockotc2048612018-03-29 01:43:3252#include "base/debug/dump_without_crashing.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"
Ken Rockotc2048612018-03-29 01:43:3265#include "base/timer/elapsed_timer.h"
Maks Orlovich5cf437b02018-03-27 04:40:4266#include "base/trace_event/process_memory_dump.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"
nharper2b0ad9a2017-05-22 18:33:4574#include "net/ssl/channel_id_service.h"
mkwst8241a122015-10-20 07:15:1075#include "url/origin.h"
initial.commit586acc5fe2008-07-26 22:42:5276
[email protected]e1acf6f2008-10-27 20:43:3377using base::Time;
78using base::TimeDelta;
[email protected]7a964a72010-09-07 19:33:2679using base::TimeTicks;
Chris Mumfordd8ed9f82018-05-01 15:43:1380using TimeRange = net::CookieDeletionInfo::TimeRange;
[email protected]e1acf6f2008-10-27 20:43:3381
[email protected]85620342011-10-17 17:35:0482// In steady state, most cookie requests can be satisfied by the in memory
erikchen1dd72a72015-05-06 20:45:0583// cookie monster store. If the cookie request cannot be satisfied by the in
84// memory store, the relevant cookies must be fetched from the persistent
85// store. The task is queued in CookieMonster::tasks_pending_ if it requires
86// all cookies to be loaded from the backend, or tasks_pending_for_key_ if it
87// only requires all cookies associated with an eTLD+1.
[email protected]85620342011-10-17 17:35:0488//
89// On the browser critical paths (e.g. for loading initial web pages in a
90// session restore) it may take too long to wait for the full load. If a cookie
rdsmithe5c701d2017-07-12 21:50:0091// request is for a specific URL, DoCookieCallbackForURL is called, which
92// triggers a priority load if the key is not loaded yet by calling
93// PersistentCookieStore::LoadCookiesForKey. The request is queued in
[email protected]0184df32013-05-14 00:53:5594// CookieMonster::tasks_pending_for_key_ and executed upon receiving
95// notification of key load completion via CookieMonster::OnKeyLoaded(). If
96// multiple requests for the same eTLD+1 are received before key load
97// completion, only the first request calls
[email protected]85620342011-10-17 17:35:0498// PersistentCookieStore::LoadCookiesForKey, all subsequent requests are queued
[email protected]0184df32013-05-14 00:53:5599// in CookieMonster::tasks_pending_for_key_ and executed upon receiving
100// notification of key load completion triggered by the first request for the
101// same eTLD+1.
[email protected]85620342011-10-17 17:35:04102
[email protected]c4058fb2010-06-22 17:25:26103static const int kMinutesInTenYears = 10 * 365 * 24 * 60;
104
erikchen1dd72a72015-05-06 20:45:05105namespace {
106
Maks Orlovichf97d1b92018-03-06 17:25:39107void MaybeRunDeleteCallback(base::WeakPtr<net::CookieMonster> cookie_monster,
108 base::OnceClosure callback) {
rdsmithe5c701d2017-07-12 21:50:00109 if (cookie_monster && callback)
110 std::move(callback).Run();
111}
112
113void MaybeRunCookieCallback(base::OnceClosure callback) {
114 if (callback)
115 std::move(callback).Run();
116}
117
118template <typename T>
119void MaybeRunCookieCallback(base::OnceCallback<void(const T&)> callback,
120 const T& result) {
121 if (callback)
122 std::move(callback).Run(result);
123}
124
125template <typename T>
126void MaybeRunCookieCallback(base::OnceCallback<void(T)> callback,
127 const T& result) {
128 if (callback)
129 std::move(callback).Run(result);
130}
131
Ken Rockotc2048612018-03-29 01:43:32132// Wraps a OnceClosure -- specifically one used by
133// |GetCookieListWithOptionsAsync()| -- with additional bound state to track the
Ken Rockot36ac3d02018-04-03 18:54:08134// duration between when its creation and destruction time.
Ken Rockotc2048612018-03-29 01:43:32135// See https://crbug.com/824024 for context.
136base::OnceClosure InstrumentGetCookieListClosure(base::OnceClosure closure) {
137 return base::BindOnce(
Ken Rockot36ac3d02018-04-03 18:54:08138 [](std::unique_ptr<base::ElapsedTimer> timer, base::OnceClosure closure) {
139 UMA_HISTOGRAM_CUSTOM_TIMES("Cookie.GetCookieListCompletionTime",
140 timer->Elapsed(),
141 base::TimeDelta::FromMilliseconds(10),
142 base::TimeDelta::FromSeconds(60), 50);
143 std::move(closure).Run();
144 },
145 std::make_unique<base::ElapsedTimer>(), std::move(closure));
Ken Rockotc2048612018-03-29 01:43:32146}
147
erikchen1dd72a72015-05-06 20:45:05148} // namespace
149
[email protected]8ac1a752008-07-31 19:40:37150namespace net {
151
[email protected]7a964a72010-09-07 19:33:26152// See comments at declaration of these variables in cookie_monster.h
153// for details.
mkwstbe84af312015-02-20 08:52:45154const size_t CookieMonster::kDomainMaxCookies = 180;
155const size_t CookieMonster::kDomainPurgeCookies = 30;
156const size_t CookieMonster::kMaxCookies = 3300;
157const size_t CookieMonster::kPurgeCookies = 300;
[email protected]8ad5d462013-05-02 08:45:26158
mkwst87734352016-03-03 17:36:23159const size_t CookieMonster::kDomainCookiesQuotaLow = 30;
160const size_t CookieMonster::kDomainCookiesQuotaMedium = 50;
161const size_t CookieMonster::kDomainCookiesQuotaHigh =
162 kDomainMaxCookies - kDomainPurgeCookies - kDomainCookiesQuotaLow -
163 kDomainCookiesQuotaMedium;
[email protected]8ad5d462013-05-02 08:45:26164
mkwstbe84af312015-02-20 08:52:45165const int CookieMonster::kSafeFromGlobalPurgeDays = 30;
[email protected]297a4ed02010-02-12 08:12:52166
[email protected]7a964a72010-09-07 19:33:26167namespace {
[email protected]e32306c52008-11-06 16:59:05168
[email protected]6210ce52013-09-20 03:33:14169bool ContainsControlCharacter(const std::string& s) {
170 for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
171 if ((*i >= 0) && (*i <= 31))
172 return true;
173 }
174
175 return false;
176}
177
[email protected]5b9bc352012-07-18 13:13:34178typedef std::vector<CanonicalCookie*> CanonicalCookieVector;
[email protected]34a160d2011-05-12 22:12:49179
[email protected]77e0a462008-11-01 00:43:35180// Default minimum delay after updating a cookie's LastAccessDate before we
181// will update it again.
[email protected]297a4ed02010-02-12 08:12:52182const int kDefaultAccessUpdateThresholdSeconds = 60;
183
184// Comparator to sort cookies from highest creation date to lowest
185// creation date.
186struct OrderByCreationTimeDesc {
187 bool operator()(const CookieMonster::CookieMap::iterator& a,
188 const CookieMonster::CookieMap::iterator& b) const {
189 return a->second->CreationDate() > b->second->CreationDate();
190 }
191};
192
[email protected]f48b9432011-01-11 07:25:40193// Mozilla sorts on the path length (longest first), and then it
194// sorts by creation time (oldest first).
195// The RFC says the sort order for the domain attribute is undefined.
[email protected]5b9bc352012-07-18 13:13:34196bool CookieSorter(CanonicalCookie* cc1, CanonicalCookie* cc2) {
[email protected]f48b9432011-01-11 07:25:40197 if (cc1->Path().length() == cc2->Path().length())
198 return cc1->CreationDate() < cc2->CreationDate();
199 return cc1->Path().length() > cc2->Path().length();
initial.commit586acc5fe2008-07-26 22:42:52200}
201
[email protected]8ad5d462013-05-02 08:45:26202bool LRACookieSorter(const CookieMonster::CookieMap::iterator& it1,
[email protected]f48b9432011-01-11 07:25:40203 const CookieMonster::CookieMap::iterator& it2) {
[email protected]f48b9432011-01-11 07:25:40204 if (it1->second->LastAccessDate() != it2->second->LastAccessDate())
205 return it1->second->LastAccessDate() < it2->second->LastAccessDate();
initial.commit586acc5fe2008-07-26 22:42:52206
mkwste079ac412016-03-11 09:04:06207 // Ensure stability for == last access times by falling back to creation.
[email protected]f48b9432011-01-11 07:25:40208 return it1->second->CreationDate() < it2->second->CreationDate();
[email protected]297a4ed02010-02-12 08:12:52209}
210
211// Our strategy to find duplicates is:
212// (1) Build a map from (cookiename, cookiepath) to
213// {list of cookies with this signature, sorted by creation time}.
214// (2) For each list with more than 1 entry, keep the cookie having the
215// most recent creation time, and delete the others.
[email protected]f48b9432011-01-11 07:25:40216//
[email protected]1655ba342010-07-14 18:17:42217// Two cookies are considered equivalent if they have the same domain,
218// name, and path.
219struct CookieSignature {
220 public:
[email protected]dedec0b2013-02-28 04:50:10221 CookieSignature(const std::string& name,
222 const std::string& domain,
[email protected]1655ba342010-07-14 18:17:42223 const std::string& path)
mkwstbe84af312015-02-20 08:52:45224 : name(name), domain(domain), path(path) {}
[email protected]1655ba342010-07-14 18:17:42225
226 // To be a key for a map this class needs to be assignable, copyable,
227 // and have an operator<. The default assignment operator
228 // and copy constructor are exactly what we want.
229
230 bool operator<(const CookieSignature& cs) const {
231 // Name compare dominates, then domain, then path.
232 int diff = name.compare(cs.name);
233 if (diff != 0)
234 return diff < 0;
235
236 diff = domain.compare(cs.domain);
237 if (diff != 0)
238 return diff < 0;
239
240 return path.compare(cs.path) < 0;
241 }
242
243 std::string name;
244 std::string domain;
245 std::string path;
246};
[email protected]f48b9432011-01-11 07:25:40247
[email protected]8ad5d462013-05-02 08:45:26248// For a CookieItVector iterator range [|it_begin|, |it_end|),
mmenkef4721d992017-06-07 17:13:59249// sorts the first |num_sort| elements by LastAccessDate().
mkwstbe84af312015-02-20 08:52:45250void SortLeastRecentlyAccessed(CookieMonster::CookieItVector::iterator it_begin,
251 CookieMonster::CookieItVector::iterator it_end,
252 size_t num_sort) {
mmenkef4721d992017-06-07 17:13:59253 DCHECK_LE(static_cast<int>(num_sort), it_end - it_begin);
254 std::partial_sort(it_begin, it_begin + num_sort, it_end, LRACookieSorter);
[email protected]8ad5d462013-05-02 08:45:26255}
[email protected]f48b9432011-01-11 07:25:40256
jww82d99c12015-11-25 18:39:53257// Given a single cookie vector |cookie_its|, pushs all of the secure cookies in
258// |cookie_its| into |secure_cookie_its| and all of the non-secure cookies into
259// |non_secure_cookie_its|. Both |secure_cookie_its| and |non_secure_cookie_its|
260// must be non-NULL.
261void SplitCookieVectorIntoSecureAndNonSecure(
262 const CookieMonster::CookieItVector& cookie_its,
263 CookieMonster::CookieItVector* secure_cookie_its,
264 CookieMonster::CookieItVector* non_secure_cookie_its) {
265 DCHECK(secure_cookie_its && non_secure_cookie_its);
266 for (const auto& curit : cookie_its) {
267 if (curit->second->IsSecure())
268 secure_cookie_its->push_back(curit);
269 else
270 non_secure_cookie_its->push_back(curit);
271 }
272}
273
mkwstbe84af312015-02-20 08:52:45274bool LowerBoundAccessDateComparator(const CookieMonster::CookieMap::iterator it,
275 const Time& access_date) {
[email protected]8ad5d462013-05-02 08:45:26276 return it->second->LastAccessDate() < access_date;
277}
278
279// For a CookieItVector iterator range [|it_begin|, |it_end|)
280// from a CookieItVector sorted by LastAccessDate(), returns the
281// first iterator with access date >= |access_date|, or cookie_its_end if this
282// holds for all.
283CookieMonster::CookieItVector::iterator LowerBoundAccessDate(
284 const CookieMonster::CookieItVector::iterator its_begin,
285 const CookieMonster::CookieItVector::iterator its_end,
286 const Time& access_date) {
287 return std::lower_bound(its_begin, its_end, access_date,
288 LowerBoundAccessDateComparator);
[email protected]7a964a72010-09-07 19:33:26289}
290
Victor Costan14f47c12018-03-01 08:02:24291// Mapping between DeletionCause and CookieChangeCause; the
[email protected]7c4b66b2014-01-04 12:28:13292// mapping also provides a boolean that specifies whether or not an
Victor Costan14f47c12018-03-01 08:02:24293// OnCookieChange notification ought to be generated.
[email protected]8bb846f2011-03-23 12:08:18294typedef struct ChangeCausePair_struct {
Victor Costan14f47c12018-03-01 08:02:24295 CookieChangeCause cause;
[email protected]8bb846f2011-03-23 12:08:18296 bool notify;
297} ChangeCausePair;
nharper352933e2016-09-30 18:24:57298const ChangeCausePair kChangeCauseMapping[] = {
mkwstbe84af312015-02-20 08:52:45299 // DELETE_COOKIE_EXPLICIT
Victor Costan14f47c12018-03-01 08:02:24300 {CookieChangeCause::EXPLICIT, true},
mkwstbe84af312015-02-20 08:52:45301 // DELETE_COOKIE_OVERWRITE
Victor Costan14f47c12018-03-01 08:02:24302 {CookieChangeCause::OVERWRITE, true},
mkwstbe84af312015-02-20 08:52:45303 // DELETE_COOKIE_EXPIRED
Victor Costan14f47c12018-03-01 08:02:24304 {CookieChangeCause::EXPIRED, true},
mkwstbe84af312015-02-20 08:52:45305 // DELETE_COOKIE_EVICTED
Victor Costan14f47c12018-03-01 08:02:24306 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45307 // DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE
Victor Costan14f47c12018-03-01 08:02:24308 {CookieChangeCause::EXPLICIT, false},
mkwstbe84af312015-02-20 08:52:45309 // DELETE_COOKIE_DONT_RECORD
Victor Costan14f47c12018-03-01 08:02:24310 {CookieChangeCause::EXPLICIT, false},
mkwstbe84af312015-02-20 08:52:45311 // DELETE_COOKIE_EVICTED_DOMAIN
Victor Costan14f47c12018-03-01 08:02:24312 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45313 // DELETE_COOKIE_EVICTED_GLOBAL
Victor Costan14f47c12018-03-01 08:02:24314 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45315 // DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE
Victor Costan14f47c12018-03-01 08:02:24316 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45317 // DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE
Victor Costan14f47c12018-03-01 08:02:24318 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45319 // DELETE_COOKIE_EXPIRED_OVERWRITE
Victor Costan14f47c12018-03-01 08:02:24320 {CookieChangeCause::EXPIRED_OVERWRITE, true},
mkwstbe84af312015-02-20 08:52:45321 // DELETE_COOKIE_CONTROL_CHAR
Victor Costan14f47c12018-03-01 08:02:24322 {CookieChangeCause::EVICTED, true},
jww82d99c12015-11-25 18:39:53323 // DELETE_COOKIE_NON_SECURE
Victor Costan14f47c12018-03-01 08:02:24324 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45325 // DELETE_COOKIE_LAST_ENTRY
Victor Costan14f47c12018-03-01 08:02:24326 {CookieChangeCause::EXPLICIT, false}};
ellyjones399e35a22014-10-27 11:09:56327
jwwc00ac712016-05-05 22:21:44328bool IsCookieEligibleForEviction(CookiePriority current_priority_level,
329 bool protect_secure_cookies,
330 const CanonicalCookie* cookie) {
mmenke645ca6772016-06-17 18:46:43331 if (cookie->Priority() == current_priority_level && protect_secure_cookies)
332 return !cookie->IsSecure();
jwwc00ac712016-05-05 22:21:44333
mmenke645ca6772016-06-17 18:46:43334 return cookie->Priority() == current_priority_level;
335}
jwwc00ac712016-05-05 22:21:44336
mmenke645ca6772016-06-17 18:46:43337size_t CountCookiesForPossibleDeletion(
338 CookiePriority priority,
339 const CookieMonster::CookieItVector* cookies,
340 bool protect_secure_cookies) {
341 size_t cookies_count = 0U;
342 for (const auto& cookie : *cookies) {
343 if (cookie->second->Priority() == priority) {
344 if (!protect_secure_cookies || cookie->second->IsSecure())
345 cookies_count++;
346 }
347 }
348 return cookies_count;
jwwc00ac712016-05-05 22:21:44349}
350
[email protected]f48b9432011-01-11 07:25:40351} // namespace
352
Pritam8354cf702018-03-10 08:55:41353CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
Helen Lifb313a92018-08-14 15:46:44354 ChannelIDService* channel_id_service,
355 NetLog* net_log)
Randy Smithb78e0922018-03-01 21:19:54356 : CookieMonster(
Pritam8354cf702018-03-10 08:55:41357 std::move(store),
Randy Smithb78e0922018-03-01 21:19:54358 channel_id_service,
Helen Lifb313a92018-08-14 15:46:44359 base::TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds),
360 net_log) {}
Randy Smithb78e0922018-03-01 21:19:54361
Pritam8354cf702018-03-10 08:55:41362CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
Helen Lifb313a92018-08-14 15:46:44363 base::TimeDelta last_access_threshold,
364 NetLog* net_log)
365 : CookieMonster(std::move(store), nullptr, last_access_threshold, net_log) {
366}
Randy Smithb78e0922018-03-01 21:19:54367
Pritam8354cf702018-03-10 08:55:41368CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
Randy Smithb78e0922018-03-01 21:19:54369 ChannelIDService* channel_id_service,
Helen Lifb313a92018-08-14 15:46:44370 base::TimeDelta last_access_threshold,
371 NetLog* net_log)
[email protected]f48b9432011-01-11 07:25:40372 : initialized_(false),
erikchen1dd72a72015-05-06 20:45:05373 started_fetching_all_cookies_(false),
374 finished_fetching_all_cookies_(false),
mmenkef49fca0e2016-03-08 12:46:24375 seen_global_task_(false),
Helen Lifb313a92018-08-14 15:46:44376 net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::COOKIE_STORE)),
Pritam8354cf702018-03-10 08:55:41377 store_(std::move(store)),
shessf0bc1182016-05-19 04:35:58378 last_access_threshold_(last_access_threshold),
nharper2b0ad9a2017-05-22 18:33:45379 channel_id_service_(channel_id_service),
[email protected]82388662011-03-10 21:04:06380 last_statistic_record_time_(base::Time::Now()),
mmenkebe0910d2016-03-01 19:09:09381 persist_session_cookies_(false),
382 weak_ptr_factory_(this) {
[email protected]f48b9432011-01-11 07:25:40383 InitializeHistograms();
mmenke18dd8ba2016-02-01 18:42:10384 cookieable_schemes_.insert(
385 cookieable_schemes_.begin(), kDefaultCookieableSchemes,
386 kDefaultCookieableSchemes + kDefaultCookieableSchemesCount);
Nick Harper14e23332017-07-28 00:27:23387 if (channel_id_service_ && store_) {
388 // |store_| can outlive this CookieMonster, but there are no guarantees
389 // about the lifetime of |channel_id_service_| relative to |store_|. The
390 // only guarantee is that |channel_id_service_| will outlive this
391 // CookieMonster. To avoid the PersistentCookieStore retaining a pointer to
392 // the ChannelIDStore via this callback after this CookieMonster is
393 // destroyed, CookieMonster's d'tor sets the callback to a null callback.
394 store_->SetBeforeFlushCallback(
395 base::Bind(&ChannelIDStore::Flush,
396 base::Unretained(channel_id_service_->GetChannelIDStore())));
397 }
Helen Licd0fab862018-08-13 16:07:53398 net_log_.BeginEvent(
399 NetLogEventType::COOKIE_STORE_ALIVE,
400 base::BindRepeating(&NetLogCookieMonsterConstructorCallback,
401 store != nullptr, channel_id_service != nullptr));
initial.commit586acc5fe2008-07-26 22:42:52402}
403
[email protected]218aa6a12011-09-13 17:38:38404// Asynchronous CookieMonster API
405
rdsmith7ac81712017-06-22 17:09:54406void CookieMonster::FlushStore(base::OnceClosure callback) {
mmenkebe0910d2016-03-01 19:09:09407 DCHECK(thread_checker_.CalledOnValidThread());
mmenke606c59c2016-03-07 18:20:55408
nharper2b0ad9a2017-05-22 18:33:45409 if (initialized_ && store_.get()) {
rdsmith7ac81712017-06-22 17:09:54410 store_->Flush(std::move(callback));
rdsmithe5c701d2017-07-12 21:50:00411 } else if (callback) {
rdsmith7ac81712017-06-22 17:09:54412 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
413 std::move(callback));
nharper2b0ad9a2017-05-22 18:33:45414 }
mmenke74bcbd52016-01-21 17:17:56415}
416
mmenkeded79da2016-02-06 08:28:51417void CookieMonster::SetForceKeepSessionState() {
mmenkebe0910d2016-03-01 19:09:09418 DCHECK(thread_checker_.CalledOnValidThread());
mmenke606c59c2016-03-07 18:20:55419
mmenkeded79da2016-02-06 08:28:51420 if (store_)
421 store_->SetForceKeepSessionState();
422}
423
drogerd5d1278c2015-03-17 19:21:51424void CookieMonster::SetAllCookiesAsync(const CookieList& list,
rdsmith7ac81712017-06-22 17:09:54425 SetCookiesCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00426 DoCookieCallback(base::BindOnce(
427 // base::Unretained is safe as DoCookieCallbackForURL stores
428 // the callback on |*this|, so the callback will not outlive
429 // the object.
430 &CookieMonster::SetAllCookies, base::Unretained(this), list,
431 std::move(callback)));
drogerd5d1278c2015-03-17 19:21:51432}
433
rdsmitha6ce4442017-06-21 17:11:05434void CookieMonster::SetCanonicalCookieAsync(
435 std::unique_ptr<CanonicalCookie> cookie,
436 bool secure_source,
437 bool modify_http_only,
rdsmith7ac81712017-06-22 17:09:54438 SetCookiesCallback callback) {
rdsmitha6ce4442017-06-21 17:11:05439 DCHECK(cookie->IsCanonical());
rdsmitha6ce4442017-06-21 17:11:05440
Maks Orlovich323efaf2018-03-06 02:56:39441 std::string domain = cookie->Domain();
442 DoCookieCallbackForHostOrDomain(
443 base::BindOnce(
444 // base::Unretained is safe as DoCookieCallbackForURL stores
445 // the callback on |*this|, so the callback will not outlive
446 // the object.
447 &CookieMonster::SetCanonicalCookie, base::Unretained(this),
448 std::move(cookie), secure_source, modify_http_only,
449 std::move(callback)),
450 domain);
rdsmitha6ce4442017-06-21 17:11:05451}
452
rdsmith7ac81712017-06-22 17:09:54453void CookieMonster::SetCookieWithOptionsAsync(const GURL& url,
454 const std::string& cookie_line,
455 const CookieOptions& options,
456 SetCookiesCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00457 DoCookieCallbackForURL(
458 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::SetCookieWithOptions, base::Unretained(this), url,
463 cookie_line, options, std::move(callback)),
464 url);
[email protected]218aa6a12011-09-13 17:38:38465}
466
mkwstc611e6d2016-02-23 15:45:55467void CookieMonster::GetCookieListWithOptionsAsync(
mmenke74bcbd52016-01-21 17:17:56468 const GURL& url,
mkwstc611e6d2016-02-23 15:45:55469 const CookieOptions& options,
rdsmith7ac81712017-06-22 17:09:54470 GetCookieListCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00471 DoCookieCallbackForURL(
Ken Rockotc2048612018-03-29 01:43:32472 InstrumentGetCookieListClosure(base::BindOnce(
rdsmithe5c701d2017-07-12 21:50:00473 // base::Unretained is safe as DoCookieCallbackForURL stores
474 // the callback on |*this|, so the callback will not outlive
475 // the object.
476 &CookieMonster::GetCookieListWithOptions, base::Unretained(this), url,
Ken Rockotc2048612018-03-29 01:43:32477 options, std::move(callback))),
rdsmithe5c701d2017-07-12 21:50:00478 url);
mmenke74bcbd52016-01-21 17:17:56479}
480
rdsmith7ac81712017-06-22 17:09:54481void CookieMonster::GetAllCookiesAsync(GetCookieListCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00482 DoCookieCallback(base::BindOnce(
483 // base::Unretained is safe as DoCookieCallbackForURL stores
484 // the callback on |*this|, so the callback will not outlive
485 // the object.
486 &CookieMonster::GetAllCookies, base::Unretained(this),
487 std::move(callback)));
mmenke9fa44f2d2016-01-22 23:36:39488}
489
[email protected]218aa6a12011-09-13 17:38:38490void CookieMonster::DeleteCookieAsync(const GURL& url,
491 const std::string& cookie_name,
rdsmith7ac81712017-06-22 17:09:54492 base::OnceClosure callback) {
rdsmithe5c701d2017-07-12 21:50:00493 DoCookieCallbackForURL(
494 base::BindOnce(
495 // base::Unretained is safe as DoCookieCallbackForURL stores
496 // the callback on |*this|, so the callback will not outlive
497 // the object.
498 &CookieMonster::DeleteCookie, base::Unretained(this), url,
499 cookie_name, std::move(callback)),
500 url);
[email protected]218aa6a12011-09-13 17:38:38501}
502
mmenke24379d52016-02-05 23:50:17503void CookieMonster::DeleteCanonicalCookieAsync(const CanonicalCookie& cookie,
rdsmith7ac81712017-06-22 17:09:54504 DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00505 DoCookieCallback(base::BindOnce(
506 // base::Unretained is safe as DoCookieCallbackForURL stores
507 // the callback on |*this|, so the callback will not outlive
508 // the object.
509 &CookieMonster::DeleteCanonicalCookie, base::Unretained(this), cookie,
510 std::move(callback)));
mmenke24379d52016-02-05 23:50:17511}
512
Chris Mumford800caa62018-04-20 19:34:44513void CookieMonster::DeleteAllCreatedInTimeRangeAsync(
514 const TimeRange& creation_range,
515 DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00516 DoCookieCallback(base::BindOnce(
517 // base::Unretained is safe as DoCookieCallbackForURL stores
518 // the callback on |*this|, so the callback will not outlive
519 // the object.
Chris Mumford800caa62018-04-20 19:34:44520 &CookieMonster::DeleteAllCreatedInTimeRange, base::Unretained(this),
521 creation_range, std::move(callback)));
mmenke74bcbd52016-01-21 17:17:56522}
523
Chris Mumford800caa62018-04-20 19:34:44524void CookieMonster::DeleteAllMatchingInfoAsync(CookieDeletionInfo delete_info,
525 DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00526 DoCookieCallback(base::BindOnce(
527 // base::Unretained is safe as DoCookieCallbackForURL stores
528 // the callback on |*this|, so the callback will not outlive
529 // the object.
Chris Mumford800caa62018-04-20 19:34:44530 &CookieMonster::DeleteAllMatchingInfo, base::Unretained(this),
531 std::move(delete_info), std::move(callback)));
mmenke74bcbd52016-01-21 17:17:56532}
533
[email protected]264807b2012-04-25 14:49:37534void CookieMonster::DeleteSessionCookiesAsync(
rdsmith7ac81712017-06-22 17:09:54535 CookieStore::DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00536 DoCookieCallback(base::BindOnce(
537 // base::Unretained is safe as DoCookieCallbackForURL stores
538 // the callback on |*this|, so the callback will not outlive
539 // the object.
540 &CookieMonster::DeleteSessionCookies, base::Unretained(this),
541 std::move(callback)));
[email protected]264807b2012-04-25 14:49:37542}
543
mmenke18dd8ba2016-02-01 18:42:10544void CookieMonster::SetCookieableSchemes(
545 const std::vector<std::string>& schemes) {
mmenkebe0910d2016-03-01 19:09:09546 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56547
548 // Calls to this method will have no effect if made after a WebView or
549 // CookieManager instance has been created.
mmenke18dd8ba2016-02-01 18:42:10550 if (initialized_)
mmenke74bcbd52016-01-21 17:17:56551 return;
mmenke74bcbd52016-01-21 17:17:56552
mmenke18dd8ba2016-02-01 18:42:10553 cookieable_schemes_ = schemes;
mmenke74bcbd52016-01-21 17:17:56554}
555
mmenke74bcbd52016-01-21 17:17:56556// This function must be called before the CookieMonster is used.
557void CookieMonster::SetPersistSessionCookies(bool persist_session_cookies) {
mmenkebe0910d2016-03-01 19:09:09558 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56559 DCHECK(!initialized_);
Helen Licd0fab862018-08-13 16:07:53560 net_log_.AddEvent(
561 NetLogEventType::COOKIE_STORE_SESSION_PERSISTENCE,
562 NetLog::BoolCallback("persistence", persist_session_cookies));
mmenke74bcbd52016-01-21 17:17:56563 persist_session_cookies_ = persist_session_cookies;
564}
565
566bool CookieMonster::IsCookieableScheme(const std::string& scheme) {
mmenkebe0910d2016-03-01 19:09:09567 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56568
tripta.gdda72022017-06-19 05:16:23569 return base::ContainsValue(cookieable_schemes_, scheme);
mmenke74bcbd52016-01-21 17:17:56570}
571
mmenke18dd8ba2016-02-01 18:42:10572const char* const CookieMonster::kDefaultCookieableSchemes[] = {"http", "https",
573 "ws", "wss"};
mmenke74bcbd52016-01-21 17:17:56574const int CookieMonster::kDefaultCookieableSchemesCount =
Ryan Sleevi435a3a22018-05-15 02:16:07575 base::size(kDefaultCookieableSchemes);
mmenke74bcbd52016-01-21 17:17:56576
Victor Costan14f47c12018-03-01 08:02:24577CookieChangeDispatcher& CookieMonster::GetChangeDispatcher() {
578 return change_dispatcher_;
Randy Smithd32dc8c2017-08-30 18:03:40579}
580
nharper5babb5e62016-03-09 18:58:07581bool CookieMonster::IsEphemeral() {
582 return store_.get() == nullptr;
583}
584
Maks Orlovich5cf437b02018-03-27 04:40:42585void CookieMonster::DumpMemoryStats(
586 base::trace_event::ProcessMemoryDump* pmd,
587 const std::string& parent_absolute_name) const {
588 const char kRelPath[] = "/cookie_monster";
589
590 pmd->CreateAllocatorDump(parent_absolute_name + kRelPath + "/cookies")
591 ->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
592 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
593 cookies_.size());
594
595 pmd->CreateAllocatorDump(parent_absolute_name + kRelPath +
596 "/tasks_pending_global")
597 ->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
598 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
599 tasks_pending_.size());
600
601 size_t total_pending_for_key = 0;
602 for (const auto& kv : tasks_pending_for_key_)
603 total_pending_for_key += kv.second.size();
604 pmd->CreateAllocatorDump(parent_absolute_name + kRelPath +
605 "/tasks_pending_for_key")
606 ->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
607 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
608 total_pending_for_key);
609}
610
mmenke74bcbd52016-01-21 17:17:56611CookieMonster::~CookieMonster() {
mmenkebe0910d2016-03-01 19:09:09612 DCHECK(thread_checker_.CalledOnValidThread());
mmenke05255cf2016-02-03 15:49:31613
Nick Harper14e23332017-07-28 00:27:23614 if (channel_id_service_ && store_) {
615 store_->SetBeforeFlushCallback(base::Closure());
616 }
617
Randy Smith0a522662017-08-30 19:35:34618 // TODO(mmenke): Does it really make sense to run
mmenke606c59c2016-03-07 18:20:55619 // CookieChanged callbacks when the CookieStore is destroyed?
mmenke05255cf2016-02-03 15:49:31620 for (CookieMap::iterator cookie_it = cookies_.begin();
621 cookie_it != cookies_.end();) {
622 CookieMap::iterator current_cookie_it = cookie_it;
623 ++cookie_it;
624 InternalDeleteCookie(current_cookie_it, false /* sync_to_store */,
625 DELETE_COOKIE_DONT_RECORD);
626 }
Helen Licd0fab862018-08-13 16:07:53627 net_log_.EndEvent(NetLogEventType::COOKIE_STORE_ALIVE);
[email protected]85620342011-10-17 17:35:04628}
629
rdsmithe5c701d2017-07-12 21:50:00630void CookieMonster::GetAllCookies(GetCookieListCallback callback) {
mmenkebe0910d2016-03-01 19:09:09631 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40632
633 // This function is being called to scrape the cookie list for management UI
634 // or similar. We shouldn't show expired cookies in this list since it will
635 // just be confusing to users, and this function is called rarely enough (and
636 // is already slow enough) that it's OK to take the time to garbage collect
637 // the expired cookies now.
638 //
639 // Note that this does not prune cookies to be below our limits (if we've
640 // exceeded them) the way that calling GarbageCollect() would.
mkwstbe84af312015-02-20 08:52:45641 GarbageCollectExpired(
642 Time::Now(), CookieMapItPair(cookies_.begin(), cookies_.end()), NULL);
[email protected]f48b9432011-01-11 07:25:40643
644 // Copy the CanonicalCookie pointers from the map so that we can use the same
645 // sorter as elsewhere, then copy the result out.
646 std::vector<CanonicalCookie*> cookie_ptrs;
647 cookie_ptrs.reserve(cookies_.size());
avie7cd11a2016-10-11 02:00:35648 for (const auto& cookie : cookies_)
649 cookie_ptrs.push_back(cookie.second.get());
[email protected]f48b9432011-01-11 07:25:40650 std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
651
652 CookieList cookie_list;
653 cookie_list.reserve(cookie_ptrs.size());
vmpstr6d9996c82017-02-23 00:43:25654 for (auto* cookie_ptr : cookie_ptrs)
avie7cd11a2016-10-11 02:00:35655 cookie_list.push_back(*cookie_ptr);
[email protected]f48b9432011-01-11 07:25:40656
rdsmithe5c701d2017-07-12 21:50:00657 MaybeRunCookieCallback(std::move(callback), cookie_list);
[email protected]f325f1e12010-04-30 22:38:55658}
659
rdsmithe5c701d2017-07-12 21:50:00660void CookieMonster::GetCookieListWithOptions(const GURL& url,
661 const CookieOptions& options,
662 GetCookieListCallback callback) {
mmenkebe0910d2016-03-01 19:09:09663 DCHECK(thread_checker_.CalledOnValidThread());
initial.commit586acc5fe2008-07-26 22:42:52664
mkwstc611e6d2016-02-23 15:45:55665 CookieList cookies;
rdsmithe5c701d2017-07-12 21:50:00666 if (HasCookieableScheme(url)) {
667 std::vector<CanonicalCookie*> cookie_ptrs;
668 FindCookiesForHostAndDomain(url, options, &cookie_ptrs);
669 std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
mkwstc611e6d2016-02-23 15:45:55670
rdsmithe5c701d2017-07-12 21:50:00671 cookies.reserve(cookie_ptrs.size());
672 for (std::vector<CanonicalCookie*>::const_iterator it = cookie_ptrs.begin();
673 it != cookie_ptrs.end(); it++)
674 cookies.push_back(**it);
675 }
676 MaybeRunCookieCallback(std::move(callback), cookies);
initial.commit586acc5fe2008-07-26 22:42:52677}
678
Chris Mumford800caa62018-04-20 19:34:44679void CookieMonster::DeleteAllCreatedInTimeRange(const TimeRange& creation_range,
680 DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09681 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]d0980332010-11-16 17:08:53682
rdsmitha5beda162017-07-08 13:55:42683 uint32_t num_deleted = 0;
[email protected]f48b9432011-01-11 07:25:40684 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
685 CookieMap::iterator curit = it;
avie7cd11a2016-10-11 02:00:35686 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:40687 ++it;
[email protected]d0980332010-11-16 17:08:53688
Chris Mumford800caa62018-04-20 19:34:44689 if (creation_range.Contains(cc->CreationDate())) {
mkwstbe84af312015-02-20 08:52:45690 InternalDeleteCookie(curit, true, /*sync_to_store*/
Nick Harper7a6683a2018-01-30 20:42:52691 DELETE_COOKIE_EXPLICIT);
[email protected]f48b9432011-01-11 07:25:40692 ++num_deleted;
initial.commit586acc5fe2008-07-26 22:42:52693 }
694 }
695
rdsmithe5c701d2017-07-12 21:50:00696 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39697 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00698 callback ? base::BindOnce(std::move(callback), num_deleted)
699 : base::OnceClosure()));
[email protected]f48b9432011-01-11 07:25:40700}
701
Chris Mumford800caa62018-04-20 19:34:44702void CookieMonster::DeleteAllMatchingInfo(CookieDeletionInfo delete_info,
703 DeleteCallback callback) {
rdsmitha5beda162017-07-08 13:55:42704 uint32_t num_deleted = 0;
dmurphfaea244c2016-04-09 00:42:30705 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
706 CookieMap::iterator curit = it;
avie7cd11a2016-10-11 02:00:35707 CanonicalCookie* cc = curit->second.get();
dmurphfaea244c2016-04-09 00:42:30708 ++it;
[email protected]f48b9432011-01-11 07:25:40709
Chris Mumford800caa62018-04-20 19:34:44710 if (delete_info.Matches(*cc)) {
dmurphfaea244c2016-04-09 00:42:30711 InternalDeleteCookie(curit, true, /*sync_to_store*/
Nick Harper7a6683a2018-01-30 20:42:52712 DELETE_COOKIE_EXPLICIT);
dmurphfaea244c2016-04-09 00:42:30713 ++num_deleted;
[email protected]f48b9432011-01-11 07:25:40714 }
715 }
dmurphfaea244c2016-04-09 00:42:30716
rdsmithe5c701d2017-07-12 21:50:00717 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39718 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00719 callback ? base::BindOnce(std::move(callback), num_deleted)
720 : base::OnceClosure()));
[email protected]f48b9432011-01-11 07:25:40721}
722
rdsmithe5c701d2017-07-12 21:50:00723void CookieMonster::SetCookieWithOptions(const GURL& url,
[email protected]f48b9432011-01-11 07:25:40724 const std::string& cookie_line,
rdsmithe5c701d2017-07-12 21:50:00725 const CookieOptions& options,
726 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:09727 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40728
729 if (!HasCookieableScheme(url)) {
rdsmithe5c701d2017-07-12 21:50:00730 MaybeRunCookieCallback(std::move(callback), false);
731 return;
[email protected]f48b9432011-01-11 07:25:40732 }
733
Oscar Johansson63e83cf2018-07-02 08:47:26734 VLOG(net::cookie_util::kVlogSetCookies)
735 << "SetCookie() line: " << cookie_line;
Maks Orlovicha61ed022018-03-01 18:24:24736
737 Time creation_time = CurrentTime();
738 last_time_seen_ = creation_time;
739
740 std::unique_ptr<CanonicalCookie> cc(
741 CanonicalCookie::Create(url, cookie_line, creation_time, options));
742
743 if (!cc.get()) {
Oscar Johansson63e83cf2018-07-02 08:47:26744 VLOG(net::cookie_util::kVlogSetCookies)
745 << "WARNING: Failed to allocate CanonicalCookie";
Maks Orlovicha61ed022018-03-01 18:24:24746 MaybeRunCookieCallback(std::move(callback), false);
747 return;
748 }
749 SetCanonicalCookie(std::move(cc), url.SchemeIsCryptographic(),
750 !options.exclude_httponly(), std::move(callback));
[email protected]f48b9432011-01-11 07:25:40751}
752
[email protected]f48b9432011-01-11 07:25:40753void CookieMonster::DeleteCookie(const GURL& url,
rdsmithe5c701d2017-07-12 21:50:00754 const std::string& cookie_name,
755 base::OnceClosure callback) {
mmenkebe0910d2016-03-01 19:09:09756 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40757
rdsmithe5c701d2017-07-12 21:50:00758 if (!HasCookieableScheme(url)) {
759 // TODO(rdsmith): Would be good to provide a failure indication here.
760 MaybeRunCookieCallback(std::move(callback));
[email protected]f48b9432011-01-11 07:25:40761 return;
rdsmithe5c701d2017-07-12 21:50:00762 }
[email protected]f48b9432011-01-11 07:25:40763
764 CookieOptions options;
765 options.set_include_httponly();
mkwstf71d0bd2016-03-21 14:15:24766 options.set_same_site_cookie_mode(
767 CookieOptions::SameSiteCookieMode::INCLUDE_STRICT_AND_LAX);
[email protected]f48b9432011-01-11 07:25:40768 // Get the cookies for this host and its domain(s).
769 std::vector<CanonicalCookie*> cookies;
mkwst72b65162016-02-22 19:58:54770 FindCookiesForHostAndDomain(url, options, &cookies);
[email protected]f48b9432011-01-11 07:25:40771 std::set<CanonicalCookie*> matching_cookies;
772
vmpstr6f21f242016-06-29 02:16:47773 for (auto* cookie : cookies) {
mmenke4379aeb2016-03-05 12:22:07774 if (cookie->Name() != cookie_name)
[email protected]f48b9432011-01-11 07:25:40775 continue;
mmenke4379aeb2016-03-05 12:22:07776 if (!cookie->IsOnPath(url.path()))
[email protected]f48b9432011-01-11 07:25:40777 continue;
mmenke4379aeb2016-03-05 12:22:07778 matching_cookies.insert(cookie);
[email protected]f48b9432011-01-11 07:25:40779 }
780
781 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
782 CookieMap::iterator curit = it;
783 ++it;
avie7cd11a2016-10-11 02:00:35784 if (matching_cookies.find(curit->second.get()) != matching_cookies.end()) {
Nick Harper7a6683a2018-01-30 20:42:52785 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPLICIT);
[email protected]f48b9432011-01-11 07:25:40786 }
787 }
rdsmithe5c701d2017-07-12 21:50:00788
Maks Orlovichf97d1b92018-03-06 17:25:39789 FlushStore(base::BindOnce(&MaybeRunDeleteCallback,
rdsmithe5c701d2017-07-12 21:50:00790 weak_ptr_factory_.GetWeakPtr(),
791 // No callback null check needed as BindOnce
792 // is not being called and MaybeRunDeleteCallback
793 // has its own check.
794 std::move(callback)));
[email protected]f48b9432011-01-11 07:25:40795}
796
rdsmithe5c701d2017-07-12 21:50:00797void CookieMonster::DeleteCanonicalCookie(const CanonicalCookie& cookie,
798 DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09799 DCHECK(thread_checker_.CalledOnValidThread());
mmenke24379d52016-02-05 23:50:17800
rdsmithe5c701d2017-07-12 21:50:00801 uint32_t result = 0u;
mmenke24379d52016-02-05 23:50:17802 for (CookieMapItPair its = cookies_.equal_range(GetKey(cookie.Domain()));
803 its.first != its.second; ++its.first) {
Maks Orlovich2896ec3f2018-04-06 13:34:27804 const std::unique_ptr<CanonicalCookie>& candidate = its.first->second;
805 // Historically, this has refused modification if the cookie has changed
806 // value in between the CanonicalCookie object was returned by a getter
807 // and when this ran. The later parts of the conditional (everything but
808 // the equivalence check) attempt to preserve this behavior.
809 if (candidate->IsEquivalent(cookie) &&
810 candidate->CreationDate() == cookie.CreationDate() &&
811 candidate->Value() == cookie.Value()) {
Nick Harper7a6683a2018-01-30 20:42:52812 InternalDeleteCookie(its.first, true, DELETE_COOKIE_EXPLICIT);
rdsmithe5c701d2017-07-12 21:50:00813 result = 1u;
814 break;
mmenke24379d52016-02-05 23:50:17815 }
816 }
rdsmithe5c701d2017-07-12 21:50:00817 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39818 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00819 callback ? base::BindOnce(std::move(callback), result)
820 : base::OnceClosure()));
mmenke24379d52016-02-05 23:50:17821}
822
rdsmithe5c701d2017-07-12 21:50:00823void CookieMonster::DeleteSessionCookies(DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09824 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]264807b2012-04-25 14:49:37825
rdsmitha5beda162017-07-08 13:55:42826 uint32_t num_deleted = 0;
[email protected]264807b2012-04-25 14:49:37827 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
828 CookieMap::iterator curit = it;
avie7cd11a2016-10-11 02:00:35829 CanonicalCookie* cc = curit->second.get();
[email protected]264807b2012-04-25 14:49:37830 ++it;
831
832 if (!cc->IsPersistent()) {
mkwstbe84af312015-02-20 08:52:45833 InternalDeleteCookie(curit, true, /*sync_to_store*/
[email protected]264807b2012-04-25 14:49:37834 DELETE_COOKIE_EXPIRED);
835 ++num_deleted;
836 }
837 }
838
rdsmithe5c701d2017-07-12 21:50:00839 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39840 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00841 callback ? base::BindOnce(std::move(callback), num_deleted)
842 : base::OnceClosure()));
[email protected]264807b2012-04-25 14:49:37843}
844
erikchen1dd72a72015-05-06 20:45:05845void CookieMonster::MarkCookieStoreAsInitialized() {
mmenkebe0910d2016-03-01 19:09:09846 DCHECK(thread_checker_.CalledOnValidThread());
erikchen1dd72a72015-05-06 20:45:05847 initialized_ = true;
848}
849
850void CookieMonster::FetchAllCookiesIfNecessary() {
mmenkebe0910d2016-03-01 19:09:09851 DCHECK(thread_checker_.CalledOnValidThread());
erikchen1dd72a72015-05-06 20:45:05852 if (store_.get() && !started_fetching_all_cookies_) {
853 started_fetching_all_cookies_ = true;
854 FetchAllCookies();
855 }
856}
857
mmenke74bcbd52016-01-21 17:17:56858void CookieMonster::FetchAllCookies() {
mmenkebe0910d2016-03-01 19:09:09859 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56860 DCHECK(store_.get()) << "Store must exist to initialize";
861 DCHECK(!finished_fetching_all_cookies_)
862 << "All cookies have already been fetched.";
863
864 // We bind in the current time so that we can report the wall-clock time for
865 // loading cookies.
mmenkebe0910d2016-03-01 19:09:09866 store_->Load(base::Bind(&CookieMonster::OnLoaded,
Helen Li92a29f102018-08-15 23:02:26867 weak_ptr_factory_.GetWeakPtr(), TimeTicks::Now()),
868 net_log_);
mmenke74bcbd52016-01-21 17:17:56869}
870
avie7cd11a2016-10-11 02:00:35871void CookieMonster::OnLoaded(
872 TimeTicks beginning_time,
873 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:09874 DCHECK(thread_checker_.CalledOnValidThread());
avie7cd11a2016-10-11 02:00:35875 StoreLoadedCookies(std::move(cookies));
[email protected]c7593fb22011-11-14 23:54:27876 histogram_time_blocked_on_load_->AddTime(TimeTicks::Now() - beginning_time);
[email protected]218aa6a12011-09-13 17:38:38877
878 // Invoke the task queue of cookie request.
879 InvokeQueue();
880}
881
avie7cd11a2016-10-11 02:00:35882void CookieMonster::OnKeyLoaded(
883 const std::string& key,
884 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:09885 DCHECK(thread_checker_.CalledOnValidThread());
886
avie7cd11a2016-10-11 02:00:35887 StoreLoadedCookies(std::move(cookies));
[email protected]85620342011-10-17 17:35:04888
mmenkebe0910d2016-03-01 19:09:09889 auto tasks_pending_for_key = tasks_pending_for_key_.find(key);
[email protected]85620342011-10-17 17:35:04890
mmenkebe0910d2016-03-01 19:09:09891 // TODO(mmenke): Can this be turned into a DCHECK?
892 if (tasks_pending_for_key == tasks_pending_for_key_.end())
893 return;
[email protected]bab72ec2013-10-30 20:50:02894
mmenkebe0910d2016-03-01 19:09:09895 // Run all tasks for the key. Note that running a task can result in multiple
896 // tasks being added to the back of the deque.
897 while (!tasks_pending_for_key->second.empty()) {
rdsmithe5c701d2017-07-12 21:50:00898 base::OnceClosure task = std::move(tasks_pending_for_key->second.front());
mmenkebe0910d2016-03-01 19:09:09899 tasks_pending_for_key->second.pop_front();
rdsmithe5c701d2017-07-12 21:50:00900 std::move(task).Run();
[email protected]85620342011-10-17 17:35:04901 }
mmenkebe0910d2016-03-01 19:09:09902
903 tasks_pending_for_key_.erase(tasks_pending_for_key);
904
905 // This has to be done last, in case running a task queues a new task for the
906 // key, to ensure tasks are run in the correct order.
907 keys_loaded_.insert(key);
[email protected]85620342011-10-17 17:35:04908}
909
[email protected]218aa6a12011-09-13 17:38:38910void CookieMonster::StoreLoadedCookies(
avie7cd11a2016-10-11 02:00:35911 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:09912 DCHECK(thread_checker_.CalledOnValidThread());
913
mmenkebe0910d2016-03-01 19:09:09914 // Even if a key is expired, insert it so it can be garbage collected,
915 // removed, and sync'd.
[email protected]6210ce52013-09-20 03:33:14916 CookieItVector cookies_with_control_chars;
917
avie7cd11a2016-10-11 02:00:35918 for (auto& cookie : cookies) {
Maks Orlovich2b0d5b12018-04-10 19:33:47919 CanonicalCookie* cookie_ptr = cookie.get();
920 CookieMap::iterator inserted = InternalInsertCookie(
921 GetKey(cookie_ptr->Domain()), std::move(cookie), false);
922 const Time cookie_access_time(cookie_ptr->LastAccessDate());
923 if (earliest_access_time_.is_null() ||
Helen Lid84010b2018-08-22 16:27:44924 cookie_access_time < earliest_access_time_) {
Maks Orlovich2b0d5b12018-04-10 19:33:47925 earliest_access_time_ = cookie_access_time;
Helen Lid84010b2018-08-22 16:27:44926 }
[email protected]f48b9432011-01-11 07:25:40927
Maks Orlovich2b0d5b12018-04-10 19:33:47928 if (ContainsControlCharacter(cookie_ptr->Name()) ||
929 ContainsControlCharacter(cookie_ptr->Value())) {
930 cookies_with_control_chars.push_back(inserted);
[email protected]f48b9432011-01-11 07:25:40931 }
932 }
[email protected]f48b9432011-01-11 07:25:40933
[email protected]6210ce52013-09-20 03:33:14934 // Any cookies that contain control characters that we have loaded from the
935 // persistent store should be deleted. See http://crbug.com/238041.
936 for (CookieItVector::iterator it = cookies_with_control_chars.begin();
937 it != cookies_with_control_chars.end();) {
938 CookieItVector::iterator curit = it;
939 ++it;
940
941 InternalDeleteCookie(*curit, true, DELETE_COOKIE_CONTROL_CHAR);
942 }
943
[email protected]f48b9432011-01-11 07:25:40944 // After importing cookies from the PersistentCookieStore, verify that
945 // none of our other constraints are violated.
[email protected]f48b9432011-01-11 07:25:40946 // In particular, the backing store might have given us duplicate cookies.
[email protected]85620342011-10-17 17:35:04947
948 // This method could be called multiple times due to priority loading, thus
949 // cookies loaded in previous runs will be validated again, but this is OK
950 // since they are expected to be much fewer than total DB.
[email protected]f48b9432011-01-11 07:25:40951 EnsureCookiesMapIsValid();
[email protected]218aa6a12011-09-13 17:38:38952}
[email protected]f48b9432011-01-11 07:25:40953
[email protected]218aa6a12011-09-13 17:38:38954void CookieMonster::InvokeQueue() {
mmenkebe0910d2016-03-01 19:09:09955 DCHECK(thread_checker_.CalledOnValidThread());
956
mmenkef49fca0e2016-03-08 12:46:24957 // Move all per-key tasks into the global queue, if there are any. This is
958 // protection about a race where the store learns about all cookies loading
959 // before it learned about the cookies for a key loading.
960
961 // Needed to prevent any recursively queued tasks from going back into the
962 // per-key queues.
963 seen_global_task_ = true;
rdsmithe5c701d2017-07-12 21:50:00964 for (auto& tasks_for_key : tasks_pending_for_key_) {
965 tasks_pending_.insert(tasks_pending_.begin(),
966 std::make_move_iterator(tasks_for_key.second.begin()),
967 std::make_move_iterator(tasks_for_key.second.end()));
mmenkef49fca0e2016-03-08 12:46:24968 }
969 tasks_pending_for_key_.clear();
970
mmenkebe0910d2016-03-01 19:09:09971 while (!tasks_pending_.empty()) {
rdsmithe5c701d2017-07-12 21:50:00972 base::OnceClosure request_task = std::move(tasks_pending_.front());
mmenkef49fca0e2016-03-08 12:46:24973 tasks_pending_.pop_front();
rdsmithe5c701d2017-07-12 21:50:00974 std::move(request_task).Run();
[email protected]218aa6a12011-09-13 17:38:38975 }
mmenkebe0910d2016-03-01 19:09:09976
mmenkef49fca0e2016-03-08 12:46:24977 DCHECK(tasks_pending_for_key_.empty());
978
mmenkebe0910d2016-03-01 19:09:09979 finished_fetching_all_cookies_ = true;
mmenkebe0910d2016-03-01 19:09:09980 keys_loaded_.clear();
[email protected]f48b9432011-01-11 07:25:40981}
982
983void CookieMonster::EnsureCookiesMapIsValid() {
mmenkebe0910d2016-03-01 19:09:09984 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40985
[email protected]f48b9432011-01-11 07:25:40986 // Iterate through all the of the cookies, grouped by host.
987 CookieMap::iterator prev_range_end = cookies_.begin();
988 while (prev_range_end != cookies_.end()) {
989 CookieMap::iterator cur_range_begin = prev_range_end;
990 const std::string key = cur_range_begin->first; // Keep a copy.
991 CookieMap::iterator cur_range_end = cookies_.upper_bound(key);
992 prev_range_end = cur_range_end;
993
994 // Ensure no equivalent cookies for this host.
ellyjonescabf57422015-08-21 18:44:51995 TrimDuplicateCookiesForKey(key, cur_range_begin, cur_range_end);
[email protected]f48b9432011-01-11 07:25:40996 }
[email protected]f48b9432011-01-11 07:25:40997}
998
ellyjonescabf57422015-08-21 18:44:51999void CookieMonster::TrimDuplicateCookiesForKey(const std::string& key,
1000 CookieMap::iterator begin,
1001 CookieMap::iterator end) {
mmenkebe0910d2016-03-01 19:09:091002 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401003
1004 // Set of cookies ordered by creation time.
Maks Orlovich2b0d5b12018-04-10 19:33:471005 typedef std::multiset<CookieMap::iterator, OrderByCreationTimeDesc> CookieSet;
[email protected]f48b9432011-01-11 07:25:401006
1007 // Helper map we populate to find the duplicates.
1008 typedef std::map<CookieSignature, CookieSet> EquivalenceMap;
1009 EquivalenceMap equivalent_cookies;
1010
1011 // The number of duplicate cookies that have been found.
1012 int num_duplicates = 0;
1013
1014 // Iterate through all of the cookies in our range, and insert them into
1015 // the equivalence map.
1016 for (CookieMap::iterator it = begin; it != end; ++it) {
1017 DCHECK_EQ(key, it->first);
avie7cd11a2016-10-11 02:00:351018 CanonicalCookie* cookie = it->second.get();
[email protected]f48b9432011-01-11 07:25:401019
mkwstbe84af312015-02-20 08:52:451020 CookieSignature signature(cookie->Name(), cookie->Domain(), cookie->Path());
[email protected]f48b9432011-01-11 07:25:401021 CookieSet& set = equivalent_cookies[signature];
1022
1023 // We found a duplicate!
1024 if (!set.empty())
1025 num_duplicates++;
1026
1027 // We save the iterator into |cookies_| rather than the actual cookie
1028 // pointer, since we may need to delete it later.
Maks Orlovich2b0d5b12018-04-10 19:33:471029 set.insert(it);
[email protected]f48b9432011-01-11 07:25:401030 }
1031
1032 // If there were no duplicates, we are done!
1033 if (num_duplicates == 0)
ellyjonescabf57422015-08-21 18:44:511034 return;
[email protected]f48b9432011-01-11 07:25:401035
1036 // Make sure we find everything below that we did above.
1037 int num_duplicates_found = 0;
1038
1039 // Otherwise, delete all the duplicate cookies, both from our in-memory store
1040 // and from the backing store.
1041 for (EquivalenceMap::iterator it = equivalent_cookies.begin();
mkwstbe84af312015-02-20 08:52:451042 it != equivalent_cookies.end(); ++it) {
[email protected]f48b9432011-01-11 07:25:401043 const CookieSignature& signature = it->first;
1044 CookieSet& dupes = it->second;
1045
1046 if (dupes.size() <= 1)
1047 continue; // This cookiename/path has no duplicates.
1048 num_duplicates_found += dupes.size() - 1;
1049
Maks Orlovich2b0d5b12018-04-10 19:33:471050 // Since |dupes| is sorted by creation time (descending), the first cookie
1051 // is the most recent one (or tied for it), so we will keep it. The rest are
1052 // duplicates.
[email protected]f48b9432011-01-11 07:25:401053 dupes.erase(dupes.begin());
1054
1055 LOG(ERROR) << base::StringPrintf(
1056 "Found %d duplicate cookies for host='%s', "
1057 "with {name='%s', domain='%s', path='%s'}",
mkwstbe84af312015-02-20 08:52:451058 static_cast<int>(dupes.size()), key.c_str(), signature.name.c_str(),
1059 signature.domain.c_str(), signature.path.c_str());
[email protected]f48b9432011-01-11 07:25:401060
1061 // Remove all the cookies identified by |dupes|. It is valid to delete our
1062 // list of iterators one at a time, since |cookies_| is a multimap (they
1063 // don't invalidate existing iterators following deletion).
mkwstbe84af312015-02-20 08:52:451064 for (CookieSet::iterator dupes_it = dupes.begin(); dupes_it != dupes.end();
[email protected]f48b9432011-01-11 07:25:401065 ++dupes_it) {
[email protected]218aa6a12011-09-13 17:38:381066 InternalDeleteCookie(*dupes_it, true,
[email protected]f48b9432011-01-11 07:25:401067 DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE);
1068 }
1069 }
1070 DCHECK_EQ(num_duplicates, num_duplicates_found);
[email protected]f48b9432011-01-11 07:25:401071}
1072
[email protected]f48b9432011-01-11 07:25:401073void CookieMonster::FindCookiesForHostAndDomain(
1074 const GURL& url,
1075 const CookieOptions& options,
[email protected]f48b9432011-01-11 07:25:401076 std::vector<CanonicalCookie*>* cookies) {
mmenkebe0910d2016-03-01 19:09:091077 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401078
1079 const Time current_time(CurrentTime());
1080
1081 // Probe to save statistics relatively frequently. We do it here rather
1082 // than in the set path as many websites won't set cookies, and we
1083 // want to collect statistics whenever the browser's being used.
1084 RecordPeriodicStats(current_time);
1085
[email protected]8e1583672012-02-11 04:39:411086 // Can just dispatch to FindCookiesForKey
Maks Orlovich323efaf2018-03-06 02:56:391087 const std::string key(GetKey(url.host_piece()));
mkwst72b65162016-02-22 19:58:541088 FindCookiesForKey(key, url, options, current_time, cookies);
[email protected]f48b9432011-01-11 07:25:401089}
1090
[email protected]dedec0b2013-02-28 04:50:101091void CookieMonster::FindCookiesForKey(const std::string& key,
1092 const GURL& url,
1093 const CookieOptions& options,
1094 const Time& current,
[email protected]dedec0b2013-02-28 04:50:101095 std::vector<CanonicalCookie*>* cookies) {
mmenkebe0910d2016-03-01 19:09:091096 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401097
[email protected]f48b9432011-01-11 07:25:401098 for (CookieMapItPair its = cookies_.equal_range(key);
mkwstbe84af312015-02-20 08:52:451099 its.first != its.second;) {
[email protected]f48b9432011-01-11 07:25:401100 CookieMap::iterator curit = its.first;
avie7cd11a2016-10-11 02:00:351101 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:401102 ++its.first;
1103
1104 // If the cookie is expired, delete it.
mmenke3c79a652016-02-12 14:39:201105 if (cc->IsExpired(current)) {
[email protected]f48b9432011-01-11 07:25:401106 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
1107 continue;
1108 }
1109
[email protected]65f4e7e2012-12-12 21:56:541110 // Filter out cookies that should not be included for a request to the
1111 // given |url|. HTTP only cookies are filtered depending on the passed
1112 // cookie |options|.
1113 if (!cc->IncludeForRequestURL(url, options))
[email protected]f48b9432011-01-11 07:25:401114 continue;
1115
[email protected]65f4e7e2012-12-12 21:56:541116 // Add this cookie to the set of matching cookies. Update the access
[email protected]f48b9432011-01-11 07:25:401117 // time if we've been requested to do so.
mkwst72b65162016-02-22 19:58:541118 if (options.update_access_time()) {
[email protected]f48b9432011-01-11 07:25:401119 InternalUpdateCookieAccessTime(cc, current);
1120 }
1121 cookies->push_back(cc);
1122 }
1123}
1124
Mike Westc4a777b2017-10-06 14:04:201125bool CookieMonster::DeleteAnyEquivalentCookie(
1126 const std::string& key,
1127 const CanonicalCookie& ecc,
1128 bool source_secure,
1129 bool skip_httponly,
1130 bool already_expired,
1131 base::Time* creation_date_to_inherit) {
mmenkebe0910d2016-03-01 19:09:091132 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401133
1134 bool found_equivalent_cookie = false;
1135 bool skipped_httponly = false;
jww601411a2015-11-20 19:46:571136 bool skipped_secure_cookie = false;
jww31e32632015-12-16 23:38:341137
1138 histogram_cookie_delete_equivalent_->Add(COOKIE_DELETE_EQUIVALENT_ATTEMPT);
1139
Lily Chen22707642b2018-10-02 17:27:211140 CookieMap::iterator cookie_it_to_possibly_delete = cookies_.end();
1141 CanonicalCookie* cc_skipped_secure = nullptr;
[email protected]f48b9432011-01-11 07:25:401142 for (CookieMapItPair its = cookies_.equal_range(key);
mkwstbe84af312015-02-20 08:52:451143 its.first != its.second;) {
[email protected]f48b9432011-01-11 07:25:401144 CookieMap::iterator curit = its.first;
avie7cd11a2016-10-11 02:00:351145 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:401146 ++its.first;
1147
jwwa26e439d2017-01-27 18:17:271148 // If the cookie is being set from an insecure scheme, then if a cookie
1149 // already exists with the same name and it is Secure, then the cookie
1150 // should *not* be updated if they domain-match and ignoring the path
1151 // attribute.
jww601411a2015-11-20 19:46:571152 //
jwwa26e439d2017-01-27 18:17:271153 // See: https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone
rdsmith2709eee2017-06-20 22:43:271154 if (cc->IsSecure() && !source_secure &&
mmenke2830b0722016-07-20 16:02:501155 ecc.IsEquivalentForSecureCookieMatching(*cc)) {
jww601411a2015-11-20 19:46:571156 skipped_secure_cookie = true;
Lily Chen22707642b2018-10-02 17:27:211157 cc_skipped_secure = cc;
jww31e32632015-12-16 23:38:341158 histogram_cookie_delete_equivalent_->Add(
1159 COOKIE_DELETE_EQUIVALENT_SKIPPING_SECURE);
Helen Licd0fab862018-08-13 16:07:531160 net_log_.AddEvent(
1161 NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_SECURE,
1162 base::BindRepeating(&NetLogCookieMonsterCookieRejectedSecure, cc,
1163 &ecc));
jww31e32632015-12-16 23:38:341164 // If the cookie is equivalent to the new cookie and wouldn't have been
1165 // skipped for being HTTP-only, record that it is a skipped secure cookie
1166 // that would have been deleted otherwise.
1167 if (ecc.IsEquivalent(*cc)) {
jwwa9a0d482015-12-16 18:19:411168 found_equivalent_cookie = true;
jww31e32632015-12-16 23:38:341169
1170 if (!skip_httponly || !cc->IsHttpOnly()) {
1171 histogram_cookie_delete_equivalent_->Add(
1172 COOKIE_DELETE_EQUIVALENT_WOULD_HAVE_DELETED);
1173 }
1174 }
jww601411a2015-11-20 19:46:571175 } else if (ecc.IsEquivalent(*cc)) {
[email protected]f48b9432011-01-11 07:25:401176 // We should never have more than one equivalent cookie, since they should
jww601411a2015-11-20 19:46:571177 // overwrite each other, unless secure cookies require secure scheme is
1178 // being enforced. In that case, cookies with different paths might exist
1179 // and be considered equivalent.
mkwstbe84af312015-02-20 08:52:451180 CHECK(!found_equivalent_cookie)
1181 << "Duplicate equivalent cookies found, cookie store is corrupted.";
Lily Chen22707642b2018-10-02 17:27:211182 DCHECK(cookie_it_to_possibly_delete == cookies_.end());
[email protected]f48b9432011-01-11 07:25:401183 if (skip_httponly && cc->IsHttpOnly()) {
1184 skipped_httponly = true;
Helen Licd0fab862018-08-13 16:07:531185 net_log_.AddEvent(
1186 NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_HTTPONLY,
1187 base::BindRepeating(&NetLogCookieMonsterCookieRejectedHttponly, cc,
1188 &ecc));
[email protected]f48b9432011-01-11 07:25:401189 } else {
Lily Chen22707642b2018-10-02 17:27:211190 cookie_it_to_possibly_delete = curit;
[email protected]f48b9432011-01-11 07:25:401191 }
1192 found_equivalent_cookie = true;
1193 }
1194 }
Lily Chen22707642b2018-10-02 17:27:211195
1196 if (cookie_it_to_possibly_delete != cookies_.end()) {
1197 CanonicalCookie* cc_to_possibly_delete =
1198 cookie_it_to_possibly_delete->second.get();
1199 // If a secure cookie was encountered (and left alone), don't actually
1200 // modify any of the pre-existing cookies. Only delete if no secure cookies
1201 // were skipped.
1202 if (!skipped_secure_cookie) {
1203 histogram_cookie_delete_equivalent_->Add(COOKIE_DELETE_EQUIVALENT_FOUND);
1204 if (cc_to_possibly_delete->Value() == ecc.Value()) {
1205 *creation_date_to_inherit = cc_to_possibly_delete->CreationDate();
1206 histogram_cookie_delete_equivalent_->Add(
1207 COOKIE_DELETE_EQUIVALENT_FOUND_WITH_SAME_VALUE);
1208 }
1209 InternalDeleteCookie(cookie_it_to_possibly_delete, true,
1210 already_expired ? DELETE_COOKIE_EXPIRED_OVERWRITE
1211 : DELETE_COOKIE_OVERWRITE);
1212 } else {
1213 // If any secure cookie was skipped, preserve the pre-existing cookie.
1214 DCHECK(cc_skipped_secure);
1215 net_log_.AddEvent(
1216 NetLogEventType::COOKIE_STORE_COOKIE_PRESERVED_SKIPPED_SECURE,
1217 base::BindRepeating(&NetLogCookieMonsterCookiePreservedSkippedSecure,
1218 cc_skipped_secure, cc_to_possibly_delete, &ecc));
1219 }
1220 }
1221
jww601411a2015-11-20 19:46:571222 return skipped_httponly || skipped_secure_cookie;
[email protected]f48b9432011-01-11 07:25:401223}
1224
[email protected]6210ce52013-09-20 03:33:141225CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie(
1226 const std::string& key,
avie7cd11a2016-10-11 02:00:351227 std::unique_ptr<CanonicalCookie> cc,
[email protected]6210ce52013-09-20 03:33:141228 bool sync_to_store) {
mmenkebe0910d2016-03-01 19:09:091229 DCHECK(thread_checker_.CalledOnValidThread());
avie7cd11a2016-10-11 02:00:351230 CanonicalCookie* cc_ptr = cc.get();
mmenkebe0910d2016-03-01 19:09:091231
Helen Licd0fab862018-08-13 16:07:531232 net_log_.AddEvent(NetLogEventType::COOKIE_STORE_COOKIE_ADDED,
1233 base::BindRepeating(&NetLogCookieMonsterCookieAdded,
1234 cc.get(), sync_to_store));
avie7cd11a2016-10-11 02:00:351235 if ((cc_ptr->IsPersistent() || persist_session_cookies_) && store_.get() &&
Helen Lid84010b2018-08-22 16:27:441236 sync_to_store) {
avie7cd11a2016-10-11 02:00:351237 store_->AddCookie(*cc_ptr);
Helen Lid84010b2018-08-22 16:27:441238 }
[email protected]6210ce52013-09-20 03:33:141239 CookieMap::iterator inserted =
avie7cd11a2016-10-11 02:00:351240 cookies_.insert(CookieMap::value_type(key, std::move(cc)));
mkwstc1aa4cc2015-04-03 19:57:451241
1242 // See InitializeHistograms() for details.
avie7cd11a2016-10-11 02:00:351243 int32_t type_sample = cc_ptr->SameSite() != CookieSameSite::NO_RESTRICTION
mkwste1a29582016-03-15 10:07:521244 ? 1 << COOKIE_TYPE_SAME_SITE
1245 : 0;
avie7cd11a2016-10-11 02:00:351246 type_sample |= cc_ptr->IsHttpOnly() ? 1 << COOKIE_TYPE_HTTPONLY : 0;
1247 type_sample |= cc_ptr->IsSecure() ? 1 << COOKIE_TYPE_SECURE : 0;
mkwst46549412016-02-01 10:05:371248 histogram_cookie_type_->Add(type_sample);
estark7feb65c2b2015-08-21 23:38:201249
Victor Costan14f47c12018-03-01 08:02:241250 change_dispatcher_.DispatchChange(*cc_ptr, CookieChangeCause::INSERTED, true);
[email protected]6210ce52013-09-20 03:33:141251
1252 return inserted;
[email protected]f48b9432011-01-11 07:25:401253}
1254
rdsmithe5c701d2017-07-12 21:50:001255void CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc,
rdsmith2709eee2017-06-20 22:43:271256 bool secure_source,
rdsmithe5c701d2017-07-12 21:50:001257 bool modify_http_only,
1258 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:091259 DCHECK(thread_checker_.CalledOnValidThread());
1260
Randy Smith10400072017-08-03 04:08:311261 if ((cc->IsSecure() && !secure_source) ||
1262 (cc->IsHttpOnly() && !modify_http_only)) {
rdsmithe5c701d2017-07-12 21:50:001263 MaybeRunCookieCallback(std::move(callback), false);
1264 return;
1265 }
rdsmith2709eee2017-06-20 22:43:271266
mmenkeea4cd402016-02-02 04:03:101267 const std::string key(GetKey(cc->Domain()));
rdsmitha6ce4442017-06-21 17:11:051268
1269 // TODO(mmenke): This class assumes each cookie to have a unique creation
1270 // time. Allowing the caller to set the creation time violates that
1271 // assumption. Worth fixing? Worth noting that time changes between browser
1272 // restarts can cause the same issue.
1273 base::Time creation_date = cc->CreationDate();
1274 if (creation_date.is_null()) {
1275 creation_date = CurrentTime();
1276 cc->SetCreationDate(creation_date);
1277 last_time_seen_ = creation_date;
1278 }
1279 bool already_expired = cc->IsExpired(creation_date);
ellyjones399e35a22014-10-27 11:09:561280
Mike Westc4a777b2017-10-06 14:04:201281 base::Time creation_date_to_inherit;
rdsmith2709eee2017-06-20 22:43:271282 if (DeleteAnyEquivalentCookie(key, *cc, secure_source, !modify_http_only,
Mike Westc4a777b2017-10-06 14:04:201283 already_expired, &creation_date_to_inherit)) {
jww601411a2015-11-20 19:46:571284 std::string error;
jwwa26e439d2017-01-27 18:17:271285 error =
1286 "SetCookie() not clobbering httponly cookie or secure cookie for "
1287 "insecure scheme";
jww601411a2015-11-20 19:46:571288
Oscar Johansson63e83cf2018-07-02 08:47:261289 VLOG(net::cookie_util::kVlogSetCookies) << error;
rdsmithe5c701d2017-07-12 21:50:001290 MaybeRunCookieCallback(std::move(callback), false);
1291 return;
[email protected]3a96c742008-11-19 19:46:271292 }
initial.commit586acc5fe2008-07-26 22:42:521293
Oscar Johansson63e83cf2018-07-02 08:47:261294 VLOG(net::cookie_util::kVlogSetCookies)
1295 << "SetCookie() key: " << key << " cc: " << cc->DebugString();
initial.commit586acc5fe2008-07-26 22:42:521296
1297 // Realize that we might be setting an expired cookie, and the only point
1298 // was to delete the cookie which we've already done.
mmenke3c79a652016-02-12 14:39:201299 if (!already_expired) {
[email protected]374f58b2010-07-20 15:29:261300 // See InitializeHistograms() for details.
mmenkeea4cd402016-02-02 04:03:101301 if (cc->IsPersistent()) {
[email protected]8475bee2011-03-17 18:40:241302 histogram_expiration_duration_minutes_->Add(
rdsmitha6ce4442017-06-21 17:11:051303 (cc->ExpiryDate() - creation_date).InMinutes());
[email protected]8475bee2011-03-17 18:40:241304 }
1305
rdsmith2709eee2017-06-20 22:43:271306 // Histogram the type of scheme used on URLs that set cookies. This
1307 // intentionally includes cookies that are set or overwritten by
1308 // http:// URLs, but not cookies that are cleared by http:// URLs, to
1309 // understand if the former behavior can be deprecated for Secure
1310 // cookies.
1311 CookieSource cookie_source_sample =
1312 (secure_source
1313 ? (cc->IsSecure()
1314 ? COOKIE_SOURCE_SECURE_COOKIE_CRYPTOGRAPHIC_SCHEME
1315 : COOKIE_SOURCE_NONSECURE_COOKIE_CRYPTOGRAPHIC_SCHEME)
1316 : (cc->IsSecure()
1317 ? COOKIE_SOURCE_SECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME
1318 : COOKIE_SOURCE_NONSECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME));
1319 histogram_cookie_source_scheme_->Add(cookie_source_sample);
1320
Mike Westc4a777b2017-10-06 14:04:201321 if (!creation_date_to_inherit.is_null()) {
1322 cc->SetCreationDate(creation_date_to_inherit);
1323 // |last_time_seen_| is intentionally not updated, as moving it into the
1324 // past might cause duplicate cookie creation dates. See
1325 // `CookieMonster::CurrentTime()` for details.
1326 }
1327
rdsmith2709eee2017-06-20 22:43:271328 InternalInsertCookie(key, std::move(cc), true);
[email protected]348dd662013-03-13 20:25:071329 } else {
Oscar Johansson63e83cf2018-07-02 08:47:261330 VLOG(net::cookie_util::kVlogSetCookies)
1331 << "SetCookie() not storing already expired cookie.";
[email protected]c4058fb2010-06-22 17:25:261332 }
initial.commit586acc5fe2008-07-26 22:42:521333
1334 // We assume that hopefully setting a cookie will be less common than
1335 // querying a cookie. Since setting a cookie can put us over our limits,
1336 // make sure that we garbage collect... We can also make the assumption that
1337 // if a cookie was set, in the common case it will be used soon after,
1338 // and we will purge the expired cookies in GetCookies().
rdsmitha6ce4442017-06-21 17:11:051339 GarbageCollect(creation_date, key);
initial.commit586acc5fe2008-07-26 22:42:521340
rdsmithe5c701d2017-07-12 21:50:001341 MaybeRunCookieCallback(std::move(callback), true);
initial.commit586acc5fe2008-07-26 22:42:521342}
1343
rdsmithe5c701d2017-07-12 21:50:001344void CookieMonster::SetAllCookies(CookieList list,
1345 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:091346 DCHECK(thread_checker_.CalledOnValidThread());
rdsmithe5c701d2017-07-12 21:50:001347
rdsmith0e84cea2017-07-13 03:09:531348 // Nuke the existing store.
1349 while (!cookies_.empty()) {
1350 // TODO(rdsmith): The CANONICAL is a lie.
Nick Harper7a6683a2018-01-30 20:42:521351 InternalDeleteCookie(cookies_.begin(), true, DELETE_COOKIE_EXPLICIT);
rdsmithe5c701d2017-07-12 21:50:001352 }
1353
rdsmith0e84cea2017-07-13 03:09:531354 // Set all passed in cookies.
mmenkeea4cd402016-02-02 04:03:101355 for (const auto& cookie : list) {
rdsmith2709eee2017-06-20 22:43:271356 const std::string key(GetKey(cookie.Domain()));
1357 Time creation_time = cookie.CreationDate();
rdsmith0e84cea2017-07-13 03:09:531358 if (cookie.IsExpired(creation_time))
rdsmith2709eee2017-06-20 22:43:271359 continue;
1360
1361 if (cookie.IsPersistent()) {
1362 histogram_expiration_duration_minutes_->Add(
1363 (cookie.ExpiryDate() - creation_time).InMinutes());
mmenkeea4cd402016-02-02 04:03:101364 }
rdsmith2709eee2017-06-20 22:43:271365
Jeremy Roman0579ed62017-08-29 15:56:191366 InternalInsertCookie(key, std::make_unique<CanonicalCookie>(cookie), true);
rdsmith2709eee2017-06-20 22:43:271367 GarbageCollect(creation_time, key);
drogerd5d1278c2015-03-17 19:21:511368 }
1369
rdsmith2709eee2017-06-20 22:43:271370 // TODO(rdsmith): If this function always returns the same value, it
1371 // shouldn't have a return value. But it should also be deleted (see
1372 // https://codereview.chromium.org/2882063002/#msg64), which would
1373 // solve the return value problem.
rdsmithe5c701d2017-07-12 21:50:001374 MaybeRunCookieCallback(std::move(callback), true);
drogerd5d1278c2015-03-17 19:21:511375}
1376
[email protected]7a964a72010-09-07 19:33:261377void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc,
1378 const Time& current) {
mmenkebe0910d2016-03-01 19:09:091379 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041380
[email protected]77e0a462008-11-01 00:43:351381 // Based off the Mozilla code. When a cookie has been accessed recently,
1382 // don't bother updating its access time again. This reduces the number of
1383 // updates we do during pageload, which in turn reduces the chance our storage
1384 // backend will hit its batch thresholds and be forced to update.
[email protected]77e0a462008-11-01 00:43:351385 if ((current - cc->LastAccessDate()) < last_access_threshold_)
1386 return;
1387
1388 cc->SetLastAccessDate(current);
[email protected]90499482013-06-01 00:39:501389 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get())
[email protected]77e0a462008-11-01 00:43:351390 store_->UpdateCookieAccessTime(*cc);
1391}
1392
[email protected]6210ce52013-09-20 03:33:141393// InternalDeleteCookies must not invalidate iterators other than the one being
1394// deleted.
initial.commit586acc5fe2008-07-26 22:42:521395void CookieMonster::InternalDeleteCookie(CookieMap::iterator it,
[email protected]c4058fb2010-06-22 17:25:261396 bool sync_to_store,
1397 DeletionCause deletion_cause) {
mmenkebe0910d2016-03-01 19:09:091398 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041399
nharper352933e2016-09-30 18:24:571400 // Ideally, this would be asserted up where we define kChangeCauseMapping,
[email protected]8bb846f2011-03-23 12:08:181401 // but DeletionCause's visibility (or lack thereof) forces us to make
1402 // this check here.
Ryan Sleevi435a3a22018-05-15 02:16:071403 static_assert(base::size(kChangeCauseMapping) == DELETE_COOKIE_LAST_ENTRY + 1,
nharper352933e2016-09-30 18:24:571404 "kChangeCauseMapping size should match DeletionCause size");
[email protected]8bb846f2011-03-23 12:08:181405
avie7cd11a2016-10-11 02:00:351406 CanonicalCookie* cc = it->second.get();
Oscar Johansson63e83cf2018-07-02 08:47:261407 VLOG(net::cookie_util::kVlogSetCookies)
1408 << "InternalDeleteCookie()"
1409 << ", cause:" << deletion_cause << ", cc: " << cc->DebugString();
[email protected]7a964a72010-09-07 19:33:261410
Helen Licd0fab862018-08-13 16:07:531411 ChangeCausePair mapping = kChangeCauseMapping[deletion_cause];
1412 if (deletion_cause != DELETE_COOKIE_DONT_RECORD) {
1413 net_log_.AddEvent(NetLogEventType::COOKIE_STORE_COOKIE_DELETED,
1414 base::BindRepeating(&NetLogCookieMonsterCookieDeleted, cc,
1415 mapping.cause, sync_to_store));
1416 }
1417
[email protected]90499482013-06-01 00:39:501418 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get() &&
Helen Lid84010b2018-08-22 16:27:441419 sync_to_store) {
initial.commit586acc5fe2008-07-26 22:42:521420 store_->DeleteCookie(*cc);
Helen Lid84010b2018-08-22 16:27:441421 }
Victor Costan14f47c12018-03-01 08:02:241422 change_dispatcher_.DispatchChange(*cc, mapping.cause, mapping.notify);
initial.commit586acc5fe2008-07-26 22:42:521423 cookies_.erase(it);
initial.commit586acc5fe2008-07-26 22:42:521424}
1425
[email protected]8807b322010-10-01 17:10:141426// Domain expiry behavior is unchanged by key/expiry scheme (the
[email protected]8ad5d462013-05-02 08:45:261427// meaning of the key is different, but that's not visible to this routine).
jww82d99c12015-11-25 18:39:531428size_t CookieMonster::GarbageCollect(const Time& current,
jwwa26e439d2017-01-27 18:17:271429 const std::string& key) {
mmenkebe0910d2016-03-01 19:09:091430 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041431
jww82d99c12015-11-25 18:39:531432 size_t num_deleted = 0;
mkwstbe84af312015-02-20 08:52:451433 Time safe_date(Time::Now() - TimeDelta::FromDays(kSafeFromGlobalPurgeDays));
initial.commit586acc5fe2008-07-26 22:42:521434
[email protected]8ad5d462013-05-02 08:45:261435 // Collect garbage for this key, minding cookie priorities.
[email protected]7a964a72010-09-07 19:33:261436 if (cookies_.count(key) > kDomainMaxCookies) {
Oscar Johansson63e83cf2018-07-02 08:47:261437 VLOG(net::cookie_util::kVlogGarbageCollection)
1438 << "GarbageCollect() key: " << key;
[email protected]7a964a72010-09-07 19:33:261439
mkwst87734352016-03-03 17:36:231440 CookieItVector* cookie_its;
jww601411a2015-11-20 19:46:571441
mkwst87734352016-03-03 17:36:231442 CookieItVector non_expired_cookie_its;
1443 cookie_its = &non_expired_cookie_its;
jww82d99c12015-11-25 18:39:531444 num_deleted +=
mkwst87734352016-03-03 17:36:231445 GarbageCollectExpired(current, cookies_.equal_range(key), cookie_its);
jww82d99c12015-11-25 18:39:531446
mkwst87734352016-03-03 17:36:231447 if (cookie_its->size() > kDomainMaxCookies) {
Oscar Johansson63e83cf2018-07-02 08:47:261448 VLOG(net::cookie_util::kVlogGarbageCollection)
1449 << "Deep Garbage Collect domain.";
[email protected]8ad5d462013-05-02 08:45:261450 size_t purge_goal =
mkwst87734352016-03-03 17:36:231451 cookie_its->size() - (kDomainMaxCookies - kDomainPurgeCookies);
[email protected]8ad5d462013-05-02 08:45:261452 DCHECK(purge_goal > kDomainPurgeCookies);
1453
mkwste079ac412016-03-11 09:04:061454 // Sort the cookies by access date, from least-recent to most-recent.
1455 std::sort(cookie_its->begin(), cookie_its->end(), LRACookieSorter);
[email protected]8ad5d462013-05-02 08:45:261456
mkwste079ac412016-03-11 09:04:061457 // Remove all but the kDomainCookiesQuotaLow most-recently accessed
1458 // cookies with low-priority. Then, if cookies still need to be removed,
1459 // bump the quota and remove low- and medium-priority. Then, if cookies
1460 // _still_ need to be removed, bump the quota and remove cookies with
1461 // any priority.
jwwc00ac712016-05-05 22:21:441462 //
1463 // 1. Low-priority non-secure cookies.
1464 // 2. Low-priority secure cookies.
1465 // 3. Medium-priority non-secure cookies.
1466 // 4. High-priority non-secure cookies.
1467 // 5. Medium-priority secure cookies.
1468 // 6. High-priority secure cookies.
1469 const static struct {
1470 CookiePriority priority;
1471 bool protect_secure_cookies;
1472 } purge_rounds[] = {
1473 // 1. Low-priority non-secure cookies.
1474 {COOKIE_PRIORITY_LOW, true},
1475 // 2. Low-priority secure cookies.
1476 {COOKIE_PRIORITY_LOW, false},
1477 // 3. Medium-priority non-secure cookies.
1478 {COOKIE_PRIORITY_MEDIUM, true},
1479 // 4. High-priority non-secure cookies.
1480 {COOKIE_PRIORITY_HIGH, true},
1481 // 5. Medium-priority secure cookies.
1482 {COOKIE_PRIORITY_MEDIUM, false},
1483 // 6. High-priority secure cookies.
1484 {COOKIE_PRIORITY_HIGH, false},
1485 };
1486
mkwste079ac412016-03-11 09:04:061487 size_t quota = 0;
jwwc00ac712016-05-05 22:21:441488 for (const auto& purge_round : purge_rounds) {
mmenke645ca6772016-06-17 18:46:431489 // Adjust quota according to the priority of cookies. Each round should
1490 // protect certain number of cookies in order to avoid starvation.
1491 // For example, when each round starts to remove cookies, the number of
1492 // cookies of that priority are counted and a decision whether they
1493 // should be deleted or not is made. If yes, some number of cookies of
1494 // that priority are deleted considering the quota.
jwwc00ac712016-05-05 22:21:441495 switch (purge_round.priority) {
1496 case COOKIE_PRIORITY_LOW:
mmenke645ca6772016-06-17 18:46:431497 quota = kDomainCookiesQuotaLow;
jwwc00ac712016-05-05 22:21:441498 break;
1499 case COOKIE_PRIORITY_MEDIUM:
mmenke645ca6772016-06-17 18:46:431500 quota = kDomainCookiesQuotaMedium;
jwwc00ac712016-05-05 22:21:441501 break;
1502 case COOKIE_PRIORITY_HIGH:
mmenke645ca6772016-06-17 18:46:431503 quota = kDomainCookiesQuotaHigh;
jwwc00ac712016-05-05 22:21:441504 break;
1505 }
jwwc00ac712016-05-05 22:21:441506 size_t just_deleted = 0u;
jwwa26e439d2017-01-27 18:17:271507 // Purge up to |purge_goal| for all cookies at the given priority. This
1508 // path will be taken only if the initial non-secure purge did not evict
1509 // enough cookies.
jwwc00ac712016-05-05 22:21:441510 if (purge_goal > 0) {
1511 just_deleted = PurgeLeastRecentMatches(
1512 cookie_its, purge_round.priority, quota, purge_goal,
1513 purge_round.protect_secure_cookies);
1514 DCHECK_LE(just_deleted, purge_goal);
1515 purge_goal -= just_deleted;
1516 num_deleted += just_deleted;
1517 }
mkwst162d2712016-02-18 18:21:291518 }
mkwste079ac412016-03-11 09:04:061519
jwwc00ac712016-05-05 22:21:441520 DCHECK_EQ(0u, purge_goal);
[email protected]8807b322010-10-01 17:10:141521 }
initial.commit586acc5fe2008-07-26 22:42:521522 }
1523
[email protected]8ad5d462013-05-02 08:45:261524 // Collect garbage for everything. With firefox style we want to preserve
1525 // cookies accessed in kSafeFromGlobalPurgeDays, otherwise evict.
mkwstbe84af312015-02-20 08:52:451526 if (cookies_.size() > kMaxCookies && earliest_access_time_ < safe_date) {
Oscar Johansson63e83cf2018-07-02 08:47:261527 VLOG(net::cookie_util::kVlogGarbageCollection)
1528 << "GarbageCollect() everything";
[email protected]8ad5d462013-05-02 08:45:261529 CookieItVector cookie_its;
jww82d99c12015-11-25 18:39:531530
[email protected]7a964a72010-09-07 19:33:261531 num_deleted += GarbageCollectExpired(
1532 current, CookieMapItPair(cookies_.begin(), cookies_.end()),
1533 &cookie_its);
jww82d99c12015-11-25 18:39:531534
[email protected]8ad5d462013-05-02 08:45:261535 if (cookie_its.size() > kMaxCookies) {
Oscar Johansson63e83cf2018-07-02 08:47:261536 VLOG(net::cookie_util::kVlogGarbageCollection)
1537 << "Deep Garbage Collect everything.";
[email protected]8ad5d462013-05-02 08:45:261538 size_t purge_goal = cookie_its.size() - (kMaxCookies - kPurgeCookies);
1539 DCHECK(purge_goal > kPurgeCookies);
jww82d99c12015-11-25 18:39:531540
jwwa26e439d2017-01-27 18:17:271541 CookieItVector secure_cookie_its;
1542 CookieItVector non_secure_cookie_its;
1543 SplitCookieVectorIntoSecureAndNonSecure(cookie_its, &secure_cookie_its,
1544 &non_secure_cookie_its);
1545 size_t non_secure_purge_goal =
mmenkef4721d992017-06-07 17:13:591546 std::min<size_t>(purge_goal, non_secure_cookie_its.size());
jww82d99c12015-11-25 18:39:531547
mmenkef4721d992017-06-07 17:13:591548 base::Time earliest_non_secure_access_time;
jwwa26e439d2017-01-27 18:17:271549 size_t just_deleted = GarbageCollectLeastRecentlyAccessed(
mmenkef4721d992017-06-07 17:13:591550 current, safe_date, non_secure_purge_goal, non_secure_cookie_its,
1551 &earliest_non_secure_access_time);
jwwa26e439d2017-01-27 18:17:271552 num_deleted += just_deleted;
jww82d99c12015-11-25 18:39:531553
mmenkef4721d992017-06-07 17:13:591554 if (secure_cookie_its.size() == 0) {
1555 // This case is unlikely, but should still update
1556 // |earliest_access_time_| if only have non-secure cookies.
1557 earliest_access_time_ = earliest_non_secure_access_time;
1558 // Garbage collection can't delete all cookies.
1559 DCHECK(!earliest_access_time_.is_null());
1560 } else if (just_deleted < purge_goal) {
1561 size_t secure_purge_goal = std::min<size_t>(purge_goal - just_deleted,
1562 secure_cookie_its.size());
1563 base::Time earliest_secure_access_time;
jww82d99c12015-11-25 18:39:531564 num_deleted += GarbageCollectLeastRecentlyAccessed(
mmenkef4721d992017-06-07 17:13:591565 current, safe_date, secure_purge_goal, secure_cookie_its,
1566 &earliest_secure_access_time);
1567
1568 if (!earliest_non_secure_access_time.is_null() &&
1569 earliest_non_secure_access_time < earliest_secure_access_time) {
1570 earliest_access_time_ = earliest_non_secure_access_time;
1571 } else {
1572 earliest_access_time_ = earliest_secure_access_time;
1573 }
1574
1575 // Garbage collection can't delete all cookies.
1576 DCHECK(!earliest_access_time_.is_null());
jww82d99c12015-11-25 18:39:531577 }
mmenkef4721d992017-06-07 17:13:591578
1579 // If there are secure cookies, but deleting non-secure cookies was enough
1580 // to meet the purge goal, secure cookies are never examined, so
1581 // |earliest_access_time_| can't be determined. Leaving it alone will mean
1582 // it's no later than the real earliest last access time, so this won't
1583 // lead to any problems.
[email protected]8807b322010-10-01 17:10:141584 }
[email protected]c890ed192008-10-30 23:45:531585 }
1586
1587 return num_deleted;
1588}
1589
mkwste079ac412016-03-11 09:04:061590size_t CookieMonster::PurgeLeastRecentMatches(CookieItVector* cookies,
1591 CookiePriority priority,
1592 size_t to_protect,
jwwc00ac712016-05-05 22:21:441593 size_t purge_goal,
1594 bool protect_secure_cookies) {
mkwste079ac412016-03-11 09:04:061595 DCHECK(thread_checker_.CalledOnValidThread());
1596
mmenke645ca6772016-06-17 18:46:431597 // 1. Count number of the cookies at |priority|
1598 size_t cookies_count_possibly_to_be_deleted = CountCookiesForPossibleDeletion(
1599 priority, cookies, false /* count all cookies */);
1600
1601 // 2. If |cookies_count_possibly_to_be_deleted| at |priority| is less than or
1602 // equal |to_protect|, skip round in order to preserve the quota. This
1603 // involves secure and non-secure cookies at |priority|.
1604 if (cookies_count_possibly_to_be_deleted <= to_protect)
1605 return 0u;
1606
1607 // 3. Calculate number of secure cookies at |priority|
1608 // and number of cookies at |priority| that can possibly be deleted.
1609 // It is guaranteed we do not delete more than |purge_goal| even if
1610 // |cookies_count_possibly_to_be_deleted| is higher.
1611 size_t secure_cookies = 0u;
jwwc00ac712016-05-05 22:21:441612 if (protect_secure_cookies) {
mmenke645ca6772016-06-17 18:46:431613 secure_cookies = CountCookiesForPossibleDeletion(
1614 priority, cookies, protect_secure_cookies /* count secure cookies */);
1615 cookies_count_possibly_to_be_deleted -=
1616 std::max(secure_cookies, to_protect - secure_cookies);
1617 } else {
1618 cookies_count_possibly_to_be_deleted -= to_protect;
jwwc00ac712016-05-05 22:21:441619 }
1620
mmenke645ca6772016-06-17 18:46:431621 size_t removed = 0u;
1622 size_t current = 0u;
1623 while ((removed < purge_goal && current < cookies->size()) &&
1624 cookies_count_possibly_to_be_deleted > 0) {
avie7cd11a2016-10-11 02:00:351625 const CanonicalCookie* current_cookie = cookies->at(current)->second.get();
mmenke645ca6772016-06-17 18:46:431626 // Only delete the current cookie if the priority is equal to
1627 // the current level.
jwwc00ac712016-05-05 22:21:441628 if (IsCookieEligibleForEviction(priority, protect_secure_cookies,
1629 current_cookie)) {
mkwstaa07ee82016-03-11 15:32:141630 InternalDeleteCookie(cookies->at(current), true,
1631 DELETE_COOKIE_EVICTED_DOMAIN);
mkwste079ac412016-03-11 09:04:061632 cookies->erase(cookies->begin() + current);
1633 removed++;
mmenke645ca6772016-06-17 18:46:431634 cookies_count_possibly_to_be_deleted--;
mkwste079ac412016-03-11 09:04:061635 } else {
1636 current++;
1637 }
1638 }
1639 return removed;
1640}
1641
jww82d99c12015-11-25 18:39:531642size_t CookieMonster::GarbageCollectExpired(const Time& current,
1643 const CookieMapItPair& itpair,
1644 CookieItVector* cookie_its) {
mmenkebe0910d2016-03-01 19:09:091645 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041646
[email protected]c890ed192008-10-30 23:45:531647 int num_deleted = 0;
1648 for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) {
1649 CookieMap::iterator curit = it;
1650 ++it;
1651
1652 if (curit->second->IsExpired(current)) {
[email protected]2f3f3592010-07-07 20:11:511653 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
[email protected]c890ed192008-10-30 23:45:531654 ++num_deleted;
1655 } else if (cookie_its) {
1656 cookie_its->push_back(curit);
1657 }
initial.commit586acc5fe2008-07-26 22:42:521658 }
1659
1660 return num_deleted;
1661}
1662
jww82d99c12015-11-25 18:39:531663size_t CookieMonster::GarbageCollectDeleteRange(
1664 const Time& current,
1665 DeletionCause cause,
1666 CookieItVector::iterator it_begin,
1667 CookieItVector::iterator it_end) {
mmenkebe0910d2016-03-01 19:09:091668 DCHECK(thread_checker_.CalledOnValidThread());
1669
[email protected]8ad5d462013-05-02 08:45:261670 for (CookieItVector::iterator it = it_begin; it != it_end; it++) {
[email protected]8ad5d462013-05-02 08:45:261671 InternalDeleteCookie((*it), true, cause);
[email protected]c10da4b02010-03-25 14:38:321672 }
[email protected]8ad5d462013-05-02 08:45:261673 return it_end - it_begin;
[email protected]c10da4b02010-03-25 14:38:321674}
1675
mmenke74bcbd52016-01-21 17:17:561676size_t CookieMonster::GarbageCollectLeastRecentlyAccessed(
1677 const base::Time& current,
1678 const base::Time& safe_date,
1679 size_t purge_goal,
mmenkef4721d992017-06-07 17:13:591680 CookieItVector cookie_its,
1681 base::Time* earliest_time) {
1682 DCHECK_LE(purge_goal, cookie_its.size());
mmenkebe0910d2016-03-01 19:09:091683 DCHECK(thread_checker_.CalledOnValidThread());
1684
mmenkef4721d992017-06-07 17:13:591685 // Sorts up to *and including* |cookie_its[purge_goal]| (if it exists), so
1686 // |earliest_time| will be properly assigned even if
mmenke74bcbd52016-01-21 17:17:561687 // |global_purge_it| == |cookie_its.begin() + purge_goal|.
mmenkef4721d992017-06-07 17:13:591688 SortLeastRecentlyAccessed(
1689 cookie_its.begin(), cookie_its.end(),
1690 cookie_its.size() < purge_goal ? purge_goal + 1 : purge_goal);
mmenke74bcbd52016-01-21 17:17:561691 // Find boundary to cookies older than safe_date.
1692 CookieItVector::iterator global_purge_it = LowerBoundAccessDate(
1693 cookie_its.begin(), cookie_its.begin() + purge_goal, safe_date);
jwwa26e439d2017-01-27 18:17:271694 // Only delete the old cookies and delete non-secure ones first.
mmenke74bcbd52016-01-21 17:17:561695 size_t num_deleted =
1696 GarbageCollectDeleteRange(current, DELETE_COOKIE_EVICTED_GLOBAL,
1697 cookie_its.begin(), global_purge_it);
mmenkef4721d992017-06-07 17:13:591698 if (global_purge_it != cookie_its.end())
1699 *earliest_time = (*global_purge_it)->second->LastAccessDate();
mmenke74bcbd52016-01-21 17:17:561700 return num_deleted;
1701}
1702
[email protected]ed32c212013-05-14 20:49:291703// A wrapper around registry_controlled_domains::GetDomainAndRegistry
Maks Orlovich323efaf2018-03-06 02:56:391704// to make clear we're creating a key for our local map or for the persistent
1705// store's use. Here and in FindCookiesForHostAndDomain() are the only two
1706// places where we need to conditionalize based on key type.
[email protected]f48b9432011-01-11 07:25:401707//
1708// Note that this key algorithm explicitly ignores the scheme. This is
1709// because when we're entering cookies into the map from the backing store,
1710// we in general won't have the scheme at that point.
1711// In practical terms, this means that file cookies will be stored
1712// in the map either by an empty string or by UNC name (and will be
1713// limited by kMaxCookiesPerHost), and extension cookies will be stored
1714// based on the single extension id, as the extension id won't have the
1715// form of a DNS host and hence GetKey() will return it unchanged.
1716//
1717// Arguably the right thing to do here is to make the key
1718// algorithm dependent on the scheme, and make sure that the scheme is
1719// available everywhere the key must be obtained (specfically at backing
1720// store load time). This would require either changing the backing store
1721// database schema to include the scheme (far more trouble than it's worth), or
1722// separating out file cookies into their own CookieMonster instance and
1723// thus restricting each scheme to a single cookie monster (which might
1724// be worth it, but is still too much trouble to solve what is currently a
1725// non-problem).
Maks Orlovich323efaf2018-03-06 02:56:391726//
1727// static
1728std::string CookieMonster::GetKey(base::StringPiece domain) {
[email protected]f48b9432011-01-11 07:25:401729 std::string effective_domain(
[email protected]ed32c212013-05-14 20:49:291730 registry_controlled_domains::GetDomainAndRegistry(
[email protected]aabe1792014-01-30 21:37:461731 domain, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES));
[email protected]f48b9432011-01-11 07:25:401732 if (effective_domain.empty())
Maks Orlovich323efaf2018-03-06 02:56:391733 domain.CopyToString(&effective_domain);
[email protected]f48b9432011-01-11 07:25:401734
1735 if (!effective_domain.empty() && effective_domain[0] == '.')
1736 return effective_domain.substr(1);
1737 return effective_domain;
1738}
1739
1740bool CookieMonster::HasCookieableScheme(const GURL& url) {
mmenkebe0910d2016-03-01 19:09:091741 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401742
1743 // Make sure the request is on a cookie-able url scheme.
1744 for (size_t i = 0; i < cookieable_schemes_.size(); ++i) {
1745 // We matched a scheme.
1746 if (url.SchemeIs(cookieable_schemes_[i].c_str())) {
1747 // We've matched a supported scheme.
initial.commit586acc5fe2008-07-26 22:42:521748 return true;
1749 }
1750 }
[email protected]f48b9432011-01-11 07:25:401751
1752 // The scheme didn't match any in our whitelist.
Oscar Johansson63e83cf2018-07-02 08:47:261753 VLOG(net::cookie_util::kVlogPerCookieMonster)
mkwstbe84af312015-02-20 08:52:451754 << "WARNING: Unsupported cookie scheme: " << url.scheme();
initial.commit586acc5fe2008-07-26 22:42:521755 return false;
1756}
1757
[email protected]c4058fb2010-06-22 17:25:261758// Test to see if stats should be recorded, and record them if so.
1759// The goal here is to get sampling for the average browser-hour of
1760// activity. We won't take samples when the web isn't being surfed,
1761// and when the web is being surfed, we'll take samples about every
1762// kRecordStatisticsIntervalSeconds.
1763// last_statistic_record_time_ is initialized to Now() rather than null
1764// in the constructor so that we won't take statistics right after
1765// startup, to avoid bias from browsers that are started but not used.
1766void CookieMonster::RecordPeriodicStats(const base::Time& current_time) {
mmenkebe0910d2016-03-01 19:09:091767 DCHECK(thread_checker_.CalledOnValidThread());
1768
[email protected]c4058fb2010-06-22 17:25:261769 const base::TimeDelta kRecordStatisticsIntervalTime(
1770 base::TimeDelta::FromSeconds(kRecordStatisticsIntervalSeconds));
1771
[email protected]7a964a72010-09-07 19:33:261772 // If we've taken statistics recently, return.
1773 if (current_time - last_statistic_record_time_ <=
[email protected]c4058fb2010-06-22 17:25:261774 kRecordStatisticsIntervalTime) {
[email protected]7a964a72010-09-07 19:33:261775 return;
[email protected]c4058fb2010-06-22 17:25:261776 }
[email protected]7a964a72010-09-07 19:33:261777
1778 // See InitializeHistograms() for details.
1779 histogram_count_->Add(cookies_.size());
1780
1781 // More detailed statistics on cookie counts at different granularities.
[email protected]7a964a72010-09-07 19:33:261782 last_statistic_record_time_ = current_time;
[email protected]c4058fb2010-06-22 17:25:261783}
1784
[email protected]f48b9432011-01-11 07:25:401785// Initialize all histogram counter variables used in this class.
1786//
1787// Normal histogram usage involves using the macros defined in
1788// histogram.h, which automatically takes care of declaring these
1789// variables (as statics), initializing them, and accumulating into
1790// them, all from a single entry point. Unfortunately, that solution
1791// doesn't work for the CookieMonster, as it's vulnerable to races between
1792// separate threads executing the same functions and hence initializing the
1793// same static variables. There isn't a race danger in the histogram
1794// accumulation calls; they are written to be resilient to simultaneous
1795// calls from multiple threads.
1796//
1797// The solution taken here is to have per-CookieMonster instance
1798// variables that are constructed during CookieMonster construction.
1799// Note that these variables refer to the same underlying histogram,
1800// so we still race (but safely) with other CookieMonster instances
1801// for accumulation.
1802//
1803// To do this we've expanded out the individual histogram macros calls,
1804// with declarations of the variables in the class decl, initialization here
1805// (done from the class constructor) and direct calls to the accumulation
1806// methods where needed. The specific histogram macro calls on which the
1807// initialization is based are included in comments below.
1808void CookieMonster::InitializeHistograms() {
mmenkebe0910d2016-03-01 19:09:091809 DCHECK(thread_checker_.CalledOnValidThread());
1810
[email protected]f48b9432011-01-11 07:25:401811 // From UMA_HISTOGRAM_CUSTOM_COUNTS
1812 histogram_expiration_duration_minutes_ = base::Histogram::FactoryGet(
mkwstbe84af312015-02-20 08:52:451813 "Cookie.ExpirationDurationMinutes", 1, kMinutesInTenYears, 50,
[email protected]f48b9432011-01-11 07:25:401814 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401815 histogram_count_ = base::Histogram::FactoryGet(
mkwstbe84af312015-02-20 08:52:451816 "Cookie.Count", 1, 4000, 50, base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401817
1818 // From UMA_HISTOGRAM_ENUMERATION
mkwstc1aa4cc2015-04-03 19:57:451819 histogram_cookie_type_ = base::LinearHistogram::FactoryGet(
mkwst87378d92015-04-10 21:22:111820 "Cookie.Type", 1, (1 << COOKIE_TYPE_LAST_ENTRY) - 1,
1821 1 << COOKIE_TYPE_LAST_ENTRY, base::Histogram::kUmaTargetedHistogramFlag);
estark7feb65c2b2015-08-21 23:38:201822 histogram_cookie_source_scheme_ = base::LinearHistogram::FactoryGet(
1823 "Cookie.CookieSourceScheme", 1, COOKIE_SOURCE_LAST_ENTRY - 1,
1824 COOKIE_SOURCE_LAST_ENTRY, base::Histogram::kUmaTargetedHistogramFlag);
jww31e32632015-12-16 23:38:341825 histogram_cookie_delete_equivalent_ = base::LinearHistogram::FactoryGet(
1826 "Cookie.CookieDeleteEquivalent", 1,
1827 COOKIE_DELETE_EQUIVALENT_LAST_ENTRY - 1,
1828 COOKIE_DELETE_EQUIVALENT_LAST_ENTRY,
1829 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401830
1831 // From UMA_HISTOGRAM_{CUSTOM_,}TIMES
[email protected]c7593fb22011-11-14 23:54:271832 histogram_time_blocked_on_load_ = base::Histogram::FactoryTimeGet(
mkwstbe84af312015-02-20 08:52:451833 "Cookie.TimeBlockedOnLoad", base::TimeDelta::FromMilliseconds(1),
1834 base::TimeDelta::FromMinutes(1), 50,
1835 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401836}
1837
[email protected]f48b9432011-01-11 07:25:401838// The system resolution is not high enough, so we can have multiple
1839// set cookies that result in the same system time. When this happens, we
1840// increment by one Time unit. Let's hope computers don't get too fast.
1841Time CookieMonster::CurrentTime() {
mkwstbe84af312015-02-20 08:52:451842 return std::max(Time::Now(), Time::FromInternalValue(
1843 last_time_seen_.ToInternalValue() + 1));
[email protected]f48b9432011-01-11 07:25:401844}
1845
rdsmithe5c701d2017-07-12 21:50:001846void CookieMonster::DoCookieCallback(base::OnceClosure callback) {
mmenkebe0910d2016-03-01 19:09:091847 DCHECK(thread_checker_.CalledOnValidThread());
1848
1849 MarkCookieStoreAsInitialized();
1850 FetchAllCookiesIfNecessary();
mmenkef49fca0e2016-03-08 12:46:241851 seen_global_task_ = true;
mmenkebe0910d2016-03-01 19:09:091852
1853 if (!finished_fetching_all_cookies_ && store_.get()) {
rdsmithe5c701d2017-07-12 21:50:001854 tasks_pending_.push_back(std::move(callback));
mmenkebe0910d2016-03-01 19:09:091855 return;
mmenke74bcbd52016-01-21 17:17:561856 }
1857
rdsmithe5c701d2017-07-12 21:50:001858 std::move(callback).Run();
mmenke74bcbd52016-01-21 17:17:561859}
1860
rdsmithe5c701d2017-07-12 21:50:001861void CookieMonster::DoCookieCallbackForURL(base::OnceClosure callback,
1862 const GURL& url) {
Maks Orlovich323efaf2018-03-06 02:56:391863 DoCookieCallbackForHostOrDomain(std::move(callback), url.host_piece());
1864}
1865
1866void CookieMonster::DoCookieCallbackForHostOrDomain(
1867 base::OnceClosure callback,
1868 base::StringPiece host_or_domain) {
mmenkebe0910d2016-03-01 19:09:091869 MarkCookieStoreAsInitialized();
erikchende4c39e2018-01-29 21:33:361870 FetchAllCookiesIfNecessary();
mmenkebe0910d2016-03-01 19:09:091871
1872 // If cookies for the requested domain key (eTLD+1) have been loaded from DB
1873 // then run the task, otherwise load from DB.
1874 if (!finished_fetching_all_cookies_ && store_.get()) {
mmenkef49fca0e2016-03-08 12:46:241875 // If a global task has been previously seen, queue the task as a global
1876 // task. Note that the CookieMonster may be in the middle of executing
1877 // the global queue, |tasks_pending_| may be empty, which is why another
1878 // bool is needed.
1879 if (seen_global_task_) {
rdsmithe5c701d2017-07-12 21:50:001880 tasks_pending_.push_back(std::move(callback));
mmenkef49fca0e2016-03-08 12:46:241881 return;
1882 }
1883
mmenkebe0910d2016-03-01 19:09:091884 // Checks if the domain key has been loaded.
Maks Orlovich323efaf2018-03-06 02:56:391885 std::string key = GetKey(host_or_domain);
mmenkebe0910d2016-03-01 19:09:091886 if (keys_loaded_.find(key) == keys_loaded_.end()) {
Brett Wilsonc6a0c822017-09-12 00:04:291887 std::map<std::string, base::circular_deque<base::OnceClosure>>::iterator
1888 it = tasks_pending_for_key_.find(key);
mmenkebe0910d2016-03-01 19:09:091889 if (it == tasks_pending_for_key_.end()) {
1890 store_->LoadCookiesForKey(
1891 key, base::Bind(&CookieMonster::OnKeyLoaded,
1892 weak_ptr_factory_.GetWeakPtr(), key));
1893 it = tasks_pending_for_key_
Brett Wilsonc6a0c822017-09-12 00:04:291894 .insert(std::make_pair(
1895 key, base::circular_deque<base::OnceClosure>()))
mmenkebe0910d2016-03-01 19:09:091896 .first;
mmenke74bcbd52016-01-21 17:17:561897 }
rdsmithe5c701d2017-07-12 21:50:001898 it->second.push_back(std::move(callback));
mmenkebe0910d2016-03-01 19:09:091899 return;
mmenke74bcbd52016-01-21 17:17:561900 }
1901 }
mmenkebe0910d2016-03-01 19:09:091902
rdsmithe5c701d2017-07-12 21:50:001903 std::move(callback).Run();
mmenke74bcbd52016-01-21 17:17:561904}
1905
[email protected]63725312012-07-19 08:24:161906} // namespace net