blob: 15a8a6705224ba6f758a3c620a8127f33922230f [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]8562034e2011-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]8562034e2011-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]8562034e2011-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]8562034e2011-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]8562034e2011-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(
496 const std::vector<std::string>& schemes) {
mmenkebe0910d2016-03-01 19:09:09497 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56498
499 // Calls to this method will have no effect if made after a WebView or
500 // CookieManager instance has been created.
mmenke18dd8ba2016-02-01 18:42:10501 if (initialized_)
mmenke74bcbd52016-01-21 17:17:56502 return;
mmenke74bcbd52016-01-21 17:17:56503
mmenke18dd8ba2016-02-01 18:42:10504 cookieable_schemes_ = schemes;
mmenke74bcbd52016-01-21 17:17:56505}
506
mmenke74bcbd52016-01-21 17:17:56507// This function must be called before the CookieMonster is used.
508void CookieMonster::SetPersistSessionCookies(bool persist_session_cookies) {
mmenkebe0910d2016-03-01 19:09:09509 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56510 DCHECK(!initialized_);
Helen Licd0fab862018-08-13 16:07:53511 net_log_.AddEvent(
512 NetLogEventType::COOKIE_STORE_SESSION_PERSISTENCE,
513 NetLog::BoolCallback("persistence", persist_session_cookies));
mmenke74bcbd52016-01-21 17:17:56514 persist_session_cookies_ = persist_session_cookies;
515}
516
517bool CookieMonster::IsCookieableScheme(const std::string& scheme) {
mmenkebe0910d2016-03-01 19:09:09518 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56519
tripta.gdda72022017-06-19 05:16:23520 return base::ContainsValue(cookieable_schemes_, scheme);
mmenke74bcbd52016-01-21 17:17:56521}
522
mmenke18dd8ba2016-02-01 18:42:10523const char* const CookieMonster::kDefaultCookieableSchemes[] = {"http", "https",
524 "ws", "wss"};
mmenke74bcbd52016-01-21 17:17:56525const int CookieMonster::kDefaultCookieableSchemesCount =
Ryan Sleevi435a3a22018-05-15 02:16:07526 base::size(kDefaultCookieableSchemes);
mmenke74bcbd52016-01-21 17:17:56527
Victor Costan14f47c12018-03-01 08:02:24528CookieChangeDispatcher& CookieMonster::GetChangeDispatcher() {
529 return change_dispatcher_;
Randy Smithd32dc8c2017-08-30 18:03:40530}
531
nharper5babb5e62016-03-09 18:58:07532bool CookieMonster::IsEphemeral() {
533 return store_.get() == nullptr;
534}
535
Maks Orlovich5cf437b02018-03-27 04:40:42536void CookieMonster::DumpMemoryStats(
537 base::trace_event::ProcessMemoryDump* pmd,
538 const std::string& parent_absolute_name) const {
539 const char kRelPath[] = "/cookie_monster";
540
541 pmd->CreateAllocatorDump(parent_absolute_name + kRelPath + "/cookies")
542 ->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
543 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
544 cookies_.size());
545
546 pmd->CreateAllocatorDump(parent_absolute_name + kRelPath +
547 "/tasks_pending_global")
548 ->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
549 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
550 tasks_pending_.size());
551
552 size_t total_pending_for_key = 0;
553 for (const auto& kv : tasks_pending_for_key_)
554 total_pending_for_key += kv.second.size();
555 pmd->CreateAllocatorDump(parent_absolute_name + kRelPath +
556 "/tasks_pending_for_key")
557 ->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
558 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
559 total_pending_for_key);
560}
561
mmenke74bcbd52016-01-21 17:17:56562CookieMonster::~CookieMonster() {
mmenkebe0910d2016-03-01 19:09:09563 DCHECK(thread_checker_.CalledOnValidThread());
mmenke05255cf2016-02-03 15:49:31564
Randy Smith0a522662017-08-30 19:35:34565 // TODO(mmenke): Does it really make sense to run
mmenke606c59c2016-03-07 18:20:55566 // CookieChanged callbacks when the CookieStore is destroyed?
jdoerrie22a91d8b92018-10-05 08:43:26567 for (auto cookie_it = cookies_.begin(); cookie_it != cookies_.end();) {
568 auto current_cookie_it = cookie_it;
mmenke05255cf2016-02-03 15:49:31569 ++cookie_it;
570 InternalDeleteCookie(current_cookie_it, false /* sync_to_store */,
571 DELETE_COOKIE_DONT_RECORD);
572 }
Helen Licd0fab862018-08-13 16:07:53573 net_log_.EndEvent(NetLogEventType::COOKIE_STORE_ALIVE);
[email protected]8562034e2011-10-17 17:35:04574}
575
rdsmithe5c701d2017-07-12 21:50:00576void CookieMonster::GetAllCookies(GetCookieListCallback callback) {
mmenkebe0910d2016-03-01 19:09:09577 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40578
579 // This function is being called to scrape the cookie list for management UI
580 // or similar. We shouldn't show expired cookies in this list since it will
581 // just be confusing to users, and this function is called rarely enough (and
582 // is already slow enough) that it's OK to take the time to garbage collect
583 // the expired cookies now.
584 //
585 // Note that this does not prune cookies to be below our limits (if we've
586 // exceeded them) the way that calling GarbageCollect() would.
mkwstbe84af312015-02-20 08:52:45587 GarbageCollectExpired(
Raul Tambre94493c652019-03-11 17:18:35588 Time::Now(), CookieMapItPair(cookies_.begin(), cookies_.end()), nullptr);
[email protected]f48b9432011-01-11 07:25:40589
590 // Copy the CanonicalCookie pointers from the map so that we can use the same
591 // sorter as elsewhere, then copy the result out.
592 std::vector<CanonicalCookie*> cookie_ptrs;
593 cookie_ptrs.reserve(cookies_.size());
avie7cd11a2016-10-11 02:00:35594 for (const auto& cookie : cookies_)
595 cookie_ptrs.push_back(cookie.second.get());
[email protected]f48b9432011-01-11 07:25:40596 std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
597
598 CookieList cookie_list;
599 cookie_list.reserve(cookie_ptrs.size());
vmpstr6d9996c82017-02-23 00:43:25600 for (auto* cookie_ptr : cookie_ptrs)
avie7cd11a2016-10-11 02:00:35601 cookie_list.push_back(*cookie_ptr);
[email protected]f48b9432011-01-11 07:25:40602
Aaron Tagliaboschia4c64b52019-01-25 03:28:49603 MaybeRunCookieCallback(std::move(callback), cookie_list, CookieStatusList());
[email protected]f325f1e12010-04-30 22:38:55604}
605
rdsmithe5c701d2017-07-12 21:50:00606void CookieMonster::GetCookieListWithOptions(const GURL& url,
607 const CookieOptions& options,
608 GetCookieListCallback callback) {
mmenkebe0910d2016-03-01 19:09:09609 DCHECK(thread_checker_.CalledOnValidThread());
initial.commit586acc5fe2008-07-26 22:42:52610
mkwstc611e6d2016-02-23 15:45:55611 CookieList cookies;
Aaron Tagliaboschia4c64b52019-01-25 03:28:49612 CookieStatusList excluded_cookies;
rdsmithe5c701d2017-07-12 21:50:00613 if (HasCookieableScheme(url)) {
614 std::vector<CanonicalCookie*> cookie_ptrs;
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:52615 FindCookiesForRegistryControlledHost(url, &cookie_ptrs);
Aaron Tagliaboschi29033b7f2019-01-31 19:58:20616 std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
mkwstc611e6d2016-02-23 15:45:55617
rdsmithe5c701d2017-07-12 21:50:00618 cookies.reserve(cookie_ptrs.size());
Aaron Tagliaboschi29033b7f2019-01-31 19:58:20619 std::vector<CanonicalCookie*> included_cookie_ptrs;
620 FilterCookiesWithOptions(url, options, &cookie_ptrs, &included_cookie_ptrs,
621 &excluded_cookies);
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:52622
Aaron Tagliaboschi29033b7f2019-01-31 19:58:20623 for (auto* cookie : included_cookie_ptrs) {
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:52624 cookies.push_back(*cookie);
625 }
rdsmithe5c701d2017-07-12 21:50:00626 }
Aaron Tagliaboschi29033b7f2019-01-31 19:58:20627
Aaron Tagliaboschia4c64b52019-01-25 03:28:49628 MaybeRunCookieCallback(std::move(callback), cookies, excluded_cookies);
initial.commit586acc5fe2008-07-26 22:42:52629}
630
Chris Mumford800caa62018-04-20 19:34:44631void CookieMonster::DeleteAllCreatedInTimeRange(const TimeRange& creation_range,
632 DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09633 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]d0980332010-11-16 17:08:53634
rdsmitha5beda162017-07-08 13:55:42635 uint32_t num_deleted = 0;
jdoerrie22a91d8b92018-10-05 08:43:26636 for (auto it = cookies_.begin(); it != cookies_.end();) {
637 auto curit = it;
avie7cd11a2016-10-11 02:00:35638 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:40639 ++it;
[email protected]d0980332010-11-16 17:08:53640
Chris Mumford800caa62018-04-20 19:34:44641 if (creation_range.Contains(cc->CreationDate())) {
mkwstbe84af312015-02-20 08:52:45642 InternalDeleteCookie(curit, true, /*sync_to_store*/
Nick Harper7a6683a2018-01-30 20:42:52643 DELETE_COOKIE_EXPLICIT);
[email protected]f48b9432011-01-11 07:25:40644 ++num_deleted;
initial.commit586acc5fe2008-07-26 22:42:52645 }
646 }
647
rdsmithe5c701d2017-07-12 21:50:00648 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39649 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00650 callback ? base::BindOnce(std::move(callback), num_deleted)
651 : base::OnceClosure()));
[email protected]f48b9432011-01-11 07:25:40652}
653
Chris Mumford800caa62018-04-20 19:34:44654void CookieMonster::DeleteAllMatchingInfo(CookieDeletionInfo delete_info,
655 DeleteCallback callback) {
rdsmitha5beda162017-07-08 13:55:42656 uint32_t num_deleted = 0;
jdoerrie22a91d8b92018-10-05 08:43:26657 for (auto it = cookies_.begin(); it != cookies_.end();) {
658 auto curit = it;
avie7cd11a2016-10-11 02:00:35659 CanonicalCookie* cc = curit->second.get();
dmurphfaea244c2016-04-09 00:42:30660 ++it;
[email protected]f48b9432011-01-11 07:25:40661
Chris Mumford800caa62018-04-20 19:34:44662 if (delete_info.Matches(*cc)) {
dmurphfaea244c2016-04-09 00:42:30663 InternalDeleteCookie(curit, true, /*sync_to_store*/
Nick Harper7a6683a2018-01-30 20:42:52664 DELETE_COOKIE_EXPLICIT);
dmurphfaea244c2016-04-09 00:42:30665 ++num_deleted;
[email protected]f48b9432011-01-11 07:25:40666 }
667 }
dmurphfaea244c2016-04-09 00:42:30668
rdsmithe5c701d2017-07-12 21:50:00669 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39670 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00671 callback ? base::BindOnce(std::move(callback), num_deleted)
672 : base::OnceClosure()));
[email protected]f48b9432011-01-11 07:25:40673}
674
rdsmithe5c701d2017-07-12 21:50:00675void CookieMonster::SetCookieWithOptions(const GURL& url,
[email protected]f48b9432011-01-11 07:25:40676 const std::string& cookie_line,
rdsmithe5c701d2017-07-12 21:50:00677 const CookieOptions& options,
678 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:09679 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40680
681 if (!HasCookieableScheme(url)) {
Aaron Tagliaboschi29764f52019-02-21 17:19:59682 MaybeRunCookieCallback(
683 std::move(callback),
684 CanonicalCookie::CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME);
rdsmithe5c701d2017-07-12 21:50:00685 return;
[email protected]f48b9432011-01-11 07:25:40686 }
687
Oscar Johansson63e83cf2018-07-02 08:47:26688 VLOG(net::cookie_util::kVlogSetCookies)
689 << "SetCookie() line: " << cookie_line;
Maks Orlovicha61ed022018-03-01 18:24:24690
Aaron Tagliaboschi29764f52019-02-21 17:19:59691 CanonicalCookie::CookieInclusionStatus status;
Maks Orlovicha61ed022018-03-01 18:24:24692
Aaron Tagliaboschi29764f52019-02-21 17:19:59693 std::unique_ptr<CanonicalCookie> cc(
694 CanonicalCookie::Create(url, cookie_line, Time::Now(), options, &status));
695
696 if (status != CanonicalCookie::CookieInclusionStatus::INCLUDE) {
697 DCHECK(!cc);
Oscar Johansson63e83cf2018-07-02 08:47:26698 VLOG(net::cookie_util::kVlogSetCookies)
699 << "WARNING: Failed to allocate CanonicalCookie";
Aaron Tagliaboschi29764f52019-02-21 17:19:59700 MaybeRunCookieCallback(std::move(callback), status);
Maks Orlovicha61ed022018-03-01 18:24:24701 return;
702 }
Aaron Tagliaboschi29764f52019-02-21 17:19:59703
704 DCHECK(cc);
Maks Orlovichfdbc8be2019-03-18 18:34:52705 SetCanonicalCookie(std::move(cc), url.scheme(), options, std::move(callback));
[email protected]f48b9432011-01-11 07:25:40706}
707
rdsmithe5c701d2017-07-12 21:50:00708void CookieMonster::DeleteCanonicalCookie(const CanonicalCookie& cookie,
709 DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09710 DCHECK(thread_checker_.CalledOnValidThread());
mmenke24379d52016-02-05 23:50:17711
rdsmithe5c701d2017-07-12 21:50:00712 uint32_t result = 0u;
mmenke24379d52016-02-05 23:50:17713 for (CookieMapItPair its = cookies_.equal_range(GetKey(cookie.Domain()));
714 its.first != its.second; ++its.first) {
Maks Orlovich2896ec3f2018-04-06 13:34:27715 const std::unique_ptr<CanonicalCookie>& candidate = its.first->second;
716 // Historically, this has refused modification if the cookie has changed
717 // value in between the CanonicalCookie object was returned by a getter
718 // and when this ran. The later parts of the conditional (everything but
719 // the equivalence check) attempt to preserve this behavior.
720 if (candidate->IsEquivalent(cookie) &&
Maks Orlovich2896ec3f2018-04-06 13:34:27721 candidate->Value() == cookie.Value()) {
Nick Harper7a6683a2018-01-30 20:42:52722 InternalDeleteCookie(its.first, true, DELETE_COOKIE_EXPLICIT);
rdsmithe5c701d2017-07-12 21:50:00723 result = 1u;
724 break;
mmenke24379d52016-02-05 23:50:17725 }
726 }
rdsmithe5c701d2017-07-12 21:50:00727 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39728 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00729 callback ? base::BindOnce(std::move(callback), result)
730 : base::OnceClosure()));
mmenke24379d52016-02-05 23:50:17731}
732
rdsmithe5c701d2017-07-12 21:50:00733void CookieMonster::DeleteSessionCookies(DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09734 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]264807b2012-04-25 14:49:37735
rdsmitha5beda162017-07-08 13:55:42736 uint32_t num_deleted = 0;
jdoerrie22a91d8b92018-10-05 08:43:26737 for (auto it = cookies_.begin(); it != cookies_.end();) {
738 auto curit = it;
avie7cd11a2016-10-11 02:00:35739 CanonicalCookie* cc = curit->second.get();
[email protected]264807b2012-04-25 14:49:37740 ++it;
741
742 if (!cc->IsPersistent()) {
mkwstbe84af312015-02-20 08:52:45743 InternalDeleteCookie(curit, true, /*sync_to_store*/
[email protected]264807b2012-04-25 14:49:37744 DELETE_COOKIE_EXPIRED);
745 ++num_deleted;
746 }
747 }
748
rdsmithe5c701d2017-07-12 21:50:00749 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39750 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00751 callback ? base::BindOnce(std::move(callback), num_deleted)
752 : base::OnceClosure()));
[email protected]264807b2012-04-25 14:49:37753}
754
erikchen1dd72a72015-05-06 20:45:05755void CookieMonster::MarkCookieStoreAsInitialized() {
mmenkebe0910d2016-03-01 19:09:09756 DCHECK(thread_checker_.CalledOnValidThread());
erikchen1dd72a72015-05-06 20:45:05757 initialized_ = true;
758}
759
760void CookieMonster::FetchAllCookiesIfNecessary() {
mmenkebe0910d2016-03-01 19:09:09761 DCHECK(thread_checker_.CalledOnValidThread());
erikchen1dd72a72015-05-06 20:45:05762 if (store_.get() && !started_fetching_all_cookies_) {
763 started_fetching_all_cookies_ = true;
764 FetchAllCookies();
765 }
766}
767
mmenke74bcbd52016-01-21 17:17:56768void CookieMonster::FetchAllCookies() {
mmenkebe0910d2016-03-01 19:09:09769 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56770 DCHECK(store_.get()) << "Store must exist to initialize";
771 DCHECK(!finished_fetching_all_cookies_)
772 << "All cookies have already been fetched.";
773
774 // We bind in the current time so that we can report the wall-clock time for
775 // loading cookies.
mmenkebe0910d2016-03-01 19:09:09776 store_->Load(base::Bind(&CookieMonster::OnLoaded,
Helen Li92a29f102018-08-15 23:02:26777 weak_ptr_factory_.GetWeakPtr(), TimeTicks::Now()),
778 net_log_);
mmenke74bcbd52016-01-21 17:17:56779}
780
avie7cd11a2016-10-11 02:00:35781void CookieMonster::OnLoaded(
782 TimeTicks beginning_time,
783 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:09784 DCHECK(thread_checker_.CalledOnValidThread());
avie7cd11a2016-10-11 02:00:35785 StoreLoadedCookies(std::move(cookies));
[email protected]c7593fb22011-11-14 23:54:27786 histogram_time_blocked_on_load_->AddTime(TimeTicks::Now() - beginning_time);
[email protected]218aa6a12011-09-13 17:38:38787
788 // Invoke the task queue of cookie request.
789 InvokeQueue();
790}
791
avie7cd11a2016-10-11 02:00:35792void CookieMonster::OnKeyLoaded(
793 const std::string& key,
794 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:09795 DCHECK(thread_checker_.CalledOnValidThread());
796
avie7cd11a2016-10-11 02:00:35797 StoreLoadedCookies(std::move(cookies));
[email protected]8562034e2011-10-17 17:35:04798
mmenkebe0910d2016-03-01 19:09:09799 auto tasks_pending_for_key = tasks_pending_for_key_.find(key);
[email protected]8562034e2011-10-17 17:35:04800
mmenkebe0910d2016-03-01 19:09:09801 // TODO(mmenke): Can this be turned into a DCHECK?
802 if (tasks_pending_for_key == tasks_pending_for_key_.end())
803 return;
[email protected]bab72ec2013-10-30 20:50:02804
mmenkebe0910d2016-03-01 19:09:09805 // Run all tasks for the key. Note that running a task can result in multiple
806 // tasks being added to the back of the deque.
807 while (!tasks_pending_for_key->second.empty()) {
rdsmithe5c701d2017-07-12 21:50:00808 base::OnceClosure task = std::move(tasks_pending_for_key->second.front());
mmenkebe0910d2016-03-01 19:09:09809 tasks_pending_for_key->second.pop_front();
rdsmithe5c701d2017-07-12 21:50:00810 std::move(task).Run();
[email protected]8562034e2011-10-17 17:35:04811 }
mmenkebe0910d2016-03-01 19:09:09812
813 tasks_pending_for_key_.erase(tasks_pending_for_key);
814
815 // This has to be done last, in case running a task queues a new task for the
816 // key, to ensure tasks are run in the correct order.
817 keys_loaded_.insert(key);
[email protected]8562034e2011-10-17 17:35:04818}
819
[email protected]218aa6a12011-09-13 17:38:38820void CookieMonster::StoreLoadedCookies(
avie7cd11a2016-10-11 02:00:35821 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:09822 DCHECK(thread_checker_.CalledOnValidThread());
823
mmenkebe0910d2016-03-01 19:09:09824 // Even if a key is expired, insert it so it can be garbage collected,
825 // removed, and sync'd.
[email protected]6210ce52013-09-20 03:33:14826 CookieItVector cookies_with_control_chars;
827
avie7cd11a2016-10-11 02:00:35828 for (auto& cookie : cookies) {
Maks Orlovich2b0d5b12018-04-10 19:33:47829 CanonicalCookie* cookie_ptr = cookie.get();
jdoerrie22a91d8b92018-10-05 08:43:26830 auto inserted = InternalInsertCookie(GetKey(cookie_ptr->Domain()),
831 std::move(cookie), false);
Maks Orlovich2b0d5b12018-04-10 19:33:47832 const Time cookie_access_time(cookie_ptr->LastAccessDate());
833 if (earliest_access_time_.is_null() ||
Helen Lid84010b2018-08-22 16:27:44834 cookie_access_time < earliest_access_time_) {
Maks Orlovich2b0d5b12018-04-10 19:33:47835 earliest_access_time_ = cookie_access_time;
Helen Lid84010b2018-08-22 16:27:44836 }
[email protected]f48b9432011-01-11 07:25:40837
Maks Orlovich2b0d5b12018-04-10 19:33:47838 if (ContainsControlCharacter(cookie_ptr->Name()) ||
839 ContainsControlCharacter(cookie_ptr->Value())) {
840 cookies_with_control_chars.push_back(inserted);
[email protected]f48b9432011-01-11 07:25:40841 }
842 }
[email protected]f48b9432011-01-11 07:25:40843
[email protected]6210ce52013-09-20 03:33:14844 // Any cookies that contain control characters that we have loaded from the
845 // persistent store should be deleted. See http://crbug.com/238041.
jdoerrie22a91d8b92018-10-05 08:43:26846 for (auto it = cookies_with_control_chars.begin();
[email protected]6210ce52013-09-20 03:33:14847 it != cookies_with_control_chars.end();) {
jdoerrie22a91d8b92018-10-05 08:43:26848 auto curit = it;
[email protected]6210ce52013-09-20 03:33:14849 ++it;
850
851 InternalDeleteCookie(*curit, true, DELETE_COOKIE_CONTROL_CHAR);
852 }
853
[email protected]f48b9432011-01-11 07:25:40854 // After importing cookies from the PersistentCookieStore, verify that
855 // none of our other constraints are violated.
[email protected]f48b9432011-01-11 07:25:40856 // In particular, the backing store might have given us duplicate cookies.
[email protected]8562034e2011-10-17 17:35:04857
858 // This method could be called multiple times due to priority loading, thus
859 // cookies loaded in previous runs will be validated again, but this is OK
860 // since they are expected to be much fewer than total DB.
[email protected]f48b9432011-01-11 07:25:40861 EnsureCookiesMapIsValid();
[email protected]218aa6a12011-09-13 17:38:38862}
[email protected]f48b9432011-01-11 07:25:40863
[email protected]218aa6a12011-09-13 17:38:38864void CookieMonster::InvokeQueue() {
mmenkebe0910d2016-03-01 19:09:09865 DCHECK(thread_checker_.CalledOnValidThread());
866
mmenkef49fca0e2016-03-08 12:46:24867 // Move all per-key tasks into the global queue, if there are any. This is
868 // protection about a race where the store learns about all cookies loading
869 // before it learned about the cookies for a key loading.
870
871 // Needed to prevent any recursively queued tasks from going back into the
872 // per-key queues.
873 seen_global_task_ = true;
rdsmithe5c701d2017-07-12 21:50:00874 for (auto& tasks_for_key : tasks_pending_for_key_) {
875 tasks_pending_.insert(tasks_pending_.begin(),
876 std::make_move_iterator(tasks_for_key.second.begin()),
877 std::make_move_iterator(tasks_for_key.second.end()));
mmenkef49fca0e2016-03-08 12:46:24878 }
879 tasks_pending_for_key_.clear();
880
mmenkebe0910d2016-03-01 19:09:09881 while (!tasks_pending_.empty()) {
rdsmithe5c701d2017-07-12 21:50:00882 base::OnceClosure request_task = std::move(tasks_pending_.front());
mmenkef49fca0e2016-03-08 12:46:24883 tasks_pending_.pop_front();
rdsmithe5c701d2017-07-12 21:50:00884 std::move(request_task).Run();
[email protected]218aa6a12011-09-13 17:38:38885 }
mmenkebe0910d2016-03-01 19:09:09886
mmenkef49fca0e2016-03-08 12:46:24887 DCHECK(tasks_pending_for_key_.empty());
888
mmenkebe0910d2016-03-01 19:09:09889 finished_fetching_all_cookies_ = true;
mmenkebe0910d2016-03-01 19:09:09890 keys_loaded_.clear();
[email protected]f48b9432011-01-11 07:25:40891}
892
893void CookieMonster::EnsureCookiesMapIsValid() {
mmenkebe0910d2016-03-01 19:09:09894 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40895
[email protected]f48b9432011-01-11 07:25:40896 // Iterate through all the of the cookies, grouped by host.
jdoerrie22a91d8b92018-10-05 08:43:26897 auto prev_range_end = cookies_.begin();
[email protected]f48b9432011-01-11 07:25:40898 while (prev_range_end != cookies_.end()) {
jdoerrie22a91d8b92018-10-05 08:43:26899 auto cur_range_begin = prev_range_end;
[email protected]f48b9432011-01-11 07:25:40900 const std::string key = cur_range_begin->first; // Keep a copy.
jdoerrie22a91d8b92018-10-05 08:43:26901 auto cur_range_end = cookies_.upper_bound(key);
[email protected]f48b9432011-01-11 07:25:40902 prev_range_end = cur_range_end;
903
904 // Ensure no equivalent cookies for this host.
ellyjonescabf57422015-08-21 18:44:51905 TrimDuplicateCookiesForKey(key, cur_range_begin, cur_range_end);
[email protected]f48b9432011-01-11 07:25:40906 }
[email protected]f48b9432011-01-11 07:25:40907}
908
ellyjonescabf57422015-08-21 18:44:51909void CookieMonster::TrimDuplicateCookiesForKey(const std::string& key,
910 CookieMap::iterator begin,
911 CookieMap::iterator end) {
mmenkebe0910d2016-03-01 19:09:09912 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40913
914 // Set of cookies ordered by creation time.
Maks Orlovich2b0d5b12018-04-10 19:33:47915 typedef std::multiset<CookieMap::iterator, OrderByCreationTimeDesc> CookieSet;
[email protected]f48b9432011-01-11 07:25:40916
917 // Helper map we populate to find the duplicates.
918 typedef std::map<CookieSignature, CookieSet> EquivalenceMap;
919 EquivalenceMap equivalent_cookies;
920
921 // The number of duplicate cookies that have been found.
922 int num_duplicates = 0;
923
924 // Iterate through all of the cookies in our range, and insert them into
925 // the equivalence map.
jdoerrie22a91d8b92018-10-05 08:43:26926 for (auto it = begin; it != end; ++it) {
[email protected]f48b9432011-01-11 07:25:40927 DCHECK_EQ(key, it->first);
avie7cd11a2016-10-11 02:00:35928 CanonicalCookie* cookie = it->second.get();
[email protected]f48b9432011-01-11 07:25:40929
mkwstbe84af312015-02-20 08:52:45930 CookieSignature signature(cookie->Name(), cookie->Domain(), cookie->Path());
[email protected]f48b9432011-01-11 07:25:40931 CookieSet& set = equivalent_cookies[signature];
932
933 // We found a duplicate!
934 if (!set.empty())
935 num_duplicates++;
936
937 // We save the iterator into |cookies_| rather than the actual cookie
938 // pointer, since we may need to delete it later.
Maks Orlovich2b0d5b12018-04-10 19:33:47939 set.insert(it);
[email protected]f48b9432011-01-11 07:25:40940 }
941
942 // If there were no duplicates, we are done!
943 if (num_duplicates == 0)
ellyjonescabf57422015-08-21 18:44:51944 return;
[email protected]f48b9432011-01-11 07:25:40945
946 // Make sure we find everything below that we did above.
947 int num_duplicates_found = 0;
948
949 // Otherwise, delete all the duplicate cookies, both from our in-memory store
950 // and from the backing store.
jdoerrie22a91d8b92018-10-05 08:43:26951 for (auto it = equivalent_cookies.begin(); it != equivalent_cookies.end();
952 ++it) {
[email protected]f48b9432011-01-11 07:25:40953 const CookieSignature& signature = it->first;
954 CookieSet& dupes = it->second;
955
956 if (dupes.size() <= 1)
957 continue; // This cookiename/path has no duplicates.
958 num_duplicates_found += dupes.size() - 1;
959
Maks Orlovich2b0d5b12018-04-10 19:33:47960 // Since |dupes| is sorted by creation time (descending), the first cookie
961 // is the most recent one (or tied for it), so we will keep it. The rest are
962 // duplicates.
[email protected]f48b9432011-01-11 07:25:40963 dupes.erase(dupes.begin());
964
965 LOG(ERROR) << base::StringPrintf(
966 "Found %d duplicate cookies for host='%s', "
967 "with {name='%s', domain='%s', path='%s'}",
mkwstbe84af312015-02-20 08:52:45968 static_cast<int>(dupes.size()), key.c_str(), signature.name.c_str(),
969 signature.domain.c_str(), signature.path.c_str());
[email protected]f48b9432011-01-11 07:25:40970
971 // Remove all the cookies identified by |dupes|. It is valid to delete our
972 // list of iterators one at a time, since |cookies_| is a multimap (they
973 // don't invalidate existing iterators following deletion).
jdoerrie22a91d8b92018-10-05 08:43:26974 for (auto dupes_it = dupes.begin(); dupes_it != dupes.end(); ++dupes_it) {
[email protected]218aa6a12011-09-13 17:38:38975 InternalDeleteCookie(*dupes_it, true,
[email protected]f48b9432011-01-11 07:25:40976 DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE);
977 }
978 }
979 DCHECK_EQ(num_duplicates, num_duplicates_found);
[email protected]f48b9432011-01-11 07:25:40980}
981
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:52982void CookieMonster::FindCookiesForRegistryControlledHost(
[email protected]f48b9432011-01-11 07:25:40983 const GURL& url,
[email protected]f48b9432011-01-11 07:25:40984 std::vector<CanonicalCookie*>* cookies) {
mmenkebe0910d2016-03-01 19:09:09985 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40986
Maks Orlovichc86cf292019-02-11 19:25:17987 Time current_time = Time::Now();
[email protected]f48b9432011-01-11 07:25:40988
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:52989 // Retrieve all cookies for a given key
Maks Orlovich323efaf2018-03-06 02:56:39990 const std::string key(GetKey(url.host_piece()));
Aaron Tagliaboschi9e1de1b2019-01-15 14:40:06991
[email protected]f48b9432011-01-11 07:25:40992 for (CookieMapItPair its = cookies_.equal_range(key);
mkwstbe84af312015-02-20 08:52:45993 its.first != its.second;) {
jdoerrie22a91d8b92018-10-05 08:43:26994 auto curit = its.first;
avie7cd11a2016-10-11 02:00:35995 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:40996 ++its.first;
997
998 // If the cookie is expired, delete it.
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:52999 if (cc->IsExpired(current_time)) {
[email protected]f48b9432011-01-11 07:25:401000 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
1001 continue;
1002 }
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521003 cookies->push_back(cc);
Aaron Tagliaboschi9e1de1b2019-01-15 14:40:061004 }
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521005}
[email protected]f48b9432011-01-11 07:25:401006
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521007void CookieMonster::FilterCookiesWithOptions(
1008 const GURL url,
1009 const CookieOptions options,
1010 std::vector<CanonicalCookie*>* cookie_ptrs,
Aaron Tagliaboschi29033b7f2019-01-31 19:58:201011 std::vector<CanonicalCookie*>* included_cookie_ptrs,
1012 CookieStatusList* excluded_cookies) {
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521013 DCHECK(thread_checker_.CalledOnValidThread());
1014
1015 // Probe to save statistics relatively frequently. We do it here rather
1016 // than in the set path as many websites won't set cookies, and we
1017 // want to collect statistics whenever the browser's being used.
Maks Orlovichc86cf292019-02-11 19:25:171018 Time current_time = Time::Now();
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521019 RecordPeriodicStats(current_time);
1020
1021 for (std::vector<CanonicalCookie*>::iterator it = cookie_ptrs->begin();
1022 it != cookie_ptrs->end(); it++) {
[email protected]65f4e7e2012-12-12 21:56:541023 // Filter out cookies that should not be included for a request to the
1024 // given |url|. HTTP only cookies are filtered depending on the passed
1025 // cookie |options|.
Aaron Tagliaboschi29033b7f2019-01-31 19:58:201026 CanonicalCookie::CookieInclusionStatus status =
1027 (*it)->IncludeForRequestURL(url, options);
1028
1029 if (status != CanonicalCookie::CookieInclusionStatus::INCLUDE) {
1030 if (options.return_excluded_cookies())
1031 excluded_cookies->push_back({**it, status});
[email protected]f48b9432011-01-11 07:25:401032 continue;
[email protected]f48b9432011-01-11 07:25:401033 }
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521034
1035 if (options.update_access_time())
1036 InternalUpdateCookieAccessTime(*it, current_time);
1037
Aaron Tagliaboschi29033b7f2019-01-31 19:58:201038 included_cookie_ptrs->push_back(*it);
[email protected]f48b9432011-01-11 07:25:401039 }
1040}
1041
Aaron Tagliaboschi29764f52019-02-21 17:19:591042CanonicalCookie::CookieInclusionStatus CookieMonster::DeleteAnyEquivalentCookie(
Mike Westc4a777b2017-10-06 14:04:201043 const std::string& key,
1044 const CanonicalCookie& ecc,
1045 bool source_secure,
1046 bool skip_httponly,
1047 bool already_expired,
1048 base::Time* creation_date_to_inherit) {
mmenkebe0910d2016-03-01 19:09:091049 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401050
1051 bool found_equivalent_cookie = false;
1052 bool skipped_httponly = false;
jww601411a2015-11-20 19:46:571053 bool skipped_secure_cookie = false;
jww31e32632015-12-16 23:38:341054
1055 histogram_cookie_delete_equivalent_->Add(COOKIE_DELETE_EQUIVALENT_ATTEMPT);
1056
Lily Chen22707642b2018-10-02 17:27:211057 CookieMap::iterator cookie_it_to_possibly_delete = cookies_.end();
1058 CanonicalCookie* cc_skipped_secure = nullptr;
[email protected]f48b9432011-01-11 07:25:401059 for (CookieMapItPair its = cookies_.equal_range(key);
mkwstbe84af312015-02-20 08:52:451060 its.first != its.second;) {
jdoerrie22a91d8b92018-10-05 08:43:261061 auto curit = its.first;
avie7cd11a2016-10-11 02:00:351062 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:401063 ++its.first;
1064
jwwa26e439d2017-01-27 18:17:271065 // If the cookie is being set from an insecure scheme, then if a cookie
1066 // already exists with the same name and it is Secure, then the cookie
1067 // should *not* be updated if they domain-match and ignoring the path
1068 // attribute.
jww601411a2015-11-20 19:46:571069 //
jwwa26e439d2017-01-27 18:17:271070 // See: https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone
rdsmith2709eee2017-06-20 22:43:271071 if (cc->IsSecure() && !source_secure &&
mmenke2830b0722016-07-20 16:02:501072 ecc.IsEquivalentForSecureCookieMatching(*cc)) {
jww601411a2015-11-20 19:46:571073 skipped_secure_cookie = true;
Lily Chen22707642b2018-10-02 17:27:211074 cc_skipped_secure = cc;
jww31e32632015-12-16 23:38:341075 histogram_cookie_delete_equivalent_->Add(
1076 COOKIE_DELETE_EQUIVALENT_SKIPPING_SECURE);
Helen Licd0fab862018-08-13 16:07:531077 net_log_.AddEvent(
1078 NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_SECURE,
1079 base::BindRepeating(&NetLogCookieMonsterCookieRejectedSecure, cc,
1080 &ecc));
jww31e32632015-12-16 23:38:341081 // If the cookie is equivalent to the new cookie and wouldn't have been
1082 // skipped for being HTTP-only, record that it is a skipped secure cookie
1083 // that would have been deleted otherwise.
1084 if (ecc.IsEquivalent(*cc)) {
jwwa9a0d482015-12-16 18:19:411085 found_equivalent_cookie = true;
jww31e32632015-12-16 23:38:341086
1087 if (!skip_httponly || !cc->IsHttpOnly()) {
1088 histogram_cookie_delete_equivalent_->Add(
1089 COOKIE_DELETE_EQUIVALENT_WOULD_HAVE_DELETED);
1090 }
1091 }
jww601411a2015-11-20 19:46:571092 } else if (ecc.IsEquivalent(*cc)) {
[email protected]f48b9432011-01-11 07:25:401093 // We should never have more than one equivalent cookie, since they should
jww601411a2015-11-20 19:46:571094 // overwrite each other, unless secure cookies require secure scheme is
1095 // being enforced. In that case, cookies with different paths might exist
1096 // and be considered equivalent.
mkwstbe84af312015-02-20 08:52:451097 CHECK(!found_equivalent_cookie)
1098 << "Duplicate equivalent cookies found, cookie store is corrupted.";
Lily Chen22707642b2018-10-02 17:27:211099 DCHECK(cookie_it_to_possibly_delete == cookies_.end());
[email protected]f48b9432011-01-11 07:25:401100 if (skip_httponly && cc->IsHttpOnly()) {
1101 skipped_httponly = true;
Helen Licd0fab862018-08-13 16:07:531102 net_log_.AddEvent(
1103 NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_HTTPONLY,
1104 base::BindRepeating(&NetLogCookieMonsterCookieRejectedHttponly, cc,
1105 &ecc));
[email protected]f48b9432011-01-11 07:25:401106 } else {
Lily Chen22707642b2018-10-02 17:27:211107 cookie_it_to_possibly_delete = curit;
[email protected]f48b9432011-01-11 07:25:401108 }
1109 found_equivalent_cookie = true;
1110 }
1111 }
Lily Chen22707642b2018-10-02 17:27:211112
1113 if (cookie_it_to_possibly_delete != cookies_.end()) {
1114 CanonicalCookie* cc_to_possibly_delete =
1115 cookie_it_to_possibly_delete->second.get();
1116 // If a secure cookie was encountered (and left alone), don't actually
1117 // modify any of the pre-existing cookies. Only delete if no secure cookies
1118 // were skipped.
1119 if (!skipped_secure_cookie) {
1120 histogram_cookie_delete_equivalent_->Add(COOKIE_DELETE_EQUIVALENT_FOUND);
1121 if (cc_to_possibly_delete->Value() == ecc.Value()) {
1122 *creation_date_to_inherit = cc_to_possibly_delete->CreationDate();
1123 histogram_cookie_delete_equivalent_->Add(
1124 COOKIE_DELETE_EQUIVALENT_FOUND_WITH_SAME_VALUE);
1125 }
1126 InternalDeleteCookie(cookie_it_to_possibly_delete, true,
1127 already_expired ? DELETE_COOKIE_EXPIRED_OVERWRITE
1128 : DELETE_COOKIE_OVERWRITE);
1129 } else {
1130 // If any secure cookie was skipped, preserve the pre-existing cookie.
1131 DCHECK(cc_skipped_secure);
1132 net_log_.AddEvent(
1133 NetLogEventType::COOKIE_STORE_COOKIE_PRESERVED_SKIPPED_SECURE,
1134 base::BindRepeating(&NetLogCookieMonsterCookiePreservedSkippedSecure,
1135 cc_skipped_secure, cc_to_possibly_delete, &ecc));
1136 }
1137 }
1138
Aaron Tagliaboschi29764f52019-02-21 17:19:591139 if (skipped_httponly)
1140 return CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY;
1141
1142 if (skipped_secure_cookie)
1143 return CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE;
1144
1145 return CanonicalCookie::CookieInclusionStatus::INCLUDE;
[email protected]f48b9432011-01-11 07:25:401146}
1147
[email protected]6210ce52013-09-20 03:33:141148CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie(
1149 const std::string& key,
avie7cd11a2016-10-11 02:00:351150 std::unique_ptr<CanonicalCookie> cc,
[email protected]6210ce52013-09-20 03:33:141151 bool sync_to_store) {
mmenkebe0910d2016-03-01 19:09:091152 DCHECK(thread_checker_.CalledOnValidThread());
avie7cd11a2016-10-11 02:00:351153 CanonicalCookie* cc_ptr = cc.get();
mmenkebe0910d2016-03-01 19:09:091154
Helen Licd0fab862018-08-13 16:07:531155 net_log_.AddEvent(NetLogEventType::COOKIE_STORE_COOKIE_ADDED,
1156 base::BindRepeating(&NetLogCookieMonsterCookieAdded,
1157 cc.get(), sync_to_store));
avie7cd11a2016-10-11 02:00:351158 if ((cc_ptr->IsPersistent() || persist_session_cookies_) && store_.get() &&
Helen Lid84010b2018-08-22 16:27:441159 sync_to_store) {
avie7cd11a2016-10-11 02:00:351160 store_->AddCookie(*cc_ptr);
Helen Lid84010b2018-08-22 16:27:441161 }
jdoerrie22a91d8b92018-10-05 08:43:261162 auto inserted = cookies_.insert(CookieMap::value_type(key, std::move(cc)));
mkwstc1aa4cc2015-04-03 19:57:451163
1164 // See InitializeHistograms() for details.
avie7cd11a2016-10-11 02:00:351165 int32_t type_sample = cc_ptr->SameSite() != CookieSameSite::NO_RESTRICTION
mkwste1a29582016-03-15 10:07:521166 ? 1 << COOKIE_TYPE_SAME_SITE
1167 : 0;
avie7cd11a2016-10-11 02:00:351168 type_sample |= cc_ptr->IsHttpOnly() ? 1 << COOKIE_TYPE_HTTPONLY : 0;
1169 type_sample |= cc_ptr->IsSecure() ? 1 << COOKIE_TYPE_SECURE : 0;
mkwst46549412016-02-01 10:05:371170 histogram_cookie_type_->Add(type_sample);
estark7feb65c2b2015-08-21 23:38:201171
Victor Costan14f47c12018-03-01 08:02:241172 change_dispatcher_.DispatchChange(*cc_ptr, CookieChangeCause::INSERTED, true);
[email protected]6210ce52013-09-20 03:33:141173
1174 return inserted;
[email protected]f48b9432011-01-11 07:25:401175}
1176
rdsmithe5c701d2017-07-12 21:50:001177void CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc,
Maks Orlovich44525ce2019-02-25 14:17:581178 std::string source_scheme,
Maks Orlovichfdbc8be2019-03-18 18:34:521179 const CookieOptions& options,
rdsmithe5c701d2017-07-12 21:50:001180 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:091181 DCHECK(thread_checker_.CalledOnValidThread());
1182
Maks Orlovich44525ce2019-02-25 14:17:581183 std::string scheme_lower = base::ToLowerASCII(source_scheme);
1184 bool secure_source = GURL::SchemeIsCryptographic(scheme_lower);
Aaron Tagliaboschi29764f52019-02-21 17:19:591185 if ((cc->IsSecure() && !secure_source)) {
1186 MaybeRunCookieCallback(
1187 std::move(callback),
1188 CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY);
1189 return;
1190 }
1191
Maks Orlovichfdbc8be2019-03-18 18:34:521192 if (cc->IsHttpOnly() && options.exclude_httponly()) {
Aaron Tagliaboschi29764f52019-02-21 17:19:591193 MaybeRunCookieCallback(
1194 std::move(callback),
1195 CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY);
rdsmithe5c701d2017-07-12 21:50:001196 return;
1197 }
rdsmith2709eee2017-06-20 22:43:271198
Maks Orlovich44525ce2019-02-25 14:17:581199 if (!IsCookieableScheme(scheme_lower)) {
1200 MaybeRunCookieCallback(
1201 std::move(callback),
1202 CanonicalCookie::CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME);
1203 return;
1204 }
1205
mmenkeea4cd402016-02-02 04:03:101206 const std::string key(GetKey(cc->Domain()));
rdsmitha6ce4442017-06-21 17:11:051207
rdsmitha6ce4442017-06-21 17:11:051208 base::Time creation_date = cc->CreationDate();
1209 if (creation_date.is_null()) {
Maks Orlovichc86cf292019-02-11 19:25:171210 creation_date = Time::Now();
rdsmitha6ce4442017-06-21 17:11:051211 cc->SetCreationDate(creation_date);
rdsmitha6ce4442017-06-21 17:11:051212 }
1213 bool already_expired = cc->IsExpired(creation_date);
ellyjones399e35a22014-10-27 11:09:561214
Mike Westc4a777b2017-10-06 14:04:201215 base::Time creation_date_to_inherit;
Aaron Tagliaboschi29764f52019-02-21 17:19:591216
Maks Orlovichfdbc8be2019-03-18 18:34:521217 CanonicalCookie::CookieInclusionStatus status = DeleteAnyEquivalentCookie(
1218 key, *cc, secure_source, options.exclude_httponly(), already_expired,
1219 &creation_date_to_inherit);
Aaron Tagliaboschi29764f52019-02-21 17:19:591220
1221 if (status != CanonicalCookie::CookieInclusionStatus::INCLUDE) {
jww601411a2015-11-20 19:46:571222 std::string error;
jwwa26e439d2017-01-27 18:17:271223 error =
1224 "SetCookie() not clobbering httponly cookie or secure cookie for "
1225 "insecure scheme";
jww601411a2015-11-20 19:46:571226
Oscar Johansson63e83cf2018-07-02 08:47:261227 VLOG(net::cookie_util::kVlogSetCookies) << error;
Aaron Tagliaboschi29764f52019-02-21 17:19:591228 MaybeRunCookieCallback(std::move(callback), status);
rdsmithe5c701d2017-07-12 21:50:001229 return;
[email protected]3a96c742008-11-19 19:46:271230 }
initial.commit586acc5fe2008-07-26 22:42:521231
Oscar Johansson63e83cf2018-07-02 08:47:261232 VLOG(net::cookie_util::kVlogSetCookies)
1233 << "SetCookie() key: " << key << " cc: " << cc->DebugString();
initial.commit586acc5fe2008-07-26 22:42:521234
1235 // Realize that we might be setting an expired cookie, and the only point
1236 // was to delete the cookie which we've already done.
mmenke3c79a652016-02-12 14:39:201237 if (!already_expired) {
[email protected]374f58b2010-07-20 15:29:261238 // See InitializeHistograms() for details.
mmenkeea4cd402016-02-02 04:03:101239 if (cc->IsPersistent()) {
[email protected]8475bee2011-03-17 18:40:241240 histogram_expiration_duration_minutes_->Add(
rdsmitha6ce4442017-06-21 17:11:051241 (cc->ExpiryDate() - creation_date).InMinutes());
[email protected]8475bee2011-03-17 18:40:241242 }
1243
rdsmith2709eee2017-06-20 22:43:271244 // Histogram the type of scheme used on URLs that set cookies. This
1245 // intentionally includes cookies that are set or overwritten by
1246 // http:// URLs, but not cookies that are cleared by http:// URLs, to
1247 // understand if the former behavior can be deprecated for Secure
1248 // cookies.
1249 CookieSource cookie_source_sample =
1250 (secure_source
1251 ? (cc->IsSecure()
1252 ? COOKIE_SOURCE_SECURE_COOKIE_CRYPTOGRAPHIC_SCHEME
1253 : COOKIE_SOURCE_NONSECURE_COOKIE_CRYPTOGRAPHIC_SCHEME)
1254 : (cc->IsSecure()
1255 ? COOKIE_SOURCE_SECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME
1256 : COOKIE_SOURCE_NONSECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME));
1257 histogram_cookie_source_scheme_->Add(cookie_source_sample);
1258
Mike Westc4a777b2017-10-06 14:04:201259 if (!creation_date_to_inherit.is_null()) {
1260 cc->SetCreationDate(creation_date_to_inherit);
Mike Westc4a777b2017-10-06 14:04:201261 }
1262
rdsmith2709eee2017-06-20 22:43:271263 InternalInsertCookie(key, std::move(cc), true);
[email protected]348dd662013-03-13 20:25:071264 } else {
Oscar Johansson63e83cf2018-07-02 08:47:261265 VLOG(net::cookie_util::kVlogSetCookies)
1266 << "SetCookie() not storing already expired cookie.";
[email protected]c4058fb2010-06-22 17:25:261267 }
initial.commit586acc5fe2008-07-26 22:42:521268
1269 // We assume that hopefully setting a cookie will be less common than
1270 // querying a cookie. Since setting a cookie can put us over our limits,
1271 // make sure that we garbage collect... We can also make the assumption that
1272 // if a cookie was set, in the common case it will be used soon after,
1273 // and we will purge the expired cookies in GetCookies().
rdsmitha6ce4442017-06-21 17:11:051274 GarbageCollect(creation_date, key);
initial.commit586acc5fe2008-07-26 22:42:521275
Aaron Tagliaboschi29764f52019-02-21 17:19:591276 MaybeRunCookieCallback(std::move(callback),
1277 CanonicalCookie::CookieInclusionStatus::INCLUDE);
initial.commit586acc5fe2008-07-26 22:42:521278}
1279
rdsmithe5c701d2017-07-12 21:50:001280void CookieMonster::SetAllCookies(CookieList list,
1281 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:091282 DCHECK(thread_checker_.CalledOnValidThread());
rdsmithe5c701d2017-07-12 21:50:001283
rdsmith0e84cea2017-07-13 03:09:531284 // Nuke the existing store.
1285 while (!cookies_.empty()) {
1286 // TODO(rdsmith): The CANONICAL is a lie.
Nick Harper7a6683a2018-01-30 20:42:521287 InternalDeleteCookie(cookies_.begin(), true, DELETE_COOKIE_EXPLICIT);
rdsmithe5c701d2017-07-12 21:50:001288 }
1289
rdsmith0e84cea2017-07-13 03:09:531290 // Set all passed in cookies.
mmenkeea4cd402016-02-02 04:03:101291 for (const auto& cookie : list) {
rdsmith2709eee2017-06-20 22:43:271292 const std::string key(GetKey(cookie.Domain()));
1293 Time creation_time = cookie.CreationDate();
rdsmith0e84cea2017-07-13 03:09:531294 if (cookie.IsExpired(creation_time))
rdsmith2709eee2017-06-20 22:43:271295 continue;
1296
1297 if (cookie.IsPersistent()) {
1298 histogram_expiration_duration_minutes_->Add(
1299 (cookie.ExpiryDate() - creation_time).InMinutes());
mmenkeea4cd402016-02-02 04:03:101300 }
rdsmith2709eee2017-06-20 22:43:271301
Jeremy Roman0579ed62017-08-29 15:56:191302 InternalInsertCookie(key, std::make_unique<CanonicalCookie>(cookie), true);
rdsmith2709eee2017-06-20 22:43:271303 GarbageCollect(creation_time, key);
drogerd5d1278c2015-03-17 19:21:511304 }
1305
rdsmith2709eee2017-06-20 22:43:271306 // TODO(rdsmith): If this function always returns the same value, it
1307 // shouldn't have a return value. But it should also be deleted (see
1308 // https://codereview.chromium.org/2882063002/#msg64), which would
1309 // solve the return value problem.
Aaron Tagliaboschi29764f52019-02-21 17:19:591310 MaybeRunCookieCallback(std::move(callback),
1311 CanonicalCookie::CookieInclusionStatus::INCLUDE);
drogerd5d1278c2015-03-17 19:21:511312}
1313
[email protected]7a964a72010-09-07 19:33:261314void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc,
1315 const Time& current) {
mmenkebe0910d2016-03-01 19:09:091316 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041317
[email protected]77e0a462008-11-01 00:43:351318 // Based off the Mozilla code. When a cookie has been accessed recently,
1319 // don't bother updating its access time again. This reduces the number of
1320 // updates we do during pageload, which in turn reduces the chance our storage
1321 // backend will hit its batch thresholds and be forced to update.
[email protected]77e0a462008-11-01 00:43:351322 if ((current - cc->LastAccessDate()) < last_access_threshold_)
1323 return;
1324
1325 cc->SetLastAccessDate(current);
[email protected]90499482013-06-01 00:39:501326 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get())
[email protected]77e0a462008-11-01 00:43:351327 store_->UpdateCookieAccessTime(*cc);
1328}
1329
[email protected]6210ce52013-09-20 03:33:141330// InternalDeleteCookies must not invalidate iterators other than the one being
1331// deleted.
initial.commit586acc5fe2008-07-26 22:42:521332void CookieMonster::InternalDeleteCookie(CookieMap::iterator it,
[email protected]c4058fb2010-06-22 17:25:261333 bool sync_to_store,
1334 DeletionCause deletion_cause) {
mmenkebe0910d2016-03-01 19:09:091335 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041336
nharper352933e2016-09-30 18:24:571337 // Ideally, this would be asserted up where we define kChangeCauseMapping,
[email protected]8bb846f2011-03-23 12:08:181338 // but DeletionCause's visibility (or lack thereof) forces us to make
1339 // this check here.
Ryan Sleevi435a3a22018-05-15 02:16:071340 static_assert(base::size(kChangeCauseMapping) == DELETE_COOKIE_LAST_ENTRY + 1,
nharper352933e2016-09-30 18:24:571341 "kChangeCauseMapping size should match DeletionCause size");
[email protected]8bb846f2011-03-23 12:08:181342
avie7cd11a2016-10-11 02:00:351343 CanonicalCookie* cc = it->second.get();
Oscar Johansson63e83cf2018-07-02 08:47:261344 VLOG(net::cookie_util::kVlogSetCookies)
1345 << "InternalDeleteCookie()"
1346 << ", cause:" << deletion_cause << ", cc: " << cc->DebugString();
[email protected]7a964a72010-09-07 19:33:261347
Helen Licd0fab862018-08-13 16:07:531348 ChangeCausePair mapping = kChangeCauseMapping[deletion_cause];
1349 if (deletion_cause != DELETE_COOKIE_DONT_RECORD) {
1350 net_log_.AddEvent(NetLogEventType::COOKIE_STORE_COOKIE_DELETED,
1351 base::BindRepeating(&NetLogCookieMonsterCookieDeleted, cc,
1352 mapping.cause, sync_to_store));
1353 }
1354
[email protected]90499482013-06-01 00:39:501355 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get() &&
Helen Lid84010b2018-08-22 16:27:441356 sync_to_store) {
initial.commit586acc5fe2008-07-26 22:42:521357 store_->DeleteCookie(*cc);
Helen Lid84010b2018-08-22 16:27:441358 }
Victor Costan14f47c12018-03-01 08:02:241359 change_dispatcher_.DispatchChange(*cc, mapping.cause, mapping.notify);
initial.commit586acc5fe2008-07-26 22:42:521360 cookies_.erase(it);
initial.commit586acc5fe2008-07-26 22:42:521361}
1362
[email protected]8807b322010-10-01 17:10:141363// Domain expiry behavior is unchanged by key/expiry scheme (the
[email protected]8ad5d462013-05-02 08:45:261364// meaning of the key is different, but that's not visible to this routine).
jww82d99c12015-11-25 18:39:531365size_t CookieMonster::GarbageCollect(const Time& current,
jwwa26e439d2017-01-27 18:17:271366 const std::string& key) {
mmenkebe0910d2016-03-01 19:09:091367 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041368
jww82d99c12015-11-25 18:39:531369 size_t num_deleted = 0;
mkwstbe84af312015-02-20 08:52:451370 Time safe_date(Time::Now() - TimeDelta::FromDays(kSafeFromGlobalPurgeDays));
initial.commit586acc5fe2008-07-26 22:42:521371
[email protected]8ad5d462013-05-02 08:45:261372 // Collect garbage for this key, minding cookie priorities.
[email protected]7a964a72010-09-07 19:33:261373 if (cookies_.count(key) > kDomainMaxCookies) {
Oscar Johansson63e83cf2018-07-02 08:47:261374 VLOG(net::cookie_util::kVlogGarbageCollection)
1375 << "GarbageCollect() key: " << key;
[email protected]7a964a72010-09-07 19:33:261376
mkwst87734352016-03-03 17:36:231377 CookieItVector* cookie_its;
jww601411a2015-11-20 19:46:571378
mkwst87734352016-03-03 17:36:231379 CookieItVector non_expired_cookie_its;
1380 cookie_its = &non_expired_cookie_its;
jww82d99c12015-11-25 18:39:531381 num_deleted +=
mkwst87734352016-03-03 17:36:231382 GarbageCollectExpired(current, cookies_.equal_range(key), cookie_its);
jww82d99c12015-11-25 18:39:531383
mkwst87734352016-03-03 17:36:231384 if (cookie_its->size() > kDomainMaxCookies) {
Oscar Johansson63e83cf2018-07-02 08:47:261385 VLOG(net::cookie_util::kVlogGarbageCollection)
1386 << "Deep Garbage Collect domain.";
[email protected]8ad5d462013-05-02 08:45:261387 size_t purge_goal =
mkwst87734352016-03-03 17:36:231388 cookie_its->size() - (kDomainMaxCookies - kDomainPurgeCookies);
[email protected]8ad5d462013-05-02 08:45:261389 DCHECK(purge_goal > kDomainPurgeCookies);
1390
mkwste079ac412016-03-11 09:04:061391 // Sort the cookies by access date, from least-recent to most-recent.
1392 std::sort(cookie_its->begin(), cookie_its->end(), LRACookieSorter);
[email protected]8ad5d462013-05-02 08:45:261393
mkwste079ac412016-03-11 09:04:061394 // Remove all but the kDomainCookiesQuotaLow most-recently accessed
1395 // cookies with low-priority. Then, if cookies still need to be removed,
1396 // bump the quota and remove low- and medium-priority. Then, if cookies
1397 // _still_ need to be removed, bump the quota and remove cookies with
1398 // any priority.
jwwc00ac712016-05-05 22:21:441399 //
1400 // 1. Low-priority non-secure cookies.
1401 // 2. Low-priority secure cookies.
1402 // 3. Medium-priority non-secure cookies.
1403 // 4. High-priority non-secure cookies.
1404 // 5. Medium-priority secure cookies.
1405 // 6. High-priority secure cookies.
1406 const static struct {
1407 CookiePriority priority;
1408 bool protect_secure_cookies;
1409 } purge_rounds[] = {
1410 // 1. Low-priority non-secure cookies.
1411 {COOKIE_PRIORITY_LOW, true},
1412 // 2. Low-priority secure cookies.
1413 {COOKIE_PRIORITY_LOW, false},
1414 // 3. Medium-priority non-secure cookies.
1415 {COOKIE_PRIORITY_MEDIUM, true},
1416 // 4. High-priority non-secure cookies.
1417 {COOKIE_PRIORITY_HIGH, true},
1418 // 5. Medium-priority secure cookies.
1419 {COOKIE_PRIORITY_MEDIUM, false},
1420 // 6. High-priority secure cookies.
1421 {COOKIE_PRIORITY_HIGH, false},
1422 };
1423
mkwste079ac412016-03-11 09:04:061424 size_t quota = 0;
jwwc00ac712016-05-05 22:21:441425 for (const auto& purge_round : purge_rounds) {
mmenke645ca6772016-06-17 18:46:431426 // Adjust quota according to the priority of cookies. Each round should
1427 // protect certain number of cookies in order to avoid starvation.
1428 // For example, when each round starts to remove cookies, the number of
1429 // cookies of that priority are counted and a decision whether they
1430 // should be deleted or not is made. If yes, some number of cookies of
1431 // that priority are deleted considering the quota.
jwwc00ac712016-05-05 22:21:441432 switch (purge_round.priority) {
1433 case COOKIE_PRIORITY_LOW:
mmenke645ca6772016-06-17 18:46:431434 quota = kDomainCookiesQuotaLow;
jwwc00ac712016-05-05 22:21:441435 break;
1436 case COOKIE_PRIORITY_MEDIUM:
mmenke645ca6772016-06-17 18:46:431437 quota = kDomainCookiesQuotaMedium;
jwwc00ac712016-05-05 22:21:441438 break;
1439 case COOKIE_PRIORITY_HIGH:
mmenke645ca6772016-06-17 18:46:431440 quota = kDomainCookiesQuotaHigh;
jwwc00ac712016-05-05 22:21:441441 break;
1442 }
jwwc00ac712016-05-05 22:21:441443 size_t just_deleted = 0u;
jwwa26e439d2017-01-27 18:17:271444 // Purge up to |purge_goal| for all cookies at the given priority. This
1445 // path will be taken only if the initial non-secure purge did not evict
1446 // enough cookies.
jwwc00ac712016-05-05 22:21:441447 if (purge_goal > 0) {
1448 just_deleted = PurgeLeastRecentMatches(
1449 cookie_its, purge_round.priority, quota, purge_goal,
1450 purge_round.protect_secure_cookies);
1451 DCHECK_LE(just_deleted, purge_goal);
1452 purge_goal -= just_deleted;
1453 num_deleted += just_deleted;
1454 }
mkwst162d2712016-02-18 18:21:291455 }
mkwste079ac412016-03-11 09:04:061456
jwwc00ac712016-05-05 22:21:441457 DCHECK_EQ(0u, purge_goal);
[email protected]8807b322010-10-01 17:10:141458 }
initial.commit586acc5fe2008-07-26 22:42:521459 }
1460
[email protected]8ad5d462013-05-02 08:45:261461 // Collect garbage for everything. With firefox style we want to preserve
1462 // cookies accessed in kSafeFromGlobalPurgeDays, otherwise evict.
mkwstbe84af312015-02-20 08:52:451463 if (cookies_.size() > kMaxCookies && earliest_access_time_ < safe_date) {
Oscar Johansson63e83cf2018-07-02 08:47:261464 VLOG(net::cookie_util::kVlogGarbageCollection)
1465 << "GarbageCollect() everything";
[email protected]8ad5d462013-05-02 08:45:261466 CookieItVector cookie_its;
jww82d99c12015-11-25 18:39:531467
[email protected]7a964a72010-09-07 19:33:261468 num_deleted += GarbageCollectExpired(
1469 current, CookieMapItPair(cookies_.begin(), cookies_.end()),
1470 &cookie_its);
jww82d99c12015-11-25 18:39:531471
[email protected]8ad5d462013-05-02 08:45:261472 if (cookie_its.size() > kMaxCookies) {
Oscar Johansson63e83cf2018-07-02 08:47:261473 VLOG(net::cookie_util::kVlogGarbageCollection)
1474 << "Deep Garbage Collect everything.";
[email protected]8ad5d462013-05-02 08:45:261475 size_t purge_goal = cookie_its.size() - (kMaxCookies - kPurgeCookies);
1476 DCHECK(purge_goal > kPurgeCookies);
jww82d99c12015-11-25 18:39:531477
jwwa26e439d2017-01-27 18:17:271478 CookieItVector secure_cookie_its;
1479 CookieItVector non_secure_cookie_its;
1480 SplitCookieVectorIntoSecureAndNonSecure(cookie_its, &secure_cookie_its,
1481 &non_secure_cookie_its);
1482 size_t non_secure_purge_goal =
mmenkef4721d992017-06-07 17:13:591483 std::min<size_t>(purge_goal, non_secure_cookie_its.size());
jww82d99c12015-11-25 18:39:531484
mmenkef4721d992017-06-07 17:13:591485 base::Time earliest_non_secure_access_time;
jwwa26e439d2017-01-27 18:17:271486 size_t just_deleted = GarbageCollectLeastRecentlyAccessed(
mmenkef4721d992017-06-07 17:13:591487 current, safe_date, non_secure_purge_goal, non_secure_cookie_its,
1488 &earliest_non_secure_access_time);
jwwa26e439d2017-01-27 18:17:271489 num_deleted += just_deleted;
jww82d99c12015-11-25 18:39:531490
mmenkef4721d992017-06-07 17:13:591491 if (secure_cookie_its.size() == 0) {
1492 // This case is unlikely, but should still update
1493 // |earliest_access_time_| if only have non-secure cookies.
1494 earliest_access_time_ = earliest_non_secure_access_time;
1495 // Garbage collection can't delete all cookies.
1496 DCHECK(!earliest_access_time_.is_null());
1497 } else if (just_deleted < purge_goal) {
1498 size_t secure_purge_goal = std::min<size_t>(purge_goal - just_deleted,
1499 secure_cookie_its.size());
1500 base::Time earliest_secure_access_time;
jww82d99c12015-11-25 18:39:531501 num_deleted += GarbageCollectLeastRecentlyAccessed(
mmenkef4721d992017-06-07 17:13:591502 current, safe_date, secure_purge_goal, secure_cookie_its,
1503 &earliest_secure_access_time);
1504
1505 if (!earliest_non_secure_access_time.is_null() &&
1506 earliest_non_secure_access_time < earliest_secure_access_time) {
1507 earliest_access_time_ = earliest_non_secure_access_time;
1508 } else {
1509 earliest_access_time_ = earliest_secure_access_time;
1510 }
1511
1512 // Garbage collection can't delete all cookies.
1513 DCHECK(!earliest_access_time_.is_null());
jww82d99c12015-11-25 18:39:531514 }
mmenkef4721d992017-06-07 17:13:591515
1516 // If there are secure cookies, but deleting non-secure cookies was enough
1517 // to meet the purge goal, secure cookies are never examined, so
1518 // |earliest_access_time_| can't be determined. Leaving it alone will mean
1519 // it's no later than the real earliest last access time, so this won't
1520 // lead to any problems.
[email protected]8807b322010-10-01 17:10:141521 }
[email protected]c890ed192008-10-30 23:45:531522 }
1523
1524 return num_deleted;
1525}
1526
mkwste079ac412016-03-11 09:04:061527size_t CookieMonster::PurgeLeastRecentMatches(CookieItVector* cookies,
1528 CookiePriority priority,
1529 size_t to_protect,
jwwc00ac712016-05-05 22:21:441530 size_t purge_goal,
1531 bool protect_secure_cookies) {
mkwste079ac412016-03-11 09:04:061532 DCHECK(thread_checker_.CalledOnValidThread());
1533
mmenke645ca6772016-06-17 18:46:431534 // 1. Count number of the cookies at |priority|
1535 size_t cookies_count_possibly_to_be_deleted = CountCookiesForPossibleDeletion(
1536 priority, cookies, false /* count all cookies */);
1537
1538 // 2. If |cookies_count_possibly_to_be_deleted| at |priority| is less than or
1539 // equal |to_protect|, skip round in order to preserve the quota. This
1540 // involves secure and non-secure cookies at |priority|.
1541 if (cookies_count_possibly_to_be_deleted <= to_protect)
1542 return 0u;
1543
1544 // 3. Calculate number of secure cookies at |priority|
1545 // and number of cookies at |priority| that can possibly be deleted.
1546 // It is guaranteed we do not delete more than |purge_goal| even if
1547 // |cookies_count_possibly_to_be_deleted| is higher.
1548 size_t secure_cookies = 0u;
jwwc00ac712016-05-05 22:21:441549 if (protect_secure_cookies) {
mmenke645ca6772016-06-17 18:46:431550 secure_cookies = CountCookiesForPossibleDeletion(
1551 priority, cookies, protect_secure_cookies /* count secure cookies */);
1552 cookies_count_possibly_to_be_deleted -=
1553 std::max(secure_cookies, to_protect - secure_cookies);
1554 } else {
1555 cookies_count_possibly_to_be_deleted -= to_protect;
jwwc00ac712016-05-05 22:21:441556 }
1557
mmenke645ca6772016-06-17 18:46:431558 size_t removed = 0u;
1559 size_t current = 0u;
1560 while ((removed < purge_goal && current < cookies->size()) &&
1561 cookies_count_possibly_to_be_deleted > 0) {
avie7cd11a2016-10-11 02:00:351562 const CanonicalCookie* current_cookie = cookies->at(current)->second.get();
mmenke645ca6772016-06-17 18:46:431563 // Only delete the current cookie if the priority is equal to
1564 // the current level.
jwwc00ac712016-05-05 22:21:441565 if (IsCookieEligibleForEviction(priority, protect_secure_cookies,
1566 current_cookie)) {
mkwstaa07ee82016-03-11 15:32:141567 InternalDeleteCookie(cookies->at(current), true,
1568 DELETE_COOKIE_EVICTED_DOMAIN);
mkwste079ac412016-03-11 09:04:061569 cookies->erase(cookies->begin() + current);
1570 removed++;
mmenke645ca6772016-06-17 18:46:431571 cookies_count_possibly_to_be_deleted--;
mkwste079ac412016-03-11 09:04:061572 } else {
1573 current++;
1574 }
1575 }
1576 return removed;
1577}
1578
jww82d99c12015-11-25 18:39:531579size_t CookieMonster::GarbageCollectExpired(const Time& current,
1580 const CookieMapItPair& itpair,
1581 CookieItVector* cookie_its) {
mmenkebe0910d2016-03-01 19:09:091582 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041583
[email protected]c890ed192008-10-30 23:45:531584 int num_deleted = 0;
1585 for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) {
jdoerrie22a91d8b92018-10-05 08:43:261586 auto curit = it;
[email protected]c890ed192008-10-30 23:45:531587 ++it;
1588
1589 if (curit->second->IsExpired(current)) {
[email protected]2f3f3592010-07-07 20:11:511590 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
[email protected]c890ed192008-10-30 23:45:531591 ++num_deleted;
1592 } else if (cookie_its) {
1593 cookie_its->push_back(curit);
1594 }
initial.commit586acc5fe2008-07-26 22:42:521595 }
1596
1597 return num_deleted;
1598}
1599
jww82d99c12015-11-25 18:39:531600size_t CookieMonster::GarbageCollectDeleteRange(
1601 const Time& current,
1602 DeletionCause cause,
1603 CookieItVector::iterator it_begin,
1604 CookieItVector::iterator it_end) {
mmenkebe0910d2016-03-01 19:09:091605 DCHECK(thread_checker_.CalledOnValidThread());
1606
jdoerrie22a91d8b92018-10-05 08:43:261607 for (auto it = it_begin; it != it_end; it++) {
[email protected]8ad5d462013-05-02 08:45:261608 InternalDeleteCookie((*it), true, cause);
[email protected]c10da4b02010-03-25 14:38:321609 }
[email protected]8ad5d462013-05-02 08:45:261610 return it_end - it_begin;
[email protected]c10da4b02010-03-25 14:38:321611}
1612
mmenke74bcbd52016-01-21 17:17:561613size_t CookieMonster::GarbageCollectLeastRecentlyAccessed(
1614 const base::Time& current,
1615 const base::Time& safe_date,
1616 size_t purge_goal,
mmenkef4721d992017-06-07 17:13:591617 CookieItVector cookie_its,
1618 base::Time* earliest_time) {
1619 DCHECK_LE(purge_goal, cookie_its.size());
mmenkebe0910d2016-03-01 19:09:091620 DCHECK(thread_checker_.CalledOnValidThread());
1621
mmenkef4721d992017-06-07 17:13:591622 // Sorts up to *and including* |cookie_its[purge_goal]| (if it exists), so
1623 // |earliest_time| will be properly assigned even if
mmenke74bcbd52016-01-21 17:17:561624 // |global_purge_it| == |cookie_its.begin() + purge_goal|.
mmenkef4721d992017-06-07 17:13:591625 SortLeastRecentlyAccessed(
1626 cookie_its.begin(), cookie_its.end(),
1627 cookie_its.size() < purge_goal ? purge_goal + 1 : purge_goal);
mmenke74bcbd52016-01-21 17:17:561628 // Find boundary to cookies older than safe_date.
jdoerrie22a91d8b92018-10-05 08:43:261629 auto global_purge_it = LowerBoundAccessDate(
mmenke74bcbd52016-01-21 17:17:561630 cookie_its.begin(), cookie_its.begin() + purge_goal, safe_date);
jwwa26e439d2017-01-27 18:17:271631 // Only delete the old cookies and delete non-secure ones first.
mmenke74bcbd52016-01-21 17:17:561632 size_t num_deleted =
1633 GarbageCollectDeleteRange(current, DELETE_COOKIE_EVICTED_GLOBAL,
1634 cookie_its.begin(), global_purge_it);
mmenkef4721d992017-06-07 17:13:591635 if (global_purge_it != cookie_its.end())
1636 *earliest_time = (*global_purge_it)->second->LastAccessDate();
mmenke74bcbd52016-01-21 17:17:561637 return num_deleted;
1638}
1639
[email protected]ed32c212013-05-14 20:49:291640// A wrapper around registry_controlled_domains::GetDomainAndRegistry
Maks Orlovich323efaf2018-03-06 02:56:391641// to make clear we're creating a key for our local map or for the persistent
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521642// store's use. Here and in FindCookiesForRegistryControlledHost() are the only
1643// two places where we need to conditionalize based on key type.
[email protected]f48b9432011-01-11 07:25:401644//
1645// Note that this key algorithm explicitly ignores the scheme. This is
1646// because when we're entering cookies into the map from the backing store,
1647// we in general won't have the scheme at that point.
1648// In practical terms, this means that file cookies will be stored
1649// in the map either by an empty string or by UNC name (and will be
1650// limited by kMaxCookiesPerHost), and extension cookies will be stored
1651// based on the single extension id, as the extension id won't have the
1652// form of a DNS host and hence GetKey() will return it unchanged.
1653//
1654// Arguably the right thing to do here is to make the key
1655// algorithm dependent on the scheme, and make sure that the scheme is
1656// available everywhere the key must be obtained (specfically at backing
1657// store load time). This would require either changing the backing store
1658// database schema to include the scheme (far more trouble than it's worth), or
1659// separating out file cookies into their own CookieMonster instance and
1660// thus restricting each scheme to a single cookie monster (which might
1661// be worth it, but is still too much trouble to solve what is currently a
1662// non-problem).
Maks Orlovich323efaf2018-03-06 02:56:391663//
1664// static
1665std::string CookieMonster::GetKey(base::StringPiece domain) {
[email protected]f48b9432011-01-11 07:25:401666 std::string effective_domain(
[email protected]ed32c212013-05-14 20:49:291667 registry_controlled_domains::GetDomainAndRegistry(
[email protected]aabe1792014-01-30 21:37:461668 domain, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES));
[email protected]f48b9432011-01-11 07:25:401669 if (effective_domain.empty())
Maks Orlovich323efaf2018-03-06 02:56:391670 domain.CopyToString(&effective_domain);
[email protected]f48b9432011-01-11 07:25:401671
1672 if (!effective_domain.empty() && effective_domain[0] == '.')
1673 return effective_domain.substr(1);
1674 return effective_domain;
1675}
1676
1677bool CookieMonster::HasCookieableScheme(const GURL& url) {
mmenkebe0910d2016-03-01 19:09:091678 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401679
1680 // Make sure the request is on a cookie-able url scheme.
1681 for (size_t i = 0; i < cookieable_schemes_.size(); ++i) {
1682 // We matched a scheme.
1683 if (url.SchemeIs(cookieable_schemes_[i].c_str())) {
1684 // We've matched a supported scheme.
initial.commit586acc5fe2008-07-26 22:42:521685 return true;
1686 }
1687 }
[email protected]f48b9432011-01-11 07:25:401688
1689 // The scheme didn't match any in our whitelist.
Oscar Johansson63e83cf2018-07-02 08:47:261690 VLOG(net::cookie_util::kVlogPerCookieMonster)
mkwstbe84af312015-02-20 08:52:451691 << "WARNING: Unsupported cookie scheme: " << url.scheme();
initial.commit586acc5fe2008-07-26 22:42:521692 return false;
1693}
1694
[email protected]c4058fb2010-06-22 17:25:261695// Test to see if stats should be recorded, and record them if so.
1696// The goal here is to get sampling for the average browser-hour of
1697// activity. We won't take samples when the web isn't being surfed,
1698// and when the web is being surfed, we'll take samples about every
1699// kRecordStatisticsIntervalSeconds.
1700// last_statistic_record_time_ is initialized to Now() rather than null
1701// in the constructor so that we won't take statistics right after
1702// startup, to avoid bias from browsers that are started but not used.
1703void CookieMonster::RecordPeriodicStats(const base::Time& current_time) {
mmenkebe0910d2016-03-01 19:09:091704 DCHECK(thread_checker_.CalledOnValidThread());
1705
[email protected]c4058fb2010-06-22 17:25:261706 const base::TimeDelta kRecordStatisticsIntervalTime(
1707 base::TimeDelta::FromSeconds(kRecordStatisticsIntervalSeconds));
1708
[email protected]7a964a72010-09-07 19:33:261709 // If we've taken statistics recently, return.
1710 if (current_time - last_statistic_record_time_ <=
[email protected]c4058fb2010-06-22 17:25:261711 kRecordStatisticsIntervalTime) {
[email protected]7a964a72010-09-07 19:33:261712 return;
[email protected]c4058fb2010-06-22 17:25:261713 }
[email protected]7a964a72010-09-07 19:33:261714
1715 // See InitializeHistograms() for details.
1716 histogram_count_->Add(cookies_.size());
1717
1718 // More detailed statistics on cookie counts at different granularities.
[email protected]7a964a72010-09-07 19:33:261719 last_statistic_record_time_ = current_time;
[email protected]c4058fb2010-06-22 17:25:261720}
1721
[email protected]f48b9432011-01-11 07:25:401722// Initialize all histogram counter variables used in this class.
1723//
1724// Normal histogram usage involves using the macros defined in
1725// histogram.h, which automatically takes care of declaring these
1726// variables (as statics), initializing them, and accumulating into
1727// them, all from a single entry point. Unfortunately, that solution
1728// doesn't work for the CookieMonster, as it's vulnerable to races between
1729// separate threads executing the same functions and hence initializing the
1730// same static variables. There isn't a race danger in the histogram
1731// accumulation calls; they are written to be resilient to simultaneous
1732// calls from multiple threads.
1733//
1734// The solution taken here is to have per-CookieMonster instance
1735// variables that are constructed during CookieMonster construction.
1736// Note that these variables refer to the same underlying histogram,
1737// so we still race (but safely) with other CookieMonster instances
1738// for accumulation.
1739//
1740// To do this we've expanded out the individual histogram macros calls,
1741// with declarations of the variables in the class decl, initialization here
1742// (done from the class constructor) and direct calls to the accumulation
1743// methods where needed. The specific histogram macro calls on which the
1744// initialization is based are included in comments below.
1745void CookieMonster::InitializeHistograms() {
mmenkebe0910d2016-03-01 19:09:091746 DCHECK(thread_checker_.CalledOnValidThread());
1747
[email protected]f48b9432011-01-11 07:25:401748 // From UMA_HISTOGRAM_CUSTOM_COUNTS
1749 histogram_expiration_duration_minutes_ = base::Histogram::FactoryGet(
mkwstbe84af312015-02-20 08:52:451750 "Cookie.ExpirationDurationMinutes", 1, kMinutesInTenYears, 50,
[email protected]f48b9432011-01-11 07:25:401751 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401752 histogram_count_ = base::Histogram::FactoryGet(
mkwstbe84af312015-02-20 08:52:451753 "Cookie.Count", 1, 4000, 50, base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401754
1755 // From UMA_HISTOGRAM_ENUMERATION
mkwstc1aa4cc2015-04-03 19:57:451756 histogram_cookie_type_ = base::LinearHistogram::FactoryGet(
mkwst87378d92015-04-10 21:22:111757 "Cookie.Type", 1, (1 << COOKIE_TYPE_LAST_ENTRY) - 1,
1758 1 << COOKIE_TYPE_LAST_ENTRY, base::Histogram::kUmaTargetedHistogramFlag);
estark7feb65c2b2015-08-21 23:38:201759 histogram_cookie_source_scheme_ = base::LinearHistogram::FactoryGet(
1760 "Cookie.CookieSourceScheme", 1, COOKIE_SOURCE_LAST_ENTRY - 1,
1761 COOKIE_SOURCE_LAST_ENTRY, base::Histogram::kUmaTargetedHistogramFlag);
jww31e32632015-12-16 23:38:341762 histogram_cookie_delete_equivalent_ = base::LinearHistogram::FactoryGet(
1763 "Cookie.CookieDeleteEquivalent", 1,
1764 COOKIE_DELETE_EQUIVALENT_LAST_ENTRY - 1,
1765 COOKIE_DELETE_EQUIVALENT_LAST_ENTRY,
1766 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401767
1768 // From UMA_HISTOGRAM_{CUSTOM_,}TIMES
[email protected]c7593fb22011-11-14 23:54:271769 histogram_time_blocked_on_load_ = base::Histogram::FactoryTimeGet(
mkwstbe84af312015-02-20 08:52:451770 "Cookie.TimeBlockedOnLoad", base::TimeDelta::FromMilliseconds(1),
1771 base::TimeDelta::FromMinutes(1), 50,
1772 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401773}
1774
rdsmithe5c701d2017-07-12 21:50:001775void CookieMonster::DoCookieCallback(base::OnceClosure callback) {
mmenkebe0910d2016-03-01 19:09:091776 DCHECK(thread_checker_.CalledOnValidThread());
1777
1778 MarkCookieStoreAsInitialized();
1779 FetchAllCookiesIfNecessary();
mmenkef49fca0e2016-03-08 12:46:241780 seen_global_task_ = true;
mmenkebe0910d2016-03-01 19:09:091781
1782 if (!finished_fetching_all_cookies_ && store_.get()) {
rdsmithe5c701d2017-07-12 21:50:001783 tasks_pending_.push_back(std::move(callback));
mmenkebe0910d2016-03-01 19:09:091784 return;
mmenke74bcbd52016-01-21 17:17:561785 }
1786
rdsmithe5c701d2017-07-12 21:50:001787 std::move(callback).Run();
mmenke74bcbd52016-01-21 17:17:561788}
1789
rdsmithe5c701d2017-07-12 21:50:001790void CookieMonster::DoCookieCallbackForURL(base::OnceClosure callback,
1791 const GURL& url) {
Maks Orlovich323efaf2018-03-06 02:56:391792 DoCookieCallbackForHostOrDomain(std::move(callback), url.host_piece());
1793}
1794
1795void CookieMonster::DoCookieCallbackForHostOrDomain(
1796 base::OnceClosure callback,
1797 base::StringPiece host_or_domain) {
mmenkebe0910d2016-03-01 19:09:091798 MarkCookieStoreAsInitialized();
erikchende4c39e2018-01-29 21:33:361799 FetchAllCookiesIfNecessary();
mmenkebe0910d2016-03-01 19:09:091800
1801 // If cookies for the requested domain key (eTLD+1) have been loaded from DB
1802 // then run the task, otherwise load from DB.
1803 if (!finished_fetching_all_cookies_ && store_.get()) {
mmenkef49fca0e2016-03-08 12:46:241804 // If a global task has been previously seen, queue the task as a global
1805 // task. Note that the CookieMonster may be in the middle of executing
1806 // the global queue, |tasks_pending_| may be empty, which is why another
1807 // bool is needed.
1808 if (seen_global_task_) {
rdsmithe5c701d2017-07-12 21:50:001809 tasks_pending_.push_back(std::move(callback));
mmenkef49fca0e2016-03-08 12:46:241810 return;
1811 }
1812
mmenkebe0910d2016-03-01 19:09:091813 // Checks if the domain key has been loaded.
Maks Orlovich323efaf2018-03-06 02:56:391814 std::string key = GetKey(host_or_domain);
mmenkebe0910d2016-03-01 19:09:091815 if (keys_loaded_.find(key) == keys_loaded_.end()) {
jdoerrie22a91d8b92018-10-05 08:43:261816 auto it = tasks_pending_for_key_.find(key);
mmenkebe0910d2016-03-01 19:09:091817 if (it == tasks_pending_for_key_.end()) {
1818 store_->LoadCookiesForKey(
1819 key, base::Bind(&CookieMonster::OnKeyLoaded,
1820 weak_ptr_factory_.GetWeakPtr(), key));
1821 it = tasks_pending_for_key_
Brett Wilsonc6a0c822017-09-12 00:04:291822 .insert(std::make_pair(
1823 key, base::circular_deque<base::OnceClosure>()))
mmenkebe0910d2016-03-01 19:09:091824 .first;
mmenke74bcbd52016-01-21 17:17:561825 }
rdsmithe5c701d2017-07-12 21:50:001826 it->second.push_back(std::move(callback));
mmenkebe0910d2016-03-01 19:09:091827 return;
mmenke74bcbd52016-01-21 17:17:561828 }
1829 }
mmenkebe0910d2016-03-01 19:09:091830
rdsmithe5c701d2017-07-12 21:50:001831 std::move(callback).Run();
mmenke74bcbd52016-01-21 17:17:561832}
1833
[email protected]63725312012-07-19 08:24:161834} // namespace net