blob: e7ad8df8817e338436f20af7fec93148c39fd0ff [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"
skyostil4891b25b2015-06-11 11:43:4552#include "base/location.h"
initial.commit586acc5fe2008-07-26 22:42:5253#include "base/logging.h"
Avi Drissman13fc8932015-12-20 04:40:4654#include "base/macros.h"
erikchen1dd72a72015-05-06 20:45:0555#include "base/metrics/field_trial.h"
[email protected]835d7c82010-10-14 04:38:3856#include "base/metrics/histogram.h"
Ken Rockotc2048612018-03-29 01:43:3257#include "base/metrics/histogram_macros.h"
anujk.sharmaafc45172015-05-15 00:50:3458#include "base/single_thread_task_runner.h"
tripta.gdda72022017-06-19 05:16:2359#include "base/stl_util.h"
Maks Orlovich323efaf2018-03-06 02:56:3960#include "base/strings/string_piece.h"
[email protected]4b355212013-06-11 10:35:1961#include "base/strings/string_util.h"
62#include "base/strings/stringprintf.h"
gabf767595f2016-05-11 18:50:3563#include "base/threading/thread_task_runner_handle.h"
Maks Orlovich5cf437b02018-03-27 04:40:4264#include "base/trace_event/process_memory_dump.h"
[email protected]be28b5f42012-07-20 11:31:2565#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
[email protected]4b355212013-06-11 10:35:1966#include "net/cookies/canonical_cookie.h"
Victor Costan14f47c12018-03-01 08:02:2467#include "net/cookies/cookie_monster_change_dispatcher.h"
Helen Licd0fab862018-08-13 16:07:5368#include "net/cookies/cookie_monster_netlog_params.h"
[email protected]63ee33bd2012-03-15 09:29:5869#include "net/cookies/cookie_util.h"
[email protected]ebfe3172012-07-12 12:21:4170#include "net/cookies/parsed_cookie.h"
Helen Licd0fab862018-08-13 16:07:5371#include "net/log/net_log.h"
mkwst8241a122015-10-20 07:15:1072#include "url/origin.h"
initial.commit586acc5fe2008-07-26 22:42:5273
[email protected]e1acf6f2008-10-27 20:43:3374using base::Time;
75using base::TimeDelta;
[email protected]7a964a72010-09-07 19:33:2676using base::TimeTicks;
Chris Mumfordd8ed9f82018-05-01 15:43:1377using TimeRange = net::CookieDeletionInfo::TimeRange;
[email protected]e1acf6f2008-10-27 20:43:3378
[email protected]85620342011-10-17 17:35:0479// In steady state, most cookie requests can be satisfied by the in memory
erikchen1dd72a72015-05-06 20:45:0580// cookie monster store. If the cookie request cannot be satisfied by the in
81// memory store, the relevant cookies must be fetched from the persistent
82// store. The task is queued in CookieMonster::tasks_pending_ if it requires
83// all cookies to be loaded from the backend, or tasks_pending_for_key_ if it
84// only requires all cookies associated with an eTLD+1.
[email protected]85620342011-10-17 17:35:0485//
86// On the browser critical paths (e.g. for loading initial web pages in a
87// session restore) it may take too long to wait for the full load. If a cookie
rdsmithe5c701d2017-07-12 21:50:0088// request is for a specific URL, DoCookieCallbackForURL is called, which
89// triggers a priority load if the key is not loaded yet by calling
90// PersistentCookieStore::LoadCookiesForKey. The request is queued in
[email protected]0184df32013-05-14 00:53:5591// CookieMonster::tasks_pending_for_key_ and executed upon receiving
92// notification of key load completion via CookieMonster::OnKeyLoaded(). If
93// multiple requests for the same eTLD+1 are received before key load
94// completion, only the first request calls
[email protected]85620342011-10-17 17:35:0495// PersistentCookieStore::LoadCookiesForKey, all subsequent requests are queued
[email protected]0184df32013-05-14 00:53:5596// in CookieMonster::tasks_pending_for_key_ and executed upon receiving
97// notification of key load completion triggered by the first request for the
98// same eTLD+1.
[email protected]85620342011-10-17 17:35:0499
[email protected]c4058fb2010-06-22 17:25:26100static const int kMinutesInTenYears = 10 * 365 * 24 * 60;
101
erikchen1dd72a72015-05-06 20:45:05102namespace {
103
Maks Orlovichf97d1b92018-03-06 17:25:39104void MaybeRunDeleteCallback(base::WeakPtr<net::CookieMonster> cookie_monster,
105 base::OnceClosure callback) {
rdsmithe5c701d2017-07-12 21:50:00106 if (cookie_monster && callback)
107 std::move(callback).Run();
108}
109
rdsmithe5c701d2017-07-12 21:50:00110template <typename T>
111void MaybeRunCookieCallback(base::OnceCallback<void(const T&)> callback,
112 const T& result) {
113 if (callback)
114 std::move(callback).Run(result);
115}
116
Aaron Tagliaboschia4c64b52019-01-25 03:28:49117template <typename T, typename U>
118void MaybeRunCookieCallback(
119 base::OnceCallback<void(const T&, const U&)> callback,
120 const T& first,
121 const U& second) {
122 if (callback)
123 std::move(callback).Run(first, second);
124}
125
rdsmithe5c701d2017-07-12 21:50:00126template <typename T>
127void MaybeRunCookieCallback(base::OnceCallback<void(T)> callback,
128 const T& result) {
129 if (callback)
130 std::move(callback).Run(result);
131}
132
erikchen1dd72a72015-05-06 20:45:05133} // namespace
134
[email protected]8ac1a752008-07-31 19:40:37135namespace net {
136
[email protected]7a964a72010-09-07 19:33:26137// See comments at declaration of these variables in cookie_monster.h
138// for details.
mkwstbe84af312015-02-20 08:52:45139const size_t CookieMonster::kDomainMaxCookies = 180;
140const size_t CookieMonster::kDomainPurgeCookies = 30;
141const size_t CookieMonster::kMaxCookies = 3300;
142const size_t CookieMonster::kPurgeCookies = 300;
[email protected]8ad5d462013-05-02 08:45:26143
mkwst87734352016-03-03 17:36:23144const size_t CookieMonster::kDomainCookiesQuotaLow = 30;
145const size_t CookieMonster::kDomainCookiesQuotaMedium = 50;
146const size_t CookieMonster::kDomainCookiesQuotaHigh =
147 kDomainMaxCookies - kDomainPurgeCookies - kDomainCookiesQuotaLow -
148 kDomainCookiesQuotaMedium;
[email protected]8ad5d462013-05-02 08:45:26149
mkwstbe84af312015-02-20 08:52:45150const int CookieMonster::kSafeFromGlobalPurgeDays = 30;
[email protected]297a4ed02010-02-12 08:12:52151
[email protected]7a964a72010-09-07 19:33:26152namespace {
[email protected]e32306c52008-11-06 16:59:05153
[email protected]6210ce52013-09-20 03:33:14154bool ContainsControlCharacter(const std::string& s) {
155 for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
156 if ((*i >= 0) && (*i <= 31))
157 return true;
158 }
159
160 return false;
161}
162
[email protected]5b9bc352012-07-18 13:13:34163typedef std::vector<CanonicalCookie*> CanonicalCookieVector;
[email protected]34a160d2011-05-12 22:12:49164
[email protected]77e0a462008-11-01 00:43:35165// Default minimum delay after updating a cookie's LastAccessDate before we
166// will update it again.
[email protected]297a4ed02010-02-12 08:12:52167const int kDefaultAccessUpdateThresholdSeconds = 60;
168
169// Comparator to sort cookies from highest creation date to lowest
170// creation date.
171struct OrderByCreationTimeDesc {
172 bool operator()(const CookieMonster::CookieMap::iterator& a,
173 const CookieMonster::CookieMap::iterator& b) const {
174 return a->second->CreationDate() > b->second->CreationDate();
175 }
176};
177
[email protected]f48b9432011-01-11 07:25:40178// Mozilla sorts on the path length (longest first), and then it
179// sorts by creation time (oldest first).
180// The RFC says the sort order for the domain attribute is undefined.
[email protected]5b9bc352012-07-18 13:13:34181bool CookieSorter(CanonicalCookie* cc1, CanonicalCookie* cc2) {
[email protected]f48b9432011-01-11 07:25:40182 if (cc1->Path().length() == cc2->Path().length())
183 return cc1->CreationDate() < cc2->CreationDate();
184 return cc1->Path().length() > cc2->Path().length();
initial.commit586acc5fe2008-07-26 22:42:52185}
186
[email protected]8ad5d462013-05-02 08:45:26187bool LRACookieSorter(const CookieMonster::CookieMap::iterator& it1,
[email protected]f48b9432011-01-11 07:25:40188 const CookieMonster::CookieMap::iterator& it2) {
[email protected]f48b9432011-01-11 07:25:40189 if (it1->second->LastAccessDate() != it2->second->LastAccessDate())
190 return it1->second->LastAccessDate() < it2->second->LastAccessDate();
initial.commit586acc5fe2008-07-26 22:42:52191
mkwste079ac412016-03-11 09:04:06192 // Ensure stability for == last access times by falling back to creation.
[email protected]f48b9432011-01-11 07:25:40193 return it1->second->CreationDate() < it2->second->CreationDate();
[email protected]297a4ed02010-02-12 08:12:52194}
195
196// Our strategy to find duplicates is:
197// (1) Build a map from (cookiename, cookiepath) to
198// {list of cookies with this signature, sorted by creation time}.
199// (2) For each list with more than 1 entry, keep the cookie having the
200// most recent creation time, and delete the others.
[email protected]f48b9432011-01-11 07:25:40201//
[email protected]1655ba342010-07-14 18:17:42202// Two cookies are considered equivalent if they have the same domain,
203// name, and path.
204struct CookieSignature {
205 public:
[email protected]dedec0b2013-02-28 04:50:10206 CookieSignature(const std::string& name,
207 const std::string& domain,
[email protected]1655ba342010-07-14 18:17:42208 const std::string& path)
mkwstbe84af312015-02-20 08:52:45209 : name(name), domain(domain), path(path) {}
[email protected]1655ba342010-07-14 18:17:42210
211 // To be a key for a map this class needs to be assignable, copyable,
212 // and have an operator<. The default assignment operator
213 // and copy constructor are exactly what we want.
214
215 bool operator<(const CookieSignature& cs) const {
216 // Name compare dominates, then domain, then path.
217 int diff = name.compare(cs.name);
218 if (diff != 0)
219 return diff < 0;
220
221 diff = domain.compare(cs.domain);
222 if (diff != 0)
223 return diff < 0;
224
225 return path.compare(cs.path) < 0;
226 }
227
228 std::string name;
229 std::string domain;
230 std::string path;
231};
[email protected]f48b9432011-01-11 07:25:40232
[email protected]8ad5d462013-05-02 08:45:26233// For a CookieItVector iterator range [|it_begin|, |it_end|),
mmenkef4721d992017-06-07 17:13:59234// sorts the first |num_sort| elements by LastAccessDate().
mkwstbe84af312015-02-20 08:52:45235void SortLeastRecentlyAccessed(CookieMonster::CookieItVector::iterator it_begin,
236 CookieMonster::CookieItVector::iterator it_end,
237 size_t num_sort) {
mmenkef4721d992017-06-07 17:13:59238 DCHECK_LE(static_cast<int>(num_sort), it_end - it_begin);
239 std::partial_sort(it_begin, it_begin + num_sort, it_end, LRACookieSorter);
[email protected]8ad5d462013-05-02 08:45:26240}
[email protected]f48b9432011-01-11 07:25:40241
jww82d99c12015-11-25 18:39:53242// Given a single cookie vector |cookie_its|, pushs all of the secure cookies in
243// |cookie_its| into |secure_cookie_its| and all of the non-secure cookies into
244// |non_secure_cookie_its|. Both |secure_cookie_its| and |non_secure_cookie_its|
245// must be non-NULL.
246void SplitCookieVectorIntoSecureAndNonSecure(
247 const CookieMonster::CookieItVector& cookie_its,
248 CookieMonster::CookieItVector* secure_cookie_its,
249 CookieMonster::CookieItVector* non_secure_cookie_its) {
250 DCHECK(secure_cookie_its && non_secure_cookie_its);
251 for (const auto& curit : cookie_its) {
252 if (curit->second->IsSecure())
253 secure_cookie_its->push_back(curit);
254 else
255 non_secure_cookie_its->push_back(curit);
256 }
257}
258
mkwstbe84af312015-02-20 08:52:45259bool LowerBoundAccessDateComparator(const CookieMonster::CookieMap::iterator it,
260 const Time& access_date) {
[email protected]8ad5d462013-05-02 08:45:26261 return it->second->LastAccessDate() < access_date;
262}
263
264// For a CookieItVector iterator range [|it_begin|, |it_end|)
265// from a CookieItVector sorted by LastAccessDate(), returns the
266// first iterator with access date >= |access_date|, or cookie_its_end if this
267// holds for all.
268CookieMonster::CookieItVector::iterator LowerBoundAccessDate(
269 const CookieMonster::CookieItVector::iterator its_begin,
270 const CookieMonster::CookieItVector::iterator its_end,
271 const Time& access_date) {
272 return std::lower_bound(its_begin, its_end, access_date,
273 LowerBoundAccessDateComparator);
[email protected]7a964a72010-09-07 19:33:26274}
275
Victor Costan14f47c12018-03-01 08:02:24276// Mapping between DeletionCause and CookieChangeCause; the
[email protected]7c4b66b2014-01-04 12:28:13277// mapping also provides a boolean that specifies whether or not an
Victor Costan14f47c12018-03-01 08:02:24278// OnCookieChange notification ought to be generated.
[email protected]8bb846f2011-03-23 12:08:18279typedef struct ChangeCausePair_struct {
Victor Costan14f47c12018-03-01 08:02:24280 CookieChangeCause cause;
[email protected]8bb846f2011-03-23 12:08:18281 bool notify;
282} ChangeCausePair;
nharper352933e2016-09-30 18:24:57283const ChangeCausePair kChangeCauseMapping[] = {
mkwstbe84af312015-02-20 08:52:45284 // DELETE_COOKIE_EXPLICIT
Victor Costan14f47c12018-03-01 08:02:24285 {CookieChangeCause::EXPLICIT, true},
mkwstbe84af312015-02-20 08:52:45286 // DELETE_COOKIE_OVERWRITE
Victor Costan14f47c12018-03-01 08:02:24287 {CookieChangeCause::OVERWRITE, true},
mkwstbe84af312015-02-20 08:52:45288 // DELETE_COOKIE_EXPIRED
Victor Costan14f47c12018-03-01 08:02:24289 {CookieChangeCause::EXPIRED, true},
mkwstbe84af312015-02-20 08:52:45290 // DELETE_COOKIE_EVICTED
Victor Costan14f47c12018-03-01 08:02:24291 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45292 // DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE
Victor Costan14f47c12018-03-01 08:02:24293 {CookieChangeCause::EXPLICIT, false},
mkwstbe84af312015-02-20 08:52:45294 // DELETE_COOKIE_DONT_RECORD
Victor Costan14f47c12018-03-01 08:02:24295 {CookieChangeCause::EXPLICIT, false},
mkwstbe84af312015-02-20 08:52:45296 // DELETE_COOKIE_EVICTED_DOMAIN
Victor Costan14f47c12018-03-01 08:02:24297 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45298 // DELETE_COOKIE_EVICTED_GLOBAL
Victor Costan14f47c12018-03-01 08:02:24299 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45300 // DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE
Victor Costan14f47c12018-03-01 08:02:24301 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45302 // DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE
Victor Costan14f47c12018-03-01 08:02:24303 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45304 // DELETE_COOKIE_EXPIRED_OVERWRITE
Victor Costan14f47c12018-03-01 08:02:24305 {CookieChangeCause::EXPIRED_OVERWRITE, true},
mkwstbe84af312015-02-20 08:52:45306 // DELETE_COOKIE_CONTROL_CHAR
Victor Costan14f47c12018-03-01 08:02:24307 {CookieChangeCause::EVICTED, true},
jww82d99c12015-11-25 18:39:53308 // DELETE_COOKIE_NON_SECURE
Victor Costan14f47c12018-03-01 08:02:24309 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45310 // DELETE_COOKIE_LAST_ENTRY
Victor Costan14f47c12018-03-01 08:02:24311 {CookieChangeCause::EXPLICIT, false}};
ellyjones399e35a22014-10-27 11:09:56312
jwwc00ac712016-05-05 22:21:44313bool IsCookieEligibleForEviction(CookiePriority current_priority_level,
314 bool protect_secure_cookies,
315 const CanonicalCookie* cookie) {
mmenke645ca6772016-06-17 18:46:43316 if (cookie->Priority() == current_priority_level && protect_secure_cookies)
317 return !cookie->IsSecure();
jwwc00ac712016-05-05 22:21:44318
mmenke645ca6772016-06-17 18:46:43319 return cookie->Priority() == current_priority_level;
320}
jwwc00ac712016-05-05 22:21:44321
mmenke645ca6772016-06-17 18:46:43322size_t CountCookiesForPossibleDeletion(
323 CookiePriority priority,
324 const CookieMonster::CookieItVector* cookies,
325 bool protect_secure_cookies) {
326 size_t cookies_count = 0U;
327 for (const auto& cookie : *cookies) {
328 if (cookie->second->Priority() == priority) {
329 if (!protect_secure_cookies || cookie->second->IsSecure())
330 cookies_count++;
331 }
332 }
333 return cookies_count;
jwwc00ac712016-05-05 22:21:44334}
335
[email protected]f48b9432011-01-11 07:25:40336} // namespace
337
Pritam8354cf702018-03-10 08:55:41338CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
Helen Lifb313a92018-08-14 15:46:44339 NetLog* net_log)
Randy Smithb78e0922018-03-01 21:19:54340 : CookieMonster(
Pritam8354cf702018-03-10 08:55:41341 std::move(store),
Helen Lifb313a92018-08-14 15:46:44342 base::TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds),
343 net_log) {}
Randy Smithb78e0922018-03-01 21:19:54344
Pritam8354cf702018-03-10 08:55:41345CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
Helen Lifb313a92018-08-14 15:46:44346 base::TimeDelta last_access_threshold,
347 NetLog* net_log)
[email protected]f48b9432011-01-11 07:25:40348 : initialized_(false),
erikchen1dd72a72015-05-06 20:45:05349 started_fetching_all_cookies_(false),
350 finished_fetching_all_cookies_(false),
mmenkef49fca0e2016-03-08 12:46:24351 seen_global_task_(false),
Helen Lifb313a92018-08-14 15:46:44352 net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::COOKIE_STORE)),
Pritam8354cf702018-03-10 08:55:41353 store_(std::move(store)),
shessf0bc1182016-05-19 04:35:58354 last_access_threshold_(last_access_threshold),
[email protected]82388662011-03-10 21:04:06355 last_statistic_record_time_(base::Time::Now()),
mmenkebe0910d2016-03-01 19:09:09356 persist_session_cookies_(false),
357 weak_ptr_factory_(this) {
[email protected]f48b9432011-01-11 07:25:40358 InitializeHistograms();
mmenke18dd8ba2016-02-01 18:42:10359 cookieable_schemes_.insert(
360 cookieable_schemes_.begin(), kDefaultCookieableSchemes,
361 kDefaultCookieableSchemes + kDefaultCookieableSchemesCount);
Helen Licd0fab862018-08-13 16:07:53362 net_log_.BeginEvent(
363 NetLogEventType::COOKIE_STORE_ALIVE,
364 base::BindRepeating(&NetLogCookieMonsterConstructorCallback,
Nick Harper57142b1c2019-03-14 21:03:59365 store != nullptr));
initial.commit586acc5fe2008-07-26 22:42:52366}
367
[email protected]218aa6a12011-09-13 17:38:38368// Asynchronous CookieMonster API
369
rdsmith7ac81712017-06-22 17:09:54370void CookieMonster::FlushStore(base::OnceClosure callback) {
mmenkebe0910d2016-03-01 19:09:09371 DCHECK(thread_checker_.CalledOnValidThread());
mmenke606c59c2016-03-07 18:20:55372
nharper2b0ad9a2017-05-22 18:33:45373 if (initialized_ && store_.get()) {
rdsmith7ac81712017-06-22 17:09:54374 store_->Flush(std::move(callback));
rdsmithe5c701d2017-07-12 21:50:00375 } else if (callback) {
rdsmith7ac81712017-06-22 17:09:54376 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
377 std::move(callback));
nharper2b0ad9a2017-05-22 18:33:45378 }
mmenke74bcbd52016-01-21 17:17:56379}
380
mmenkeded79da2016-02-06 08:28:51381void CookieMonster::SetForceKeepSessionState() {
mmenkebe0910d2016-03-01 19:09:09382 DCHECK(thread_checker_.CalledOnValidThread());
mmenke606c59c2016-03-07 18:20:55383
mmenkeded79da2016-02-06 08:28:51384 if (store_)
385 store_->SetForceKeepSessionState();
386}
387
drogerd5d1278c2015-03-17 19:21:51388void CookieMonster::SetAllCookiesAsync(const CookieList& list,
rdsmith7ac81712017-06-22 17:09:54389 SetCookiesCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00390 DoCookieCallback(base::BindOnce(
391 // base::Unretained is safe as DoCookieCallbackForURL stores
392 // the callback on |*this|, so the callback will not outlive
393 // the object.
394 &CookieMonster::SetAllCookies, base::Unretained(this), list,
395 std::move(callback)));
drogerd5d1278c2015-03-17 19:21:51396}
397
rdsmitha6ce4442017-06-21 17:11:05398void CookieMonster::SetCanonicalCookieAsync(
399 std::unique_ptr<CanonicalCookie> cookie,
Maks Orlovich44525ce2019-02-25 14:17:58400 std::string source_scheme,
Maks Orlovichfdbc8be2019-03-18 18:34:52401 const CookieOptions& options,
rdsmith7ac81712017-06-22 17:09:54402 SetCookiesCallback callback) {
rdsmitha6ce4442017-06-21 17:11:05403 DCHECK(cookie->IsCanonical());
rdsmitha6ce4442017-06-21 17:11:05404
Maks Orlovich323efaf2018-03-06 02:56:39405 std::string domain = cookie->Domain();
406 DoCookieCallbackForHostOrDomain(
407 base::BindOnce(
408 // base::Unretained is safe as DoCookieCallbackForURL stores
409 // the callback on |*this|, so the callback will not outlive
410 // the object.
411 &CookieMonster::SetCanonicalCookie, base::Unretained(this),
Maks Orlovichfdbc8be2019-03-18 18:34:52412 std::move(cookie), std::move(source_scheme), options,
Maks Orlovich323efaf2018-03-06 02:56:39413 std::move(callback)),
414 domain);
rdsmitha6ce4442017-06-21 17:11:05415}
416
rdsmith7ac81712017-06-22 17:09:54417void CookieMonster::SetCookieWithOptionsAsync(const GURL& url,
418 const std::string& cookie_line,
419 const CookieOptions& options,
420 SetCookiesCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00421 DoCookieCallbackForURL(
422 base::BindOnce(
423 // base::Unretained is safe as DoCookieCallbackForURL stores
424 // the callback on |*this|, so the callback will not outlive
425 // the object.
426 &CookieMonster::SetCookieWithOptions, base::Unretained(this), url,
427 cookie_line, options, std::move(callback)),
428 url);
[email protected]218aa6a12011-09-13 17:38:38429}
430
mkwstc611e6d2016-02-23 15:45:55431void CookieMonster::GetCookieListWithOptionsAsync(
mmenke74bcbd52016-01-21 17:17:56432 const GURL& url,
mkwstc611e6d2016-02-23 15:45:55433 const CookieOptions& options,
rdsmith7ac81712017-06-22 17:09:54434 GetCookieListCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00435 DoCookieCallbackForURL(
Ken Rockotec216e3dd2019-02-20 00:43:59436 base::BindOnce(
rdsmithe5c701d2017-07-12 21:50:00437 // base::Unretained is safe as DoCookieCallbackForURL stores
438 // the callback on |*this|, so the callback will not outlive
439 // the object.
440 &CookieMonster::GetCookieListWithOptions, base::Unretained(this), url,
Ken Rockotec216e3dd2019-02-20 00:43:59441 options, std::move(callback)),
rdsmithe5c701d2017-07-12 21:50:00442 url);
mmenke74bcbd52016-01-21 17:17:56443}
444
rdsmith7ac81712017-06-22 17:09:54445void CookieMonster::GetAllCookiesAsync(GetCookieListCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00446 DoCookieCallback(base::BindOnce(
447 // base::Unretained is safe as DoCookieCallbackForURL stores
448 // the callback on |*this|, so the callback will not outlive
449 // the object.
450 &CookieMonster::GetAllCookies, base::Unretained(this),
451 std::move(callback)));
mmenke9fa44f2d2016-01-22 23:36:39452}
453
mmenke24379d52016-02-05 23:50:17454void CookieMonster::DeleteCanonicalCookieAsync(const CanonicalCookie& cookie,
rdsmith7ac81712017-06-22 17:09:54455 DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00456 DoCookieCallback(base::BindOnce(
457 // base::Unretained is safe as DoCookieCallbackForURL stores
458 // the callback on |*this|, so the callback will not outlive
459 // the object.
460 &CookieMonster::DeleteCanonicalCookie, base::Unretained(this), cookie,
461 std::move(callback)));
mmenke24379d52016-02-05 23:50:17462}
463
Chris Mumford800caa62018-04-20 19:34:44464void CookieMonster::DeleteAllCreatedInTimeRangeAsync(
465 const TimeRange& creation_range,
466 DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00467 DoCookieCallback(base::BindOnce(
468 // base::Unretained is safe as DoCookieCallbackForURL stores
469 // the callback on |*this|, so the callback will not outlive
470 // the object.
Chris Mumford800caa62018-04-20 19:34:44471 &CookieMonster::DeleteAllCreatedInTimeRange, base::Unretained(this),
472 creation_range, std::move(callback)));
mmenke74bcbd52016-01-21 17:17:56473}
474
Chris Mumford800caa62018-04-20 19:34:44475void CookieMonster::DeleteAllMatchingInfoAsync(CookieDeletionInfo delete_info,
476 DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00477 DoCookieCallback(base::BindOnce(
478 // base::Unretained is safe as DoCookieCallbackForURL stores
479 // the callback on |*this|, so the callback will not outlive
480 // the object.
Chris Mumford800caa62018-04-20 19:34:44481 &CookieMonster::DeleteAllMatchingInfo, base::Unretained(this),
482 std::move(delete_info), std::move(callback)));
mmenke74bcbd52016-01-21 17:17:56483}
484
[email protected]264807b2012-04-25 14:49:37485void CookieMonster::DeleteSessionCookiesAsync(
rdsmith7ac81712017-06-22 17:09:54486 CookieStore::DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00487 DoCookieCallback(base::BindOnce(
488 // base::Unretained is safe as DoCookieCallbackForURL stores
489 // the callback on |*this|, so the callback will not outlive
490 // the object.
491 &CookieMonster::DeleteSessionCookies, base::Unretained(this),
492 std::move(callback)));
[email protected]264807b2012-04-25 14:49:37493}
494
mmenke18dd8ba2016-02-01 18:42:10495void CookieMonster::SetCookieableSchemes(
Nate Fischerc6fb6cf2019-03-27 00:39:49496 const std::vector<std::string>& schemes,
497 SetCookieableSchemesCallback callback) {
mmenkebe0910d2016-03-01 19:09:09498 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56499
500 // Calls to this method will have no effect if made after a WebView or
501 // CookieManager instance has been created.
Nate Fischerc6fb6cf2019-03-27 00:39:49502 if (initialized_) {
503 MaybeRunCookieCallback(std::move(callback), false);
mmenke74bcbd52016-01-21 17:17:56504 return;
Nate Fischerc6fb6cf2019-03-27 00:39:49505 }
mmenke74bcbd52016-01-21 17:17:56506
mmenke18dd8ba2016-02-01 18:42:10507 cookieable_schemes_ = schemes;
Nate Fischerc6fb6cf2019-03-27 00:39:49508 MaybeRunCookieCallback(std::move(callback), true);
mmenke74bcbd52016-01-21 17:17:56509}
510
mmenke74bcbd52016-01-21 17:17:56511// This function must be called before the CookieMonster is used.
512void CookieMonster::SetPersistSessionCookies(bool persist_session_cookies) {
mmenkebe0910d2016-03-01 19:09:09513 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56514 DCHECK(!initialized_);
Helen Licd0fab862018-08-13 16:07:53515 net_log_.AddEvent(
516 NetLogEventType::COOKIE_STORE_SESSION_PERSISTENCE,
517 NetLog::BoolCallback("persistence", persist_session_cookies));
mmenke74bcbd52016-01-21 17:17:56518 persist_session_cookies_ = persist_session_cookies;
519}
520
521bool CookieMonster::IsCookieableScheme(const std::string& scheme) {
mmenkebe0910d2016-03-01 19:09:09522 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56523
tripta.gdda72022017-06-19 05:16:23524 return base::ContainsValue(cookieable_schemes_, scheme);
mmenke74bcbd52016-01-21 17:17:56525}
526
mmenke18dd8ba2016-02-01 18:42:10527const char* const CookieMonster::kDefaultCookieableSchemes[] = {"http", "https",
528 "ws", "wss"};
mmenke74bcbd52016-01-21 17:17:56529const int CookieMonster::kDefaultCookieableSchemesCount =
Ryan Sleevi435a3a22018-05-15 02:16:07530 base::size(kDefaultCookieableSchemes);
mmenke74bcbd52016-01-21 17:17:56531
Victor Costan14f47c12018-03-01 08:02:24532CookieChangeDispatcher& CookieMonster::GetChangeDispatcher() {
533 return change_dispatcher_;
Randy Smithd32dc8c2017-08-30 18:03:40534}
535
nharper5babb5e62016-03-09 18:58:07536bool CookieMonster::IsEphemeral() {
537 return store_.get() == nullptr;
538}
539
Maks Orlovich5cf437b02018-03-27 04:40:42540void CookieMonster::DumpMemoryStats(
541 base::trace_event::ProcessMemoryDump* pmd,
542 const std::string& parent_absolute_name) const {
543 const char kRelPath[] = "/cookie_monster";
544
545 pmd->CreateAllocatorDump(parent_absolute_name + kRelPath + "/cookies")
546 ->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
547 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
548 cookies_.size());
549
550 pmd->CreateAllocatorDump(parent_absolute_name + kRelPath +
551 "/tasks_pending_global")
552 ->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
553 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
554 tasks_pending_.size());
555
556 size_t total_pending_for_key = 0;
557 for (const auto& kv : tasks_pending_for_key_)
558 total_pending_for_key += kv.second.size();
559 pmd->CreateAllocatorDump(parent_absolute_name + kRelPath +
560 "/tasks_pending_for_key")
561 ->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
562 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
563 total_pending_for_key);
564}
565
mmenke74bcbd52016-01-21 17:17:56566CookieMonster::~CookieMonster() {
mmenkebe0910d2016-03-01 19:09:09567 DCHECK(thread_checker_.CalledOnValidThread());
mmenke05255cf2016-02-03 15:49:31568
Randy Smith0a522662017-08-30 19:35:34569 // TODO(mmenke): Does it really make sense to run
mmenke606c59c2016-03-07 18:20:55570 // CookieChanged callbacks when the CookieStore is destroyed?
jdoerrie22a91d8b92018-10-05 08:43:26571 for (auto cookie_it = cookies_.begin(); cookie_it != cookies_.end();) {
572 auto current_cookie_it = cookie_it;
mmenke05255cf2016-02-03 15:49:31573 ++cookie_it;
574 InternalDeleteCookie(current_cookie_it, false /* sync_to_store */,
575 DELETE_COOKIE_DONT_RECORD);
576 }
Helen Licd0fab862018-08-13 16:07:53577 net_log_.EndEvent(NetLogEventType::COOKIE_STORE_ALIVE);
[email protected]85620342011-10-17 17:35:04578}
579
rdsmithe5c701d2017-07-12 21:50:00580void CookieMonster::GetAllCookies(GetCookieListCallback callback) {
mmenkebe0910d2016-03-01 19:09:09581 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40582
583 // This function is being called to scrape the cookie list for management UI
584 // or similar. We shouldn't show expired cookies in this list since it will
585 // just be confusing to users, and this function is called rarely enough (and
586 // is already slow enough) that it's OK to take the time to garbage collect
587 // the expired cookies now.
588 //
589 // Note that this does not prune cookies to be below our limits (if we've
590 // exceeded them) the way that calling GarbageCollect() would.
mkwstbe84af312015-02-20 08:52:45591 GarbageCollectExpired(
Raul Tambre94493c652019-03-11 17:18:35592 Time::Now(), CookieMapItPair(cookies_.begin(), cookies_.end()), nullptr);
[email protected]f48b9432011-01-11 07:25:40593
594 // Copy the CanonicalCookie pointers from the map so that we can use the same
595 // sorter as elsewhere, then copy the result out.
596 std::vector<CanonicalCookie*> cookie_ptrs;
597 cookie_ptrs.reserve(cookies_.size());
avie7cd11a2016-10-11 02:00:35598 for (const auto& cookie : cookies_)
599 cookie_ptrs.push_back(cookie.second.get());
[email protected]f48b9432011-01-11 07:25:40600 std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
601
602 CookieList cookie_list;
603 cookie_list.reserve(cookie_ptrs.size());
vmpstr6d9996c82017-02-23 00:43:25604 for (auto* cookie_ptr : cookie_ptrs)
avie7cd11a2016-10-11 02:00:35605 cookie_list.push_back(*cookie_ptr);
[email protected]f48b9432011-01-11 07:25:40606
Aaron Tagliaboschia4c64b52019-01-25 03:28:49607 MaybeRunCookieCallback(std::move(callback), cookie_list, CookieStatusList());
[email protected]f325f1e12010-04-30 22:38:55608}
609
rdsmithe5c701d2017-07-12 21:50:00610void CookieMonster::GetCookieListWithOptions(const GURL& url,
611 const CookieOptions& options,
612 GetCookieListCallback callback) {
mmenkebe0910d2016-03-01 19:09:09613 DCHECK(thread_checker_.CalledOnValidThread());
initial.commit586acc5fe2008-07-26 22:42:52614
mkwstc611e6d2016-02-23 15:45:55615 CookieList cookies;
Aaron Tagliaboschia4c64b52019-01-25 03:28:49616 CookieStatusList excluded_cookies;
rdsmithe5c701d2017-07-12 21:50:00617 if (HasCookieableScheme(url)) {
618 std::vector<CanonicalCookie*> cookie_ptrs;
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:52619 FindCookiesForRegistryControlledHost(url, &cookie_ptrs);
Aaron Tagliaboschi29033b7f2019-01-31 19:58:20620 std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
mkwstc611e6d2016-02-23 15:45:55621
rdsmithe5c701d2017-07-12 21:50:00622 cookies.reserve(cookie_ptrs.size());
Aaron Tagliaboschi29033b7f2019-01-31 19:58:20623 std::vector<CanonicalCookie*> included_cookie_ptrs;
624 FilterCookiesWithOptions(url, options, &cookie_ptrs, &included_cookie_ptrs,
625 &excluded_cookies);
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:52626
Aaron Tagliaboschi29033b7f2019-01-31 19:58:20627 for (auto* cookie : included_cookie_ptrs) {
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:52628 cookies.push_back(*cookie);
629 }
rdsmithe5c701d2017-07-12 21:50:00630 }
Aaron Tagliaboschi29033b7f2019-01-31 19:58:20631
Aaron Tagliaboschia4c64b52019-01-25 03:28:49632 MaybeRunCookieCallback(std::move(callback), cookies, excluded_cookies);
initial.commit586acc5fe2008-07-26 22:42:52633}
634
Chris Mumford800caa62018-04-20 19:34:44635void CookieMonster::DeleteAllCreatedInTimeRange(const TimeRange& creation_range,
636 DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09637 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]d0980332010-11-16 17:08:53638
rdsmitha5beda162017-07-08 13:55:42639 uint32_t num_deleted = 0;
jdoerrie22a91d8b92018-10-05 08:43:26640 for (auto it = cookies_.begin(); it != cookies_.end();) {
641 auto curit = it;
avie7cd11a2016-10-11 02:00:35642 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:40643 ++it;
[email protected]d0980332010-11-16 17:08:53644
Chris Mumford800caa62018-04-20 19:34:44645 if (creation_range.Contains(cc->CreationDate())) {
mkwstbe84af312015-02-20 08:52:45646 InternalDeleteCookie(curit, true, /*sync_to_store*/
Nick Harper7a6683a2018-01-30 20:42:52647 DELETE_COOKIE_EXPLICIT);
[email protected]f48b9432011-01-11 07:25:40648 ++num_deleted;
initial.commit586acc5fe2008-07-26 22:42:52649 }
650 }
651
rdsmithe5c701d2017-07-12 21:50:00652 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39653 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00654 callback ? base::BindOnce(std::move(callback), num_deleted)
655 : base::OnceClosure()));
[email protected]f48b9432011-01-11 07:25:40656}
657
Chris Mumford800caa62018-04-20 19:34:44658void CookieMonster::DeleteAllMatchingInfo(CookieDeletionInfo delete_info,
659 DeleteCallback callback) {
rdsmitha5beda162017-07-08 13:55:42660 uint32_t num_deleted = 0;
jdoerrie22a91d8b92018-10-05 08:43:26661 for (auto it = cookies_.begin(); it != cookies_.end();) {
662 auto curit = it;
avie7cd11a2016-10-11 02:00:35663 CanonicalCookie* cc = curit->second.get();
dmurphfaea244c2016-04-09 00:42:30664 ++it;
[email protected]f48b9432011-01-11 07:25:40665
Chris Mumford800caa62018-04-20 19:34:44666 if (delete_info.Matches(*cc)) {
dmurphfaea244c2016-04-09 00:42:30667 InternalDeleteCookie(curit, true, /*sync_to_store*/
Nick Harper7a6683a2018-01-30 20:42:52668 DELETE_COOKIE_EXPLICIT);
dmurphfaea244c2016-04-09 00:42:30669 ++num_deleted;
[email protected]f48b9432011-01-11 07:25:40670 }
671 }
dmurphfaea244c2016-04-09 00:42:30672
rdsmithe5c701d2017-07-12 21:50:00673 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39674 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00675 callback ? base::BindOnce(std::move(callback), num_deleted)
676 : base::OnceClosure()));
[email protected]f48b9432011-01-11 07:25:40677}
678
rdsmithe5c701d2017-07-12 21:50:00679void CookieMonster::SetCookieWithOptions(const GURL& url,
[email protected]f48b9432011-01-11 07:25:40680 const std::string& cookie_line,
rdsmithe5c701d2017-07-12 21:50:00681 const CookieOptions& options,
682 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:09683 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40684
685 if (!HasCookieableScheme(url)) {
Aaron Tagliaboschi29764f52019-02-21 17:19:59686 MaybeRunCookieCallback(
687 std::move(callback),
688 CanonicalCookie::CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME);
rdsmithe5c701d2017-07-12 21:50:00689 return;
[email protected]f48b9432011-01-11 07:25:40690 }
691
Maks Orlovich35d74c042019-04-18 16:38:01692 DVLOG(net::cookie_util::kVlogSetCookies)
Oscar Johansson63e83cf2018-07-02 08:47:26693 << "SetCookie() line: " << cookie_line;
Maks Orlovicha61ed022018-03-01 18:24:24694
Aaron Tagliaboschi29764f52019-02-21 17:19:59695 CanonicalCookie::CookieInclusionStatus status;
Maks Orlovicha61ed022018-03-01 18:24:24696
Aaron Tagliaboschi29764f52019-02-21 17:19:59697 std::unique_ptr<CanonicalCookie> cc(
698 CanonicalCookie::Create(url, cookie_line, Time::Now(), options, &status));
699
700 if (status != CanonicalCookie::CookieInclusionStatus::INCLUDE) {
701 DCHECK(!cc);
Maks Orlovich35d74c042019-04-18 16:38:01702 DVLOG(net::cookie_util::kVlogSetCookies)
Oscar Johansson63e83cf2018-07-02 08:47:26703 << "WARNING: Failed to allocate CanonicalCookie";
Aaron Tagliaboschi29764f52019-02-21 17:19:59704 MaybeRunCookieCallback(std::move(callback), status);
Maks Orlovicha61ed022018-03-01 18:24:24705 return;
706 }
Aaron Tagliaboschi29764f52019-02-21 17:19:59707
708 DCHECK(cc);
Maks Orlovichfdbc8be2019-03-18 18:34:52709 SetCanonicalCookie(std::move(cc), url.scheme(), options, std::move(callback));
[email protected]f48b9432011-01-11 07:25:40710}
711
rdsmithe5c701d2017-07-12 21:50:00712void CookieMonster::DeleteCanonicalCookie(const CanonicalCookie& cookie,
713 DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09714 DCHECK(thread_checker_.CalledOnValidThread());
mmenke24379d52016-02-05 23:50:17715
rdsmithe5c701d2017-07-12 21:50:00716 uint32_t result = 0u;
mmenke24379d52016-02-05 23:50:17717 for (CookieMapItPair its = cookies_.equal_range(GetKey(cookie.Domain()));
718 its.first != its.second; ++its.first) {
Maks Orlovich2896ec3f2018-04-06 13:34:27719 const std::unique_ptr<CanonicalCookie>& candidate = its.first->second;
720 // Historically, this has refused modification if the cookie has changed
721 // value in between the CanonicalCookie object was returned by a getter
722 // and when this ran. The later parts of the conditional (everything but
723 // the equivalence check) attempt to preserve this behavior.
724 if (candidate->IsEquivalent(cookie) &&
Maks Orlovich2896ec3f2018-04-06 13:34:27725 candidate->Value() == cookie.Value()) {
Nick Harper7a6683a2018-01-30 20:42:52726 InternalDeleteCookie(its.first, true, DELETE_COOKIE_EXPLICIT);
rdsmithe5c701d2017-07-12 21:50:00727 result = 1u;
728 break;
mmenke24379d52016-02-05 23:50:17729 }
730 }
rdsmithe5c701d2017-07-12 21:50:00731 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39732 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00733 callback ? base::BindOnce(std::move(callback), result)
734 : base::OnceClosure()));
mmenke24379d52016-02-05 23:50:17735}
736
rdsmithe5c701d2017-07-12 21:50:00737void CookieMonster::DeleteSessionCookies(DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09738 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]264807b2012-04-25 14:49:37739
rdsmitha5beda162017-07-08 13:55:42740 uint32_t num_deleted = 0;
jdoerrie22a91d8b92018-10-05 08:43:26741 for (auto it = cookies_.begin(); it != cookies_.end();) {
742 auto curit = it;
avie7cd11a2016-10-11 02:00:35743 CanonicalCookie* cc = curit->second.get();
[email protected]264807b2012-04-25 14:49:37744 ++it;
745
746 if (!cc->IsPersistent()) {
mkwstbe84af312015-02-20 08:52:45747 InternalDeleteCookie(curit, true, /*sync_to_store*/
[email protected]264807b2012-04-25 14:49:37748 DELETE_COOKIE_EXPIRED);
749 ++num_deleted;
750 }
751 }
752
rdsmithe5c701d2017-07-12 21:50:00753 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39754 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00755 callback ? base::BindOnce(std::move(callback), num_deleted)
756 : base::OnceClosure()));
[email protected]264807b2012-04-25 14:49:37757}
758
erikchen1dd72a72015-05-06 20:45:05759void CookieMonster::MarkCookieStoreAsInitialized() {
mmenkebe0910d2016-03-01 19:09:09760 DCHECK(thread_checker_.CalledOnValidThread());
erikchen1dd72a72015-05-06 20:45:05761 initialized_ = true;
762}
763
764void CookieMonster::FetchAllCookiesIfNecessary() {
mmenkebe0910d2016-03-01 19:09:09765 DCHECK(thread_checker_.CalledOnValidThread());
erikchen1dd72a72015-05-06 20:45:05766 if (store_.get() && !started_fetching_all_cookies_) {
767 started_fetching_all_cookies_ = true;
768 FetchAllCookies();
769 }
770}
771
mmenke74bcbd52016-01-21 17:17:56772void CookieMonster::FetchAllCookies() {
mmenkebe0910d2016-03-01 19:09:09773 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56774 DCHECK(store_.get()) << "Store must exist to initialize";
775 DCHECK(!finished_fetching_all_cookies_)
776 << "All cookies have already been fetched.";
777
778 // We bind in the current time so that we can report the wall-clock time for
779 // loading cookies.
Maks Orlovich108cb4c2019-03-26 20:24:57780 store_->Load(base::BindOnce(&CookieMonster::OnLoaded,
781 weak_ptr_factory_.GetWeakPtr(), TimeTicks::Now()),
Helen Li92a29f102018-08-15 23:02:26782 net_log_);
mmenke74bcbd52016-01-21 17:17:56783}
784
avie7cd11a2016-10-11 02:00:35785void CookieMonster::OnLoaded(
786 TimeTicks beginning_time,
787 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:09788 DCHECK(thread_checker_.CalledOnValidThread());
avie7cd11a2016-10-11 02:00:35789 StoreLoadedCookies(std::move(cookies));
[email protected]c7593fb22011-11-14 23:54:27790 histogram_time_blocked_on_load_->AddTime(TimeTicks::Now() - beginning_time);
[email protected]218aa6a12011-09-13 17:38:38791
792 // Invoke the task queue of cookie request.
793 InvokeQueue();
794}
795
avie7cd11a2016-10-11 02:00:35796void CookieMonster::OnKeyLoaded(
797 const std::string& key,
798 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:09799 DCHECK(thread_checker_.CalledOnValidThread());
800
avie7cd11a2016-10-11 02:00:35801 StoreLoadedCookies(std::move(cookies));
[email protected]85620342011-10-17 17:35:04802
mmenkebe0910d2016-03-01 19:09:09803 auto tasks_pending_for_key = tasks_pending_for_key_.find(key);
[email protected]85620342011-10-17 17:35:04804
mmenkebe0910d2016-03-01 19:09:09805 // TODO(mmenke): Can this be turned into a DCHECK?
806 if (tasks_pending_for_key == tasks_pending_for_key_.end())
807 return;
[email protected]bab72ec2013-10-30 20:50:02808
mmenkebe0910d2016-03-01 19:09:09809 // Run all tasks for the key. Note that running a task can result in multiple
810 // tasks being added to the back of the deque.
811 while (!tasks_pending_for_key->second.empty()) {
rdsmithe5c701d2017-07-12 21:50:00812 base::OnceClosure task = std::move(tasks_pending_for_key->second.front());
mmenkebe0910d2016-03-01 19:09:09813 tasks_pending_for_key->second.pop_front();
rdsmithe5c701d2017-07-12 21:50:00814 std::move(task).Run();
[email protected]85620342011-10-17 17:35:04815 }
mmenkebe0910d2016-03-01 19:09:09816
817 tasks_pending_for_key_.erase(tasks_pending_for_key);
818
819 // This has to be done last, in case running a task queues a new task for the
820 // key, to ensure tasks are run in the correct order.
821 keys_loaded_.insert(key);
[email protected]85620342011-10-17 17:35:04822}
823
[email protected]218aa6a12011-09-13 17:38:38824void CookieMonster::StoreLoadedCookies(
avie7cd11a2016-10-11 02:00:35825 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:09826 DCHECK(thread_checker_.CalledOnValidThread());
827
mmenkebe0910d2016-03-01 19:09:09828 // Even if a key is expired, insert it so it can be garbage collected,
829 // removed, and sync'd.
[email protected]6210ce52013-09-20 03:33:14830 CookieItVector cookies_with_control_chars;
831
avie7cd11a2016-10-11 02:00:35832 for (auto& cookie : cookies) {
Maks Orlovich2b0d5b12018-04-10 19:33:47833 CanonicalCookie* cookie_ptr = cookie.get();
jdoerrie22a91d8b92018-10-05 08:43:26834 auto inserted = InternalInsertCookie(GetKey(cookie_ptr->Domain()),
835 std::move(cookie), false);
Maks Orlovich2b0d5b12018-04-10 19:33:47836 const Time cookie_access_time(cookie_ptr->LastAccessDate());
837 if (earliest_access_time_.is_null() ||
Helen Lid84010b2018-08-22 16:27:44838 cookie_access_time < earliest_access_time_) {
Maks Orlovich2b0d5b12018-04-10 19:33:47839 earliest_access_time_ = cookie_access_time;
Helen Lid84010b2018-08-22 16:27:44840 }
[email protected]f48b9432011-01-11 07:25:40841
Maks Orlovich2b0d5b12018-04-10 19:33:47842 if (ContainsControlCharacter(cookie_ptr->Name()) ||
843 ContainsControlCharacter(cookie_ptr->Value())) {
844 cookies_with_control_chars.push_back(inserted);
[email protected]f48b9432011-01-11 07:25:40845 }
846 }
[email protected]f48b9432011-01-11 07:25:40847
[email protected]6210ce52013-09-20 03:33:14848 // Any cookies that contain control characters that we have loaded from the
849 // persistent store should be deleted. See http://crbug.com/238041.
jdoerrie22a91d8b92018-10-05 08:43:26850 for (auto it = cookies_with_control_chars.begin();
[email protected]6210ce52013-09-20 03:33:14851 it != cookies_with_control_chars.end();) {
jdoerrie22a91d8b92018-10-05 08:43:26852 auto curit = it;
[email protected]6210ce52013-09-20 03:33:14853 ++it;
854
855 InternalDeleteCookie(*curit, true, DELETE_COOKIE_CONTROL_CHAR);
856 }
857
[email protected]f48b9432011-01-11 07:25:40858 // After importing cookies from the PersistentCookieStore, verify that
859 // none of our other constraints are violated.
[email protected]f48b9432011-01-11 07:25:40860 // In particular, the backing store might have given us duplicate cookies.
[email protected]85620342011-10-17 17:35:04861
862 // This method could be called multiple times due to priority loading, thus
863 // cookies loaded in previous runs will be validated again, but this is OK
864 // since they are expected to be much fewer than total DB.
[email protected]f48b9432011-01-11 07:25:40865 EnsureCookiesMapIsValid();
[email protected]218aa6a12011-09-13 17:38:38866}
[email protected]f48b9432011-01-11 07:25:40867
[email protected]218aa6a12011-09-13 17:38:38868void CookieMonster::InvokeQueue() {
mmenkebe0910d2016-03-01 19:09:09869 DCHECK(thread_checker_.CalledOnValidThread());
870
mmenkef49fca0e2016-03-08 12:46:24871 // Move all per-key tasks into the global queue, if there are any. This is
872 // protection about a race where the store learns about all cookies loading
873 // before it learned about the cookies for a key loading.
874
875 // Needed to prevent any recursively queued tasks from going back into the
876 // per-key queues.
877 seen_global_task_ = true;
rdsmithe5c701d2017-07-12 21:50:00878 for (auto& tasks_for_key : tasks_pending_for_key_) {
879 tasks_pending_.insert(tasks_pending_.begin(),
880 std::make_move_iterator(tasks_for_key.second.begin()),
881 std::make_move_iterator(tasks_for_key.second.end()));
mmenkef49fca0e2016-03-08 12:46:24882 }
883 tasks_pending_for_key_.clear();
884
mmenkebe0910d2016-03-01 19:09:09885 while (!tasks_pending_.empty()) {
rdsmithe5c701d2017-07-12 21:50:00886 base::OnceClosure request_task = std::move(tasks_pending_.front());
mmenkef49fca0e2016-03-08 12:46:24887 tasks_pending_.pop_front();
rdsmithe5c701d2017-07-12 21:50:00888 std::move(request_task).Run();
[email protected]218aa6a12011-09-13 17:38:38889 }
mmenkebe0910d2016-03-01 19:09:09890
mmenkef49fca0e2016-03-08 12:46:24891 DCHECK(tasks_pending_for_key_.empty());
892
mmenkebe0910d2016-03-01 19:09:09893 finished_fetching_all_cookies_ = true;
mmenkebe0910d2016-03-01 19:09:09894 keys_loaded_.clear();
[email protected]f48b9432011-01-11 07:25:40895}
896
897void CookieMonster::EnsureCookiesMapIsValid() {
mmenkebe0910d2016-03-01 19:09:09898 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40899
[email protected]f48b9432011-01-11 07:25:40900 // Iterate through all the of the cookies, grouped by host.
jdoerrie22a91d8b92018-10-05 08:43:26901 auto prev_range_end = cookies_.begin();
[email protected]f48b9432011-01-11 07:25:40902 while (prev_range_end != cookies_.end()) {
jdoerrie22a91d8b92018-10-05 08:43:26903 auto cur_range_begin = prev_range_end;
[email protected]f48b9432011-01-11 07:25:40904 const std::string key = cur_range_begin->first; // Keep a copy.
jdoerrie22a91d8b92018-10-05 08:43:26905 auto cur_range_end = cookies_.upper_bound(key);
[email protected]f48b9432011-01-11 07:25:40906 prev_range_end = cur_range_end;
907
908 // Ensure no equivalent cookies for this host.
ellyjonescabf57422015-08-21 18:44:51909 TrimDuplicateCookiesForKey(key, cur_range_begin, cur_range_end);
[email protected]f48b9432011-01-11 07:25:40910 }
[email protected]f48b9432011-01-11 07:25:40911}
912
ellyjonescabf57422015-08-21 18:44:51913void CookieMonster::TrimDuplicateCookiesForKey(const std::string& key,
914 CookieMap::iterator begin,
915 CookieMap::iterator end) {
mmenkebe0910d2016-03-01 19:09:09916 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40917
918 // Set of cookies ordered by creation time.
Maks Orlovich2b0d5b12018-04-10 19:33:47919 typedef std::multiset<CookieMap::iterator, OrderByCreationTimeDesc> CookieSet;
[email protected]f48b9432011-01-11 07:25:40920
921 // Helper map we populate to find the duplicates.
922 typedef std::map<CookieSignature, CookieSet> EquivalenceMap;
923 EquivalenceMap equivalent_cookies;
924
925 // The number of duplicate cookies that have been found.
926 int num_duplicates = 0;
927
928 // Iterate through all of the cookies in our range, and insert them into
929 // the equivalence map.
jdoerrie22a91d8b92018-10-05 08:43:26930 for (auto it = begin; it != end; ++it) {
[email protected]f48b9432011-01-11 07:25:40931 DCHECK_EQ(key, it->first);
avie7cd11a2016-10-11 02:00:35932 CanonicalCookie* cookie = it->second.get();
[email protected]f48b9432011-01-11 07:25:40933
mkwstbe84af312015-02-20 08:52:45934 CookieSignature signature(cookie->Name(), cookie->Domain(), cookie->Path());
[email protected]f48b9432011-01-11 07:25:40935 CookieSet& set = equivalent_cookies[signature];
936
937 // We found a duplicate!
938 if (!set.empty())
939 num_duplicates++;
940
941 // We save the iterator into |cookies_| rather than the actual cookie
942 // pointer, since we may need to delete it later.
Maks Orlovich2b0d5b12018-04-10 19:33:47943 set.insert(it);
[email protected]f48b9432011-01-11 07:25:40944 }
945
946 // If there were no duplicates, we are done!
947 if (num_duplicates == 0)
ellyjonescabf57422015-08-21 18:44:51948 return;
[email protected]f48b9432011-01-11 07:25:40949
950 // Make sure we find everything below that we did above.
951 int num_duplicates_found = 0;
952
953 // Otherwise, delete all the duplicate cookies, both from our in-memory store
954 // and from the backing store.
jdoerrie22a91d8b92018-10-05 08:43:26955 for (auto it = equivalent_cookies.begin(); it != equivalent_cookies.end();
956 ++it) {
[email protected]f48b9432011-01-11 07:25:40957 const CookieSignature& signature = it->first;
958 CookieSet& dupes = it->second;
959
960 if (dupes.size() <= 1)
961 continue; // This cookiename/path has no duplicates.
962 num_duplicates_found += dupes.size() - 1;
963
Maks Orlovich2b0d5b12018-04-10 19:33:47964 // Since |dupes| is sorted by creation time (descending), the first cookie
965 // is the most recent one (or tied for it), so we will keep it. The rest are
966 // duplicates.
[email protected]f48b9432011-01-11 07:25:40967 dupes.erase(dupes.begin());
968
969 LOG(ERROR) << base::StringPrintf(
970 "Found %d duplicate cookies for host='%s', "
971 "with {name='%s', domain='%s', path='%s'}",
mkwstbe84af312015-02-20 08:52:45972 static_cast<int>(dupes.size()), key.c_str(), signature.name.c_str(),
973 signature.domain.c_str(), signature.path.c_str());
[email protected]f48b9432011-01-11 07:25:40974
975 // Remove all the cookies identified by |dupes|. It is valid to delete our
976 // list of iterators one at a time, since |cookies_| is a multimap (they
977 // don't invalidate existing iterators following deletion).
jdoerrie22a91d8b92018-10-05 08:43:26978 for (auto dupes_it = dupes.begin(); dupes_it != dupes.end(); ++dupes_it) {
[email protected]218aa6a12011-09-13 17:38:38979 InternalDeleteCookie(*dupes_it, true,
[email protected]f48b9432011-01-11 07:25:40980 DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE);
981 }
982 }
983 DCHECK_EQ(num_duplicates, num_duplicates_found);
[email protected]f48b9432011-01-11 07:25:40984}
985
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:52986void CookieMonster::FindCookiesForRegistryControlledHost(
[email protected]f48b9432011-01-11 07:25:40987 const GURL& url,
[email protected]f48b9432011-01-11 07:25:40988 std::vector<CanonicalCookie*>* cookies) {
mmenkebe0910d2016-03-01 19:09:09989 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40990
Maks Orlovichc86cf292019-02-11 19:25:17991 Time current_time = Time::Now();
[email protected]f48b9432011-01-11 07:25:40992
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:52993 // Retrieve all cookies for a given key
Maks Orlovich323efaf2018-03-06 02:56:39994 const std::string key(GetKey(url.host_piece()));
Aaron Tagliaboschi9e1de1b2019-01-15 14:40:06995
[email protected]f48b9432011-01-11 07:25:40996 for (CookieMapItPair its = cookies_.equal_range(key);
mkwstbe84af312015-02-20 08:52:45997 its.first != its.second;) {
jdoerrie22a91d8b92018-10-05 08:43:26998 auto curit = its.first;
avie7cd11a2016-10-11 02:00:35999 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:401000 ++its.first;
1001
1002 // If the cookie is expired, delete it.
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521003 if (cc->IsExpired(current_time)) {
[email protected]f48b9432011-01-11 07:25:401004 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
1005 continue;
1006 }
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521007 cookies->push_back(cc);
Aaron Tagliaboschi9e1de1b2019-01-15 14:40:061008 }
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521009}
[email protected]f48b9432011-01-11 07:25:401010
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521011void CookieMonster::FilterCookiesWithOptions(
1012 const GURL url,
1013 const CookieOptions options,
1014 std::vector<CanonicalCookie*>* cookie_ptrs,
Aaron Tagliaboschi29033b7f2019-01-31 19:58:201015 std::vector<CanonicalCookie*>* included_cookie_ptrs,
1016 CookieStatusList* excluded_cookies) {
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521017 DCHECK(thread_checker_.CalledOnValidThread());
1018
1019 // Probe to save statistics relatively frequently. We do it here rather
1020 // than in the set path as many websites won't set cookies, and we
1021 // want to collect statistics whenever the browser's being used.
Maks Orlovichc86cf292019-02-11 19:25:171022 Time current_time = Time::Now();
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521023 RecordPeriodicStats(current_time);
1024
1025 for (std::vector<CanonicalCookie*>::iterator it = cookie_ptrs->begin();
1026 it != cookie_ptrs->end(); it++) {
[email protected]65f4e7e2012-12-12 21:56:541027 // Filter out cookies that should not be included for a request to the
1028 // given |url|. HTTP only cookies are filtered depending on the passed
1029 // cookie |options|.
Aaron Tagliaboschi29033b7f2019-01-31 19:58:201030 CanonicalCookie::CookieInclusionStatus status =
1031 (*it)->IncludeForRequestURL(url, options);
1032
1033 if (status != CanonicalCookie::CookieInclusionStatus::INCLUDE) {
1034 if (options.return_excluded_cookies())
1035 excluded_cookies->push_back({**it, status});
[email protected]f48b9432011-01-11 07:25:401036 continue;
[email protected]f48b9432011-01-11 07:25:401037 }
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521038
1039 if (options.update_access_time())
1040 InternalUpdateCookieAccessTime(*it, current_time);
1041
Aaron Tagliaboschi29033b7f2019-01-31 19:58:201042 included_cookie_ptrs->push_back(*it);
[email protected]f48b9432011-01-11 07:25:401043 }
1044}
1045
Aaron Tagliaboschi29764f52019-02-21 17:19:591046CanonicalCookie::CookieInclusionStatus CookieMonster::DeleteAnyEquivalentCookie(
Mike Westc4a777b2017-10-06 14:04:201047 const std::string& key,
1048 const CanonicalCookie& ecc,
1049 bool source_secure,
1050 bool skip_httponly,
1051 bool already_expired,
1052 base::Time* creation_date_to_inherit) {
mmenkebe0910d2016-03-01 19:09:091053 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401054
1055 bool found_equivalent_cookie = false;
1056 bool skipped_httponly = false;
jww601411a2015-11-20 19:46:571057 bool skipped_secure_cookie = false;
jww31e32632015-12-16 23:38:341058
1059 histogram_cookie_delete_equivalent_->Add(COOKIE_DELETE_EQUIVALENT_ATTEMPT);
1060
Lily Chen22707642b2018-10-02 17:27:211061 CookieMap::iterator cookie_it_to_possibly_delete = cookies_.end();
1062 CanonicalCookie* cc_skipped_secure = nullptr;
[email protected]f48b9432011-01-11 07:25:401063 for (CookieMapItPair its = cookies_.equal_range(key);
mkwstbe84af312015-02-20 08:52:451064 its.first != its.second;) {
jdoerrie22a91d8b92018-10-05 08:43:261065 auto curit = its.first;
avie7cd11a2016-10-11 02:00:351066 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:401067 ++its.first;
1068
jwwa26e439d2017-01-27 18:17:271069 // If the cookie is being set from an insecure scheme, then if a cookie
1070 // already exists with the same name and it is Secure, then the cookie
1071 // should *not* be updated if they domain-match and ignoring the path
1072 // attribute.
jww601411a2015-11-20 19:46:571073 //
jwwa26e439d2017-01-27 18:17:271074 // See: https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone
rdsmith2709eee2017-06-20 22:43:271075 if (cc->IsSecure() && !source_secure &&
mmenke2830b0722016-07-20 16:02:501076 ecc.IsEquivalentForSecureCookieMatching(*cc)) {
jww601411a2015-11-20 19:46:571077 skipped_secure_cookie = true;
Lily Chen22707642b2018-10-02 17:27:211078 cc_skipped_secure = cc;
jww31e32632015-12-16 23:38:341079 histogram_cookie_delete_equivalent_->Add(
1080 COOKIE_DELETE_EQUIVALENT_SKIPPING_SECURE);
Helen Licd0fab862018-08-13 16:07:531081 net_log_.AddEvent(
1082 NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_SECURE,
1083 base::BindRepeating(&NetLogCookieMonsterCookieRejectedSecure, cc,
1084 &ecc));
jww31e32632015-12-16 23:38:341085 // If the cookie is equivalent to the new cookie and wouldn't have been
1086 // skipped for being HTTP-only, record that it is a skipped secure cookie
1087 // that would have been deleted otherwise.
1088 if (ecc.IsEquivalent(*cc)) {
jwwa9a0d482015-12-16 18:19:411089 found_equivalent_cookie = true;
jww31e32632015-12-16 23:38:341090
1091 if (!skip_httponly || !cc->IsHttpOnly()) {
1092 histogram_cookie_delete_equivalent_->Add(
1093 COOKIE_DELETE_EQUIVALENT_WOULD_HAVE_DELETED);
1094 }
1095 }
jww601411a2015-11-20 19:46:571096 } else if (ecc.IsEquivalent(*cc)) {
[email protected]f48b9432011-01-11 07:25:401097 // We should never have more than one equivalent cookie, since they should
jww601411a2015-11-20 19:46:571098 // overwrite each other, unless secure cookies require secure scheme is
1099 // being enforced. In that case, cookies with different paths might exist
1100 // and be considered equivalent.
mkwstbe84af312015-02-20 08:52:451101 CHECK(!found_equivalent_cookie)
1102 << "Duplicate equivalent cookies found, cookie store is corrupted.";
Lily Chen22707642b2018-10-02 17:27:211103 DCHECK(cookie_it_to_possibly_delete == cookies_.end());
[email protected]f48b9432011-01-11 07:25:401104 if (skip_httponly && cc->IsHttpOnly()) {
1105 skipped_httponly = true;
Helen Licd0fab862018-08-13 16:07:531106 net_log_.AddEvent(
1107 NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_HTTPONLY,
1108 base::BindRepeating(&NetLogCookieMonsterCookieRejectedHttponly, cc,
1109 &ecc));
[email protected]f48b9432011-01-11 07:25:401110 } else {
Lily Chen22707642b2018-10-02 17:27:211111 cookie_it_to_possibly_delete = curit;
[email protected]f48b9432011-01-11 07:25:401112 }
1113 found_equivalent_cookie = true;
1114 }
1115 }
Lily Chen22707642b2018-10-02 17:27:211116
1117 if (cookie_it_to_possibly_delete != cookies_.end()) {
1118 CanonicalCookie* cc_to_possibly_delete =
1119 cookie_it_to_possibly_delete->second.get();
1120 // If a secure cookie was encountered (and left alone), don't actually
1121 // modify any of the pre-existing cookies. Only delete if no secure cookies
1122 // were skipped.
1123 if (!skipped_secure_cookie) {
1124 histogram_cookie_delete_equivalent_->Add(COOKIE_DELETE_EQUIVALENT_FOUND);
1125 if (cc_to_possibly_delete->Value() == ecc.Value()) {
1126 *creation_date_to_inherit = cc_to_possibly_delete->CreationDate();
1127 histogram_cookie_delete_equivalent_->Add(
1128 COOKIE_DELETE_EQUIVALENT_FOUND_WITH_SAME_VALUE);
1129 }
1130 InternalDeleteCookie(cookie_it_to_possibly_delete, true,
1131 already_expired ? DELETE_COOKIE_EXPIRED_OVERWRITE
1132 : DELETE_COOKIE_OVERWRITE);
1133 } else {
1134 // If any secure cookie was skipped, preserve the pre-existing cookie.
1135 DCHECK(cc_skipped_secure);
1136 net_log_.AddEvent(
1137 NetLogEventType::COOKIE_STORE_COOKIE_PRESERVED_SKIPPED_SECURE,
1138 base::BindRepeating(&NetLogCookieMonsterCookiePreservedSkippedSecure,
1139 cc_skipped_secure, cc_to_possibly_delete, &ecc));
1140 }
1141 }
1142
Aaron Tagliaboschi29764f52019-02-21 17:19:591143 if (skipped_httponly)
1144 return CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY;
1145
1146 if (skipped_secure_cookie)
1147 return CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE;
1148
1149 return CanonicalCookie::CookieInclusionStatus::INCLUDE;
[email protected]f48b9432011-01-11 07:25:401150}
1151
[email protected]6210ce52013-09-20 03:33:141152CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie(
1153 const std::string& key,
avie7cd11a2016-10-11 02:00:351154 std::unique_ptr<CanonicalCookie> cc,
[email protected]6210ce52013-09-20 03:33:141155 bool sync_to_store) {
mmenkebe0910d2016-03-01 19:09:091156 DCHECK(thread_checker_.CalledOnValidThread());
avie7cd11a2016-10-11 02:00:351157 CanonicalCookie* cc_ptr = cc.get();
mmenkebe0910d2016-03-01 19:09:091158
Helen Licd0fab862018-08-13 16:07:531159 net_log_.AddEvent(NetLogEventType::COOKIE_STORE_COOKIE_ADDED,
1160 base::BindRepeating(&NetLogCookieMonsterCookieAdded,
1161 cc.get(), sync_to_store));
avie7cd11a2016-10-11 02:00:351162 if ((cc_ptr->IsPersistent() || persist_session_cookies_) && store_.get() &&
Helen Lid84010b2018-08-22 16:27:441163 sync_to_store) {
avie7cd11a2016-10-11 02:00:351164 store_->AddCookie(*cc_ptr);
Helen Lid84010b2018-08-22 16:27:441165 }
jdoerrie22a91d8b92018-10-05 08:43:261166 auto inserted = cookies_.insert(CookieMap::value_type(key, std::move(cc)));
mkwstc1aa4cc2015-04-03 19:57:451167
1168 // See InitializeHistograms() for details.
Lily Chenf93d43e2019-04-18 20:22:021169 int32_t type_sample =
1170 cc_ptr->GetEffectiveSameSite() != CookieSameSite::NO_RESTRICTION
1171 ? 1 << COOKIE_TYPE_SAME_SITE
1172 : 0;
avie7cd11a2016-10-11 02:00:351173 type_sample |= cc_ptr->IsHttpOnly() ? 1 << COOKIE_TYPE_HTTPONLY : 0;
1174 type_sample |= cc_ptr->IsSecure() ? 1 << COOKIE_TYPE_SECURE : 0;
mkwst46549412016-02-01 10:05:371175 histogram_cookie_type_->Add(type_sample);
estark7feb65c2b2015-08-21 23:38:201176
Victor Costan14f47c12018-03-01 08:02:241177 change_dispatcher_.DispatchChange(*cc_ptr, CookieChangeCause::INSERTED, true);
[email protected]6210ce52013-09-20 03:33:141178
1179 return inserted;
[email protected]f48b9432011-01-11 07:25:401180}
1181
rdsmithe5c701d2017-07-12 21:50:001182void CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc,
Maks Orlovich44525ce2019-02-25 14:17:581183 std::string source_scheme,
Maks Orlovichfdbc8be2019-03-18 18:34:521184 const CookieOptions& options,
rdsmithe5c701d2017-07-12 21:50:001185 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:091186 DCHECK(thread_checker_.CalledOnValidThread());
1187
Maks Orlovich44525ce2019-02-25 14:17:581188 std::string scheme_lower = base::ToLowerASCII(source_scheme);
1189 bool secure_source = GURL::SchemeIsCryptographic(scheme_lower);
Aaron Tagliaboschi29764f52019-02-21 17:19:591190 if ((cc->IsSecure() && !secure_source)) {
1191 MaybeRunCookieCallback(
1192 std::move(callback),
1193 CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY);
1194 return;
1195 }
1196
Maks Orlovichfdbc8be2019-03-18 18:34:521197 if (cc->IsHttpOnly() && options.exclude_httponly()) {
Aaron Tagliaboschi29764f52019-02-21 17:19:591198 MaybeRunCookieCallback(
1199 std::move(callback),
1200 CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY);
rdsmithe5c701d2017-07-12 21:50:001201 return;
1202 }
rdsmith2709eee2017-06-20 22:43:271203
Maks Orlovich44525ce2019-02-25 14:17:581204 if (!IsCookieableScheme(scheme_lower)) {
1205 MaybeRunCookieCallback(
1206 std::move(callback),
1207 CanonicalCookie::CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME);
1208 return;
1209 }
1210
mmenkeea4cd402016-02-02 04:03:101211 const std::string key(GetKey(cc->Domain()));
rdsmitha6ce4442017-06-21 17:11:051212
rdsmitha6ce4442017-06-21 17:11:051213 base::Time creation_date = cc->CreationDate();
1214 if (creation_date.is_null()) {
Maks Orlovichc86cf292019-02-11 19:25:171215 creation_date = Time::Now();
rdsmitha6ce4442017-06-21 17:11:051216 cc->SetCreationDate(creation_date);
rdsmitha6ce4442017-06-21 17:11:051217 }
1218 bool already_expired = cc->IsExpired(creation_date);
ellyjones399e35a22014-10-27 11:09:561219
Mike Westc4a777b2017-10-06 14:04:201220 base::Time creation_date_to_inherit;
Aaron Tagliaboschi29764f52019-02-21 17:19:591221
Maks Orlovichfdbc8be2019-03-18 18:34:521222 CanonicalCookie::CookieInclusionStatus status = DeleteAnyEquivalentCookie(
1223 key, *cc, secure_source, options.exclude_httponly(), already_expired,
1224 &creation_date_to_inherit);
Aaron Tagliaboschi29764f52019-02-21 17:19:591225
1226 if (status != CanonicalCookie::CookieInclusionStatus::INCLUDE) {
jww601411a2015-11-20 19:46:571227 std::string error;
jwwa26e439d2017-01-27 18:17:271228 error =
1229 "SetCookie() not clobbering httponly cookie or secure cookie for "
1230 "insecure scheme";
jww601411a2015-11-20 19:46:571231
Maks Orlovich35d74c042019-04-18 16:38:011232 DVLOG(net::cookie_util::kVlogSetCookies) << error;
Aaron Tagliaboschi29764f52019-02-21 17:19:591233 MaybeRunCookieCallback(std::move(callback), status);
rdsmithe5c701d2017-07-12 21:50:001234 return;
[email protected]3a96c742008-11-19 19:46:271235 }
initial.commit586acc5fe2008-07-26 22:42:521236
Maks Orlovich35d74c042019-04-18 16:38:011237 DVLOG(net::cookie_util::kVlogSetCookies)
Oscar Johansson63e83cf2018-07-02 08:47:261238 << "SetCookie() key: " << key << " cc: " << cc->DebugString();
initial.commit586acc5fe2008-07-26 22:42:521239
1240 // Realize that we might be setting an expired cookie, and the only point
1241 // was to delete the cookie which we've already done.
mmenke3c79a652016-02-12 14:39:201242 if (!already_expired) {
[email protected]374f58b2010-07-20 15:29:261243 // See InitializeHistograms() for details.
mmenkeea4cd402016-02-02 04:03:101244 if (cc->IsPersistent()) {
[email protected]8475bee2011-03-17 18:40:241245 histogram_expiration_duration_minutes_->Add(
rdsmitha6ce4442017-06-21 17:11:051246 (cc->ExpiryDate() - creation_date).InMinutes());
[email protected]8475bee2011-03-17 18:40:241247 }
1248
rdsmith2709eee2017-06-20 22:43:271249 // Histogram the type of scheme used on URLs that set cookies. This
1250 // intentionally includes cookies that are set or overwritten by
1251 // http:// URLs, but not cookies that are cleared by http:// URLs, to
1252 // understand if the former behavior can be deprecated for Secure
1253 // cookies.
1254 CookieSource cookie_source_sample =
1255 (secure_source
1256 ? (cc->IsSecure()
1257 ? COOKIE_SOURCE_SECURE_COOKIE_CRYPTOGRAPHIC_SCHEME
1258 : COOKIE_SOURCE_NONSECURE_COOKIE_CRYPTOGRAPHIC_SCHEME)
1259 : (cc->IsSecure()
1260 ? COOKIE_SOURCE_SECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME
1261 : COOKIE_SOURCE_NONSECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME));
1262 histogram_cookie_source_scheme_->Add(cookie_source_sample);
1263
Mike Westc4a777b2017-10-06 14:04:201264 if (!creation_date_to_inherit.is_null()) {
1265 cc->SetCreationDate(creation_date_to_inherit);
Mike Westc4a777b2017-10-06 14:04:201266 }
1267
rdsmith2709eee2017-06-20 22:43:271268 InternalInsertCookie(key, std::move(cc), true);
[email protected]348dd662013-03-13 20:25:071269 } else {
Maks Orlovich35d74c042019-04-18 16:38:011270 DVLOG(net::cookie_util::kVlogSetCookies)
Oscar Johansson63e83cf2018-07-02 08:47:261271 << "SetCookie() not storing already expired cookie.";
[email protected]c4058fb2010-06-22 17:25:261272 }
initial.commit586acc5fe2008-07-26 22:42:521273
1274 // We assume that hopefully setting a cookie will be less common than
1275 // querying a cookie. Since setting a cookie can put us over our limits,
1276 // make sure that we garbage collect... We can also make the assumption that
1277 // if a cookie was set, in the common case it will be used soon after,
1278 // and we will purge the expired cookies in GetCookies().
rdsmitha6ce4442017-06-21 17:11:051279 GarbageCollect(creation_date, key);
initial.commit586acc5fe2008-07-26 22:42:521280
Aaron Tagliaboschi29764f52019-02-21 17:19:591281 MaybeRunCookieCallback(std::move(callback),
1282 CanonicalCookie::CookieInclusionStatus::INCLUDE);
initial.commit586acc5fe2008-07-26 22:42:521283}
1284
rdsmithe5c701d2017-07-12 21:50:001285void CookieMonster::SetAllCookies(CookieList list,
1286 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:091287 DCHECK(thread_checker_.CalledOnValidThread());
rdsmithe5c701d2017-07-12 21:50:001288
rdsmith0e84cea2017-07-13 03:09:531289 // Nuke the existing store.
1290 while (!cookies_.empty()) {
1291 // TODO(rdsmith): The CANONICAL is a lie.
Nick Harper7a6683a2018-01-30 20:42:521292 InternalDeleteCookie(cookies_.begin(), true, DELETE_COOKIE_EXPLICIT);
rdsmithe5c701d2017-07-12 21:50:001293 }
1294
rdsmith0e84cea2017-07-13 03:09:531295 // Set all passed in cookies.
mmenkeea4cd402016-02-02 04:03:101296 for (const auto& cookie : list) {
rdsmith2709eee2017-06-20 22:43:271297 const std::string key(GetKey(cookie.Domain()));
1298 Time creation_time = cookie.CreationDate();
rdsmith0e84cea2017-07-13 03:09:531299 if (cookie.IsExpired(creation_time))
rdsmith2709eee2017-06-20 22:43:271300 continue;
1301
1302 if (cookie.IsPersistent()) {
1303 histogram_expiration_duration_minutes_->Add(
1304 (cookie.ExpiryDate() - creation_time).InMinutes());
mmenkeea4cd402016-02-02 04:03:101305 }
rdsmith2709eee2017-06-20 22:43:271306
Jeremy Roman0579ed62017-08-29 15:56:191307 InternalInsertCookie(key, std::make_unique<CanonicalCookie>(cookie), true);
rdsmith2709eee2017-06-20 22:43:271308 GarbageCollect(creation_time, key);
drogerd5d1278c2015-03-17 19:21:511309 }
1310
rdsmith2709eee2017-06-20 22:43:271311 // TODO(rdsmith): If this function always returns the same value, it
1312 // shouldn't have a return value. But it should also be deleted (see
1313 // https://codereview.chromium.org/2882063002/#msg64), which would
1314 // solve the return value problem.
Aaron Tagliaboschi29764f52019-02-21 17:19:591315 MaybeRunCookieCallback(std::move(callback),
1316 CanonicalCookie::CookieInclusionStatus::INCLUDE);
drogerd5d1278c2015-03-17 19:21:511317}
1318
[email protected]7a964a72010-09-07 19:33:261319void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc,
1320 const Time& current) {
mmenkebe0910d2016-03-01 19:09:091321 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041322
[email protected]77e0a462008-11-01 00:43:351323 // Based off the Mozilla code. When a cookie has been accessed recently,
1324 // don't bother updating its access time again. This reduces the number of
1325 // updates we do during pageload, which in turn reduces the chance our storage
1326 // backend will hit its batch thresholds and be forced to update.
[email protected]77e0a462008-11-01 00:43:351327 if ((current - cc->LastAccessDate()) < last_access_threshold_)
1328 return;
1329
1330 cc->SetLastAccessDate(current);
[email protected]90499482013-06-01 00:39:501331 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get())
[email protected]77e0a462008-11-01 00:43:351332 store_->UpdateCookieAccessTime(*cc);
1333}
1334
[email protected]6210ce52013-09-20 03:33:141335// InternalDeleteCookies must not invalidate iterators other than the one being
1336// deleted.
initial.commit586acc5fe2008-07-26 22:42:521337void CookieMonster::InternalDeleteCookie(CookieMap::iterator it,
[email protected]c4058fb2010-06-22 17:25:261338 bool sync_to_store,
1339 DeletionCause deletion_cause) {
mmenkebe0910d2016-03-01 19:09:091340 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041341
nharper352933e2016-09-30 18:24:571342 // Ideally, this would be asserted up where we define kChangeCauseMapping,
[email protected]8bb846f2011-03-23 12:08:181343 // but DeletionCause's visibility (or lack thereof) forces us to make
1344 // this check here.
Ryan Sleevi435a3a22018-05-15 02:16:071345 static_assert(base::size(kChangeCauseMapping) == DELETE_COOKIE_LAST_ENTRY + 1,
nharper352933e2016-09-30 18:24:571346 "kChangeCauseMapping size should match DeletionCause size");
[email protected]8bb846f2011-03-23 12:08:181347
avie7cd11a2016-10-11 02:00:351348 CanonicalCookie* cc = it->second.get();
Maks Orlovich35d74c042019-04-18 16:38:011349 DVLOG(net::cookie_util::kVlogSetCookies)
Oscar Johansson63e83cf2018-07-02 08:47:261350 << "InternalDeleteCookie()"
1351 << ", cause:" << deletion_cause << ", cc: " << cc->DebugString();
[email protected]7a964a72010-09-07 19:33:261352
Helen Licd0fab862018-08-13 16:07:531353 ChangeCausePair mapping = kChangeCauseMapping[deletion_cause];
1354 if (deletion_cause != DELETE_COOKIE_DONT_RECORD) {
1355 net_log_.AddEvent(NetLogEventType::COOKIE_STORE_COOKIE_DELETED,
1356 base::BindRepeating(&NetLogCookieMonsterCookieDeleted, cc,
1357 mapping.cause, sync_to_store));
1358 }
1359
[email protected]90499482013-06-01 00:39:501360 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get() &&
Helen Lid84010b2018-08-22 16:27:441361 sync_to_store) {
initial.commit586acc5fe2008-07-26 22:42:521362 store_->DeleteCookie(*cc);
Helen Lid84010b2018-08-22 16:27:441363 }
Victor Costan14f47c12018-03-01 08:02:241364 change_dispatcher_.DispatchChange(*cc, mapping.cause, mapping.notify);
initial.commit586acc5fe2008-07-26 22:42:521365 cookies_.erase(it);
initial.commit586acc5fe2008-07-26 22:42:521366}
1367
[email protected]8807b322010-10-01 17:10:141368// Domain expiry behavior is unchanged by key/expiry scheme (the
[email protected]8ad5d462013-05-02 08:45:261369// meaning of the key is different, but that's not visible to this routine).
jww82d99c12015-11-25 18:39:531370size_t CookieMonster::GarbageCollect(const Time& current,
jwwa26e439d2017-01-27 18:17:271371 const std::string& key) {
mmenkebe0910d2016-03-01 19:09:091372 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041373
jww82d99c12015-11-25 18:39:531374 size_t num_deleted = 0;
mkwstbe84af312015-02-20 08:52:451375 Time safe_date(Time::Now() - TimeDelta::FromDays(kSafeFromGlobalPurgeDays));
initial.commit586acc5fe2008-07-26 22:42:521376
[email protected]8ad5d462013-05-02 08:45:261377 // Collect garbage for this key, minding cookie priorities.
[email protected]7a964a72010-09-07 19:33:261378 if (cookies_.count(key) > kDomainMaxCookies) {
Maks Orlovich35d74c042019-04-18 16:38:011379 DVLOG(net::cookie_util::kVlogGarbageCollection)
Oscar Johansson63e83cf2018-07-02 08:47:261380 << "GarbageCollect() key: " << key;
[email protected]7a964a72010-09-07 19:33:261381
mkwst87734352016-03-03 17:36:231382 CookieItVector* cookie_its;
jww601411a2015-11-20 19:46:571383
mkwst87734352016-03-03 17:36:231384 CookieItVector non_expired_cookie_its;
1385 cookie_its = &non_expired_cookie_its;
jww82d99c12015-11-25 18:39:531386 num_deleted +=
mkwst87734352016-03-03 17:36:231387 GarbageCollectExpired(current, cookies_.equal_range(key), cookie_its);
jww82d99c12015-11-25 18:39:531388
mkwst87734352016-03-03 17:36:231389 if (cookie_its->size() > kDomainMaxCookies) {
Maks Orlovich35d74c042019-04-18 16:38:011390 DVLOG(net::cookie_util::kVlogGarbageCollection)
Oscar Johansson63e83cf2018-07-02 08:47:261391 << "Deep Garbage Collect domain.";
[email protected]8ad5d462013-05-02 08:45:261392 size_t purge_goal =
mkwst87734352016-03-03 17:36:231393 cookie_its->size() - (kDomainMaxCookies - kDomainPurgeCookies);
[email protected]8ad5d462013-05-02 08:45:261394 DCHECK(purge_goal > kDomainPurgeCookies);
1395
mkwste079ac412016-03-11 09:04:061396 // Sort the cookies by access date, from least-recent to most-recent.
1397 std::sort(cookie_its->begin(), cookie_its->end(), LRACookieSorter);
[email protected]8ad5d462013-05-02 08:45:261398
mkwste079ac412016-03-11 09:04:061399 // Remove all but the kDomainCookiesQuotaLow most-recently accessed
1400 // cookies with low-priority. Then, if cookies still need to be removed,
1401 // bump the quota and remove low- and medium-priority. Then, if cookies
1402 // _still_ need to be removed, bump the quota and remove cookies with
1403 // any priority.
jwwc00ac712016-05-05 22:21:441404 //
1405 // 1. Low-priority non-secure cookies.
1406 // 2. Low-priority secure cookies.
1407 // 3. Medium-priority non-secure cookies.
1408 // 4. High-priority non-secure cookies.
1409 // 5. Medium-priority secure cookies.
1410 // 6. High-priority secure cookies.
1411 const static struct {
1412 CookiePriority priority;
1413 bool protect_secure_cookies;
1414 } purge_rounds[] = {
1415 // 1. Low-priority non-secure cookies.
1416 {COOKIE_PRIORITY_LOW, true},
1417 // 2. Low-priority secure cookies.
1418 {COOKIE_PRIORITY_LOW, false},
1419 // 3. Medium-priority non-secure cookies.
1420 {COOKIE_PRIORITY_MEDIUM, true},
1421 // 4. High-priority non-secure cookies.
1422 {COOKIE_PRIORITY_HIGH, true},
1423 // 5. Medium-priority secure cookies.
1424 {COOKIE_PRIORITY_MEDIUM, false},
1425 // 6. High-priority secure cookies.
1426 {COOKIE_PRIORITY_HIGH, false},
1427 };
1428
mkwste079ac412016-03-11 09:04:061429 size_t quota = 0;
jwwc00ac712016-05-05 22:21:441430 for (const auto& purge_round : purge_rounds) {
mmenke645ca6772016-06-17 18:46:431431 // Adjust quota according to the priority of cookies. Each round should
1432 // protect certain number of cookies in order to avoid starvation.
1433 // For example, when each round starts to remove cookies, the number of
1434 // cookies of that priority are counted and a decision whether they
1435 // should be deleted or not is made. If yes, some number of cookies of
1436 // that priority are deleted considering the quota.
jwwc00ac712016-05-05 22:21:441437 switch (purge_round.priority) {
1438 case COOKIE_PRIORITY_LOW:
mmenke645ca6772016-06-17 18:46:431439 quota = kDomainCookiesQuotaLow;
jwwc00ac712016-05-05 22:21:441440 break;
1441 case COOKIE_PRIORITY_MEDIUM:
mmenke645ca6772016-06-17 18:46:431442 quota = kDomainCookiesQuotaMedium;
jwwc00ac712016-05-05 22:21:441443 break;
1444 case COOKIE_PRIORITY_HIGH:
mmenke645ca6772016-06-17 18:46:431445 quota = kDomainCookiesQuotaHigh;
jwwc00ac712016-05-05 22:21:441446 break;
1447 }
jwwc00ac712016-05-05 22:21:441448 size_t just_deleted = 0u;
jwwa26e439d2017-01-27 18:17:271449 // Purge up to |purge_goal| for all cookies at the given priority. This
1450 // path will be taken only if the initial non-secure purge did not evict
1451 // enough cookies.
jwwc00ac712016-05-05 22:21:441452 if (purge_goal > 0) {
1453 just_deleted = PurgeLeastRecentMatches(
1454 cookie_its, purge_round.priority, quota, purge_goal,
1455 purge_round.protect_secure_cookies);
1456 DCHECK_LE(just_deleted, purge_goal);
1457 purge_goal -= just_deleted;
1458 num_deleted += just_deleted;
1459 }
mkwst162d2712016-02-18 18:21:291460 }
mkwste079ac412016-03-11 09:04:061461
jwwc00ac712016-05-05 22:21:441462 DCHECK_EQ(0u, purge_goal);
[email protected]8807b322010-10-01 17:10:141463 }
initial.commit586acc5fe2008-07-26 22:42:521464 }
1465
[email protected]8ad5d462013-05-02 08:45:261466 // Collect garbage for everything. With firefox style we want to preserve
1467 // cookies accessed in kSafeFromGlobalPurgeDays, otherwise evict.
mkwstbe84af312015-02-20 08:52:451468 if (cookies_.size() > kMaxCookies && earliest_access_time_ < safe_date) {
Maks Orlovich35d74c042019-04-18 16:38:011469 DVLOG(net::cookie_util::kVlogGarbageCollection)
Oscar Johansson63e83cf2018-07-02 08:47:261470 << "GarbageCollect() everything";
[email protected]8ad5d462013-05-02 08:45:261471 CookieItVector cookie_its;
jww82d99c12015-11-25 18:39:531472
[email protected]7a964a72010-09-07 19:33:261473 num_deleted += GarbageCollectExpired(
1474 current, CookieMapItPair(cookies_.begin(), cookies_.end()),
1475 &cookie_its);
jww82d99c12015-11-25 18:39:531476
[email protected]8ad5d462013-05-02 08:45:261477 if (cookie_its.size() > kMaxCookies) {
Maks Orlovich35d74c042019-04-18 16:38:011478 DVLOG(net::cookie_util::kVlogGarbageCollection)
Oscar Johansson63e83cf2018-07-02 08:47:261479 << "Deep Garbage Collect everything.";
[email protected]8ad5d462013-05-02 08:45:261480 size_t purge_goal = cookie_its.size() - (kMaxCookies - kPurgeCookies);
1481 DCHECK(purge_goal > kPurgeCookies);
jww82d99c12015-11-25 18:39:531482
jwwa26e439d2017-01-27 18:17:271483 CookieItVector secure_cookie_its;
1484 CookieItVector non_secure_cookie_its;
1485 SplitCookieVectorIntoSecureAndNonSecure(cookie_its, &secure_cookie_its,
1486 &non_secure_cookie_its);
1487 size_t non_secure_purge_goal =
mmenkef4721d992017-06-07 17:13:591488 std::min<size_t>(purge_goal, non_secure_cookie_its.size());
jww82d99c12015-11-25 18:39:531489
mmenkef4721d992017-06-07 17:13:591490 base::Time earliest_non_secure_access_time;
jwwa26e439d2017-01-27 18:17:271491 size_t just_deleted = GarbageCollectLeastRecentlyAccessed(
mmenkef4721d992017-06-07 17:13:591492 current, safe_date, non_secure_purge_goal, non_secure_cookie_its,
1493 &earliest_non_secure_access_time);
jwwa26e439d2017-01-27 18:17:271494 num_deleted += just_deleted;
jww82d99c12015-11-25 18:39:531495
mmenkef4721d992017-06-07 17:13:591496 if (secure_cookie_its.size() == 0) {
1497 // This case is unlikely, but should still update
1498 // |earliest_access_time_| if only have non-secure cookies.
1499 earliest_access_time_ = earliest_non_secure_access_time;
1500 // Garbage collection can't delete all cookies.
1501 DCHECK(!earliest_access_time_.is_null());
1502 } else if (just_deleted < purge_goal) {
1503 size_t secure_purge_goal = std::min<size_t>(purge_goal - just_deleted,
1504 secure_cookie_its.size());
1505 base::Time earliest_secure_access_time;
jww82d99c12015-11-25 18:39:531506 num_deleted += GarbageCollectLeastRecentlyAccessed(
mmenkef4721d992017-06-07 17:13:591507 current, safe_date, secure_purge_goal, secure_cookie_its,
1508 &earliest_secure_access_time);
1509
1510 if (!earliest_non_secure_access_time.is_null() &&
1511 earliest_non_secure_access_time < earliest_secure_access_time) {
1512 earliest_access_time_ = earliest_non_secure_access_time;
1513 } else {
1514 earliest_access_time_ = earliest_secure_access_time;
1515 }
1516
1517 // Garbage collection can't delete all cookies.
1518 DCHECK(!earliest_access_time_.is_null());
jww82d99c12015-11-25 18:39:531519 }
mmenkef4721d992017-06-07 17:13:591520
1521 // If there are secure cookies, but deleting non-secure cookies was enough
1522 // to meet the purge goal, secure cookies are never examined, so
1523 // |earliest_access_time_| can't be determined. Leaving it alone will mean
1524 // it's no later than the real earliest last access time, so this won't
1525 // lead to any problems.
[email protected]8807b322010-10-01 17:10:141526 }
[email protected]c890ed192008-10-30 23:45:531527 }
1528
1529 return num_deleted;
1530}
1531
mkwste079ac412016-03-11 09:04:061532size_t CookieMonster::PurgeLeastRecentMatches(CookieItVector* cookies,
1533 CookiePriority priority,
1534 size_t to_protect,
jwwc00ac712016-05-05 22:21:441535 size_t purge_goal,
1536 bool protect_secure_cookies) {
mkwste079ac412016-03-11 09:04:061537 DCHECK(thread_checker_.CalledOnValidThread());
1538
mmenke645ca6772016-06-17 18:46:431539 // 1. Count number of the cookies at |priority|
1540 size_t cookies_count_possibly_to_be_deleted = CountCookiesForPossibleDeletion(
1541 priority, cookies, false /* count all cookies */);
1542
1543 // 2. If |cookies_count_possibly_to_be_deleted| at |priority| is less than or
1544 // equal |to_protect|, skip round in order to preserve the quota. This
1545 // involves secure and non-secure cookies at |priority|.
1546 if (cookies_count_possibly_to_be_deleted <= to_protect)
1547 return 0u;
1548
1549 // 3. Calculate number of secure cookies at |priority|
1550 // and number of cookies at |priority| that can possibly be deleted.
1551 // It is guaranteed we do not delete more than |purge_goal| even if
1552 // |cookies_count_possibly_to_be_deleted| is higher.
1553 size_t secure_cookies = 0u;
jwwc00ac712016-05-05 22:21:441554 if (protect_secure_cookies) {
mmenke645ca6772016-06-17 18:46:431555 secure_cookies = CountCookiesForPossibleDeletion(
1556 priority, cookies, protect_secure_cookies /* count secure cookies */);
1557 cookies_count_possibly_to_be_deleted -=
1558 std::max(secure_cookies, to_protect - secure_cookies);
1559 } else {
1560 cookies_count_possibly_to_be_deleted -= to_protect;
jwwc00ac712016-05-05 22:21:441561 }
1562
mmenke645ca6772016-06-17 18:46:431563 size_t removed = 0u;
1564 size_t current = 0u;
1565 while ((removed < purge_goal && current < cookies->size()) &&
1566 cookies_count_possibly_to_be_deleted > 0) {
avie7cd11a2016-10-11 02:00:351567 const CanonicalCookie* current_cookie = cookies->at(current)->second.get();
mmenke645ca6772016-06-17 18:46:431568 // Only delete the current cookie if the priority is equal to
1569 // the current level.
jwwc00ac712016-05-05 22:21:441570 if (IsCookieEligibleForEviction(priority, protect_secure_cookies,
1571 current_cookie)) {
mkwstaa07ee82016-03-11 15:32:141572 InternalDeleteCookie(cookies->at(current), true,
1573 DELETE_COOKIE_EVICTED_DOMAIN);
mkwste079ac412016-03-11 09:04:061574 cookies->erase(cookies->begin() + current);
1575 removed++;
mmenke645ca6772016-06-17 18:46:431576 cookies_count_possibly_to_be_deleted--;
mkwste079ac412016-03-11 09:04:061577 } else {
1578 current++;
1579 }
1580 }
1581 return removed;
1582}
1583
jww82d99c12015-11-25 18:39:531584size_t CookieMonster::GarbageCollectExpired(const Time& current,
1585 const CookieMapItPair& itpair,
1586 CookieItVector* cookie_its) {
mmenkebe0910d2016-03-01 19:09:091587 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041588
[email protected]c890ed192008-10-30 23:45:531589 int num_deleted = 0;
1590 for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) {
jdoerrie22a91d8b92018-10-05 08:43:261591 auto curit = it;
[email protected]c890ed192008-10-30 23:45:531592 ++it;
1593
1594 if (curit->second->IsExpired(current)) {
[email protected]2f3f3592010-07-07 20:11:511595 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
[email protected]c890ed192008-10-30 23:45:531596 ++num_deleted;
1597 } else if (cookie_its) {
1598 cookie_its->push_back(curit);
1599 }
initial.commit586acc5fe2008-07-26 22:42:521600 }
1601
1602 return num_deleted;
1603}
1604
jww82d99c12015-11-25 18:39:531605size_t CookieMonster::GarbageCollectDeleteRange(
1606 const Time& current,
1607 DeletionCause cause,
1608 CookieItVector::iterator it_begin,
1609 CookieItVector::iterator it_end) {
mmenkebe0910d2016-03-01 19:09:091610 DCHECK(thread_checker_.CalledOnValidThread());
1611
jdoerrie22a91d8b92018-10-05 08:43:261612 for (auto it = it_begin; it != it_end; it++) {
[email protected]8ad5d462013-05-02 08:45:261613 InternalDeleteCookie((*it), true, cause);
[email protected]c10da4b02010-03-25 14:38:321614 }
[email protected]8ad5d462013-05-02 08:45:261615 return it_end - it_begin;
[email protected]c10da4b02010-03-25 14:38:321616}
1617
mmenke74bcbd52016-01-21 17:17:561618size_t CookieMonster::GarbageCollectLeastRecentlyAccessed(
1619 const base::Time& current,
1620 const base::Time& safe_date,
1621 size_t purge_goal,
mmenkef4721d992017-06-07 17:13:591622 CookieItVector cookie_its,
1623 base::Time* earliest_time) {
1624 DCHECK_LE(purge_goal, cookie_its.size());
mmenkebe0910d2016-03-01 19:09:091625 DCHECK(thread_checker_.CalledOnValidThread());
1626
mmenkef4721d992017-06-07 17:13:591627 // Sorts up to *and including* |cookie_its[purge_goal]| (if it exists), so
1628 // |earliest_time| will be properly assigned even if
mmenke74bcbd52016-01-21 17:17:561629 // |global_purge_it| == |cookie_its.begin() + purge_goal|.
mmenkef4721d992017-06-07 17:13:591630 SortLeastRecentlyAccessed(
1631 cookie_its.begin(), cookie_its.end(),
1632 cookie_its.size() < purge_goal ? purge_goal + 1 : purge_goal);
mmenke74bcbd52016-01-21 17:17:561633 // Find boundary to cookies older than safe_date.
jdoerrie22a91d8b92018-10-05 08:43:261634 auto global_purge_it = LowerBoundAccessDate(
mmenke74bcbd52016-01-21 17:17:561635 cookie_its.begin(), cookie_its.begin() + purge_goal, safe_date);
jwwa26e439d2017-01-27 18:17:271636 // Only delete the old cookies and delete non-secure ones first.
mmenke74bcbd52016-01-21 17:17:561637 size_t num_deleted =
1638 GarbageCollectDeleteRange(current, DELETE_COOKIE_EVICTED_GLOBAL,
1639 cookie_its.begin(), global_purge_it);
mmenkef4721d992017-06-07 17:13:591640 if (global_purge_it != cookie_its.end())
1641 *earliest_time = (*global_purge_it)->second->LastAccessDate();
mmenke74bcbd52016-01-21 17:17:561642 return num_deleted;
1643}
1644
[email protected]ed32c212013-05-14 20:49:291645// A wrapper around registry_controlled_domains::GetDomainAndRegistry
Maks Orlovich323efaf2018-03-06 02:56:391646// to make clear we're creating a key for our local map or for the persistent
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521647// store's use. Here and in FindCookiesForRegistryControlledHost() are the only
1648// two places where we need to conditionalize based on key type.
[email protected]f48b9432011-01-11 07:25:401649//
1650// Note that this key algorithm explicitly ignores the scheme. This is
1651// because when we're entering cookies into the map from the backing store,
1652// we in general won't have the scheme at that point.
1653// In practical terms, this means that file cookies will be stored
1654// in the map either by an empty string or by UNC name (and will be
1655// limited by kMaxCookiesPerHost), and extension cookies will be stored
1656// based on the single extension id, as the extension id won't have the
1657// form of a DNS host and hence GetKey() will return it unchanged.
1658//
1659// Arguably the right thing to do here is to make the key
1660// algorithm dependent on the scheme, and make sure that the scheme is
1661// available everywhere the key must be obtained (specfically at backing
1662// store load time). This would require either changing the backing store
1663// database schema to include the scheme (far more trouble than it's worth), or
1664// separating out file cookies into their own CookieMonster instance and
1665// thus restricting each scheme to a single cookie monster (which might
1666// be worth it, but is still too much trouble to solve what is currently a
1667// non-problem).
Maks Orlovich323efaf2018-03-06 02:56:391668//
1669// static
1670std::string CookieMonster::GetKey(base::StringPiece domain) {
[email protected]f48b9432011-01-11 07:25:401671 std::string effective_domain(
[email protected]ed32c212013-05-14 20:49:291672 registry_controlled_domains::GetDomainAndRegistry(
[email protected]aabe1792014-01-30 21:37:461673 domain, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES));
[email protected]f48b9432011-01-11 07:25:401674 if (effective_domain.empty())
Maks Orlovich323efaf2018-03-06 02:56:391675 domain.CopyToString(&effective_domain);
[email protected]f48b9432011-01-11 07:25:401676
1677 if (!effective_domain.empty() && effective_domain[0] == '.')
1678 return effective_domain.substr(1);
1679 return effective_domain;
1680}
1681
1682bool CookieMonster::HasCookieableScheme(const GURL& url) {
mmenkebe0910d2016-03-01 19:09:091683 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401684
1685 // Make sure the request is on a cookie-able url scheme.
1686 for (size_t i = 0; i < cookieable_schemes_.size(); ++i) {
1687 // We matched a scheme.
1688 if (url.SchemeIs(cookieable_schemes_[i].c_str())) {
1689 // We've matched a supported scheme.
initial.commit586acc5fe2008-07-26 22:42:521690 return true;
1691 }
1692 }
[email protected]f48b9432011-01-11 07:25:401693
1694 // The scheme didn't match any in our whitelist.
Maks Orlovich35d74c042019-04-18 16:38:011695 DVLOG(net::cookie_util::kVlogPerCookieMonster)
mkwstbe84af312015-02-20 08:52:451696 << "WARNING: Unsupported cookie scheme: " << url.scheme();
initial.commit586acc5fe2008-07-26 22:42:521697 return false;
1698}
1699
[email protected]c4058fb2010-06-22 17:25:261700// Test to see if stats should be recorded, and record them if so.
1701// The goal here is to get sampling for the average browser-hour of
1702// activity. We won't take samples when the web isn't being surfed,
1703// and when the web is being surfed, we'll take samples about every
1704// kRecordStatisticsIntervalSeconds.
1705// last_statistic_record_time_ is initialized to Now() rather than null
1706// in the constructor so that we won't take statistics right after
1707// startup, to avoid bias from browsers that are started but not used.
1708void CookieMonster::RecordPeriodicStats(const base::Time& current_time) {
mmenkebe0910d2016-03-01 19:09:091709 DCHECK(thread_checker_.CalledOnValidThread());
1710
[email protected]c4058fb2010-06-22 17:25:261711 const base::TimeDelta kRecordStatisticsIntervalTime(
1712 base::TimeDelta::FromSeconds(kRecordStatisticsIntervalSeconds));
1713
[email protected]7a964a72010-09-07 19:33:261714 // If we've taken statistics recently, return.
1715 if (current_time - last_statistic_record_time_ <=
[email protected]c4058fb2010-06-22 17:25:261716 kRecordStatisticsIntervalTime) {
[email protected]7a964a72010-09-07 19:33:261717 return;
[email protected]c4058fb2010-06-22 17:25:261718 }
[email protected]7a964a72010-09-07 19:33:261719
1720 // See InitializeHistograms() for details.
1721 histogram_count_->Add(cookies_.size());
1722
1723 // More detailed statistics on cookie counts at different granularities.
[email protected]7a964a72010-09-07 19:33:261724 last_statistic_record_time_ = current_time;
[email protected]c4058fb2010-06-22 17:25:261725}
1726
[email protected]f48b9432011-01-11 07:25:401727// Initialize all histogram counter variables used in this class.
1728//
1729// Normal histogram usage involves using the macros defined in
1730// histogram.h, which automatically takes care of declaring these
1731// variables (as statics), initializing them, and accumulating into
1732// them, all from a single entry point. Unfortunately, that solution
1733// doesn't work for the CookieMonster, as it's vulnerable to races between
1734// separate threads executing the same functions and hence initializing the
1735// same static variables. There isn't a race danger in the histogram
1736// accumulation calls; they are written to be resilient to simultaneous
1737// calls from multiple threads.
1738//
1739// The solution taken here is to have per-CookieMonster instance
1740// variables that are constructed during CookieMonster construction.
1741// Note that these variables refer to the same underlying histogram,
1742// so we still race (but safely) with other CookieMonster instances
1743// for accumulation.
1744//
1745// To do this we've expanded out the individual histogram macros calls,
1746// with declarations of the variables in the class decl, initialization here
1747// (done from the class constructor) and direct calls to the accumulation
1748// methods where needed. The specific histogram macro calls on which the
1749// initialization is based are included in comments below.
1750void CookieMonster::InitializeHistograms() {
mmenkebe0910d2016-03-01 19:09:091751 DCHECK(thread_checker_.CalledOnValidThread());
1752
[email protected]f48b9432011-01-11 07:25:401753 // From UMA_HISTOGRAM_CUSTOM_COUNTS
1754 histogram_expiration_duration_minutes_ = base::Histogram::FactoryGet(
mkwstbe84af312015-02-20 08:52:451755 "Cookie.ExpirationDurationMinutes", 1, kMinutesInTenYears, 50,
[email protected]f48b9432011-01-11 07:25:401756 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401757 histogram_count_ = base::Histogram::FactoryGet(
mkwstbe84af312015-02-20 08:52:451758 "Cookie.Count", 1, 4000, 50, base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401759
1760 // From UMA_HISTOGRAM_ENUMERATION
mkwstc1aa4cc2015-04-03 19:57:451761 histogram_cookie_type_ = base::LinearHistogram::FactoryGet(
mkwst87378d92015-04-10 21:22:111762 "Cookie.Type", 1, (1 << COOKIE_TYPE_LAST_ENTRY) - 1,
1763 1 << COOKIE_TYPE_LAST_ENTRY, base::Histogram::kUmaTargetedHistogramFlag);
estark7feb65c2b2015-08-21 23:38:201764 histogram_cookie_source_scheme_ = base::LinearHistogram::FactoryGet(
1765 "Cookie.CookieSourceScheme", 1, COOKIE_SOURCE_LAST_ENTRY - 1,
1766 COOKIE_SOURCE_LAST_ENTRY, base::Histogram::kUmaTargetedHistogramFlag);
jww31e32632015-12-16 23:38:341767 histogram_cookie_delete_equivalent_ = base::LinearHistogram::FactoryGet(
1768 "Cookie.CookieDeleteEquivalent", 1,
1769 COOKIE_DELETE_EQUIVALENT_LAST_ENTRY - 1,
1770 COOKIE_DELETE_EQUIVALENT_LAST_ENTRY,
1771 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401772
1773 // From UMA_HISTOGRAM_{CUSTOM_,}TIMES
[email protected]c7593fb22011-11-14 23:54:271774 histogram_time_blocked_on_load_ = base::Histogram::FactoryTimeGet(
mkwstbe84af312015-02-20 08:52:451775 "Cookie.TimeBlockedOnLoad", base::TimeDelta::FromMilliseconds(1),
1776 base::TimeDelta::FromMinutes(1), 50,
1777 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401778}
1779
rdsmithe5c701d2017-07-12 21:50:001780void CookieMonster::DoCookieCallback(base::OnceClosure callback) {
mmenkebe0910d2016-03-01 19:09:091781 DCHECK(thread_checker_.CalledOnValidThread());
1782
1783 MarkCookieStoreAsInitialized();
1784 FetchAllCookiesIfNecessary();
mmenkef49fca0e2016-03-08 12:46:241785 seen_global_task_ = true;
mmenkebe0910d2016-03-01 19:09:091786
1787 if (!finished_fetching_all_cookies_ && store_.get()) {
rdsmithe5c701d2017-07-12 21:50:001788 tasks_pending_.push_back(std::move(callback));
mmenkebe0910d2016-03-01 19:09:091789 return;
mmenke74bcbd52016-01-21 17:17:561790 }
1791
rdsmithe5c701d2017-07-12 21:50:001792 std::move(callback).Run();
mmenke74bcbd52016-01-21 17:17:561793}
1794
rdsmithe5c701d2017-07-12 21:50:001795void CookieMonster::DoCookieCallbackForURL(base::OnceClosure callback,
1796 const GURL& url) {
Maks Orlovich323efaf2018-03-06 02:56:391797 DoCookieCallbackForHostOrDomain(std::move(callback), url.host_piece());
1798}
1799
1800void CookieMonster::DoCookieCallbackForHostOrDomain(
1801 base::OnceClosure callback,
1802 base::StringPiece host_or_domain) {
mmenkebe0910d2016-03-01 19:09:091803 MarkCookieStoreAsInitialized();
erikchende4c39e2018-01-29 21:33:361804 FetchAllCookiesIfNecessary();
mmenkebe0910d2016-03-01 19:09:091805
1806 // If cookies for the requested domain key (eTLD+1) have been loaded from DB
1807 // then run the task, otherwise load from DB.
1808 if (!finished_fetching_all_cookies_ && store_.get()) {
mmenkef49fca0e2016-03-08 12:46:241809 // If a global task has been previously seen, queue the task as a global
1810 // task. Note that the CookieMonster may be in the middle of executing
1811 // the global queue, |tasks_pending_| may be empty, which is why another
1812 // bool is needed.
1813 if (seen_global_task_) {
rdsmithe5c701d2017-07-12 21:50:001814 tasks_pending_.push_back(std::move(callback));
mmenkef49fca0e2016-03-08 12:46:241815 return;
1816 }
1817
mmenkebe0910d2016-03-01 19:09:091818 // Checks if the domain key has been loaded.
Maks Orlovich323efaf2018-03-06 02:56:391819 std::string key = GetKey(host_or_domain);
mmenkebe0910d2016-03-01 19:09:091820 if (keys_loaded_.find(key) == keys_loaded_.end()) {
jdoerrie22a91d8b92018-10-05 08:43:261821 auto it = tasks_pending_for_key_.find(key);
mmenkebe0910d2016-03-01 19:09:091822 if (it == tasks_pending_for_key_.end()) {
1823 store_->LoadCookiesForKey(
Maks Orlovich108cb4c2019-03-26 20:24:571824 key, base::BindOnce(&CookieMonster::OnKeyLoaded,
1825 weak_ptr_factory_.GetWeakPtr(), key));
mmenkebe0910d2016-03-01 19:09:091826 it = tasks_pending_for_key_
Brett Wilsonc6a0c822017-09-12 00:04:291827 .insert(std::make_pair(
1828 key, base::circular_deque<base::OnceClosure>()))
mmenkebe0910d2016-03-01 19:09:091829 .first;
mmenke74bcbd52016-01-21 17:17:561830 }
rdsmithe5c701d2017-07-12 21:50:001831 it->second.push_back(std::move(callback));
mmenkebe0910d2016-03-01 19:09:091832 return;
mmenke74bcbd52016-01-21 17:17:561833 }
1834 }
mmenkebe0910d2016-03-01 19:09:091835
rdsmithe5c701d2017-07-12 21:50:001836 std::move(callback).Run();
mmenke74bcbd52016-01-21 17:17:561837}
1838
[email protected]63725312012-07-19 08:24:161839} // namespace net