blob: ba98b041aad932aa2847ef6d2d7fafb59d254cd3 [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"
nharper2b0ad9a2017-05-22 18:33:4572#include "net/ssl/channel_id_service.h"
mkwst8241a122015-10-20 07:15:1073#include "url/origin.h"
initial.commit586acc5fe2008-07-26 22:42:5274
[email protected]e1acf6f2008-10-27 20:43:3375using base::Time;
76using base::TimeDelta;
[email protected]7a964a72010-09-07 19:33:2677using base::TimeTicks;
Chris Mumfordd8ed9f82018-05-01 15:43:1378using TimeRange = net::CookieDeletionInfo::TimeRange;
[email protected]e1acf6f2008-10-27 20:43:3379
[email protected]8562034e2011-10-17 17:35:0480// In steady state, most cookie requests can be satisfied by the in memory
erikchen1dd72a72015-05-06 20:45:0581// cookie monster store. If the cookie request cannot be satisfied by the in
82// memory store, the relevant cookies must be fetched from the persistent
83// store. The task is queued in CookieMonster::tasks_pending_ if it requires
84// all cookies to be loaded from the backend, or tasks_pending_for_key_ if it
85// only requires all cookies associated with an eTLD+1.
[email protected]8562034e2011-10-17 17:35:0486//
87// On the browser critical paths (e.g. for loading initial web pages in a
88// session restore) it may take too long to wait for the full load. If a cookie
rdsmithe5c701d2017-07-12 21:50:0089// request is for a specific URL, DoCookieCallbackForURL is called, which
90// triggers a priority load if the key is not loaded yet by calling
91// PersistentCookieStore::LoadCookiesForKey. The request is queued in
[email protected]0184df32013-05-14 00:53:5592// CookieMonster::tasks_pending_for_key_ and executed upon receiving
93// notification of key load completion via CookieMonster::OnKeyLoaded(). If
94// multiple requests for the same eTLD+1 are received before key load
95// completion, only the first request calls
[email protected]8562034e2011-10-17 17:35:0496// PersistentCookieStore::LoadCookiesForKey, all subsequent requests are queued
[email protected]0184df32013-05-14 00:53:5597// in CookieMonster::tasks_pending_for_key_ and executed upon receiving
98// notification of key load completion triggered by the first request for the
99// same eTLD+1.
[email protected]8562034e2011-10-17 17:35:04100
[email protected]c4058fb2010-06-22 17:25:26101static const int kMinutesInTenYears = 10 * 365 * 24 * 60;
102
erikchen1dd72a72015-05-06 20:45:05103namespace {
104
Maks Orlovichf97d1b92018-03-06 17:25:39105void MaybeRunDeleteCallback(base::WeakPtr<net::CookieMonster> cookie_monster,
106 base::OnceClosure callback) {
rdsmithe5c701d2017-07-12 21:50:00107 if (cookie_monster && callback)
108 std::move(callback).Run();
109}
110
rdsmithe5c701d2017-07-12 21:50:00111template <typename T>
112void MaybeRunCookieCallback(base::OnceCallback<void(const T&)> callback,
113 const T& result) {
114 if (callback)
115 std::move(callback).Run(result);
116}
117
Aaron Tagliaboschia4c64b52019-01-25 03:28:49118template <typename T, typename U>
119void MaybeRunCookieCallback(
120 base::OnceCallback<void(const T&, const U&)> callback,
121 const T& first,
122 const U& second) {
123 if (callback)
124 std::move(callback).Run(first, second);
125}
126
rdsmithe5c701d2017-07-12 21:50:00127template <typename T>
128void MaybeRunCookieCallback(base::OnceCallback<void(T)> callback,
129 const T& result) {
130 if (callback)
131 std::move(callback).Run(result);
132}
133
erikchen1dd72a72015-05-06 20:45:05134} // namespace
135
[email protected]8ac1a752008-07-31 19:40:37136namespace net {
137
[email protected]7a964a72010-09-07 19:33:26138// See comments at declaration of these variables in cookie_monster.h
139// for details.
mkwstbe84af312015-02-20 08:52:45140const size_t CookieMonster::kDomainMaxCookies = 180;
141const size_t CookieMonster::kDomainPurgeCookies = 30;
142const size_t CookieMonster::kMaxCookies = 3300;
143const size_t CookieMonster::kPurgeCookies = 300;
[email protected]8ad5d462013-05-02 08:45:26144
mkwst87734352016-03-03 17:36:23145const size_t CookieMonster::kDomainCookiesQuotaLow = 30;
146const size_t CookieMonster::kDomainCookiesQuotaMedium = 50;
147const size_t CookieMonster::kDomainCookiesQuotaHigh =
148 kDomainMaxCookies - kDomainPurgeCookies - kDomainCookiesQuotaLow -
149 kDomainCookiesQuotaMedium;
[email protected]8ad5d462013-05-02 08:45:26150
mkwstbe84af312015-02-20 08:52:45151const int CookieMonster::kSafeFromGlobalPurgeDays = 30;
[email protected]297a4ed02010-02-12 08:12:52152
[email protected]7a964a72010-09-07 19:33:26153namespace {
[email protected]e32306c52008-11-06 16:59:05154
[email protected]6210ce52013-09-20 03:33:14155bool ContainsControlCharacter(const std::string& s) {
156 for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
157 if ((*i >= 0) && (*i <= 31))
158 return true;
159 }
160
161 return false;
162}
163
[email protected]5b9bc352012-07-18 13:13:34164typedef std::vector<CanonicalCookie*> CanonicalCookieVector;
[email protected]34a160d2011-05-12 22:12:49165
[email protected]77e0a462008-11-01 00:43:35166// Default minimum delay after updating a cookie's LastAccessDate before we
167// will update it again.
[email protected]297a4ed02010-02-12 08:12:52168const int kDefaultAccessUpdateThresholdSeconds = 60;
169
170// Comparator to sort cookies from highest creation date to lowest
171// creation date.
172struct OrderByCreationTimeDesc {
173 bool operator()(const CookieMonster::CookieMap::iterator& a,
174 const CookieMonster::CookieMap::iterator& b) const {
175 return a->second->CreationDate() > b->second->CreationDate();
176 }
177};
178
[email protected]f48b9432011-01-11 07:25:40179// Mozilla sorts on the path length (longest first), and then it
180// sorts by creation time (oldest first).
181// The RFC says the sort order for the domain attribute is undefined.
[email protected]5b9bc352012-07-18 13:13:34182bool CookieSorter(CanonicalCookie* cc1, CanonicalCookie* cc2) {
[email protected]f48b9432011-01-11 07:25:40183 if (cc1->Path().length() == cc2->Path().length())
184 return cc1->CreationDate() < cc2->CreationDate();
185 return cc1->Path().length() > cc2->Path().length();
initial.commit586acc5fe2008-07-26 22:42:52186}
187
[email protected]8ad5d462013-05-02 08:45:26188bool LRACookieSorter(const CookieMonster::CookieMap::iterator& it1,
[email protected]f48b9432011-01-11 07:25:40189 const CookieMonster::CookieMap::iterator& it2) {
[email protected]f48b9432011-01-11 07:25:40190 if (it1->second->LastAccessDate() != it2->second->LastAccessDate())
191 return it1->second->LastAccessDate() < it2->second->LastAccessDate();
initial.commit586acc5fe2008-07-26 22:42:52192
mkwste079ac412016-03-11 09:04:06193 // Ensure stability for == last access times by falling back to creation.
[email protected]f48b9432011-01-11 07:25:40194 return it1->second->CreationDate() < it2->second->CreationDate();
[email protected]297a4ed02010-02-12 08:12:52195}
196
197// Our strategy to find duplicates is:
198// (1) Build a map from (cookiename, cookiepath) to
199// {list of cookies with this signature, sorted by creation time}.
200// (2) For each list with more than 1 entry, keep the cookie having the
201// most recent creation time, and delete the others.
[email protected]f48b9432011-01-11 07:25:40202//
[email protected]1655ba342010-07-14 18:17:42203// Two cookies are considered equivalent if they have the same domain,
204// name, and path.
205struct CookieSignature {
206 public:
[email protected]dedec0b2013-02-28 04:50:10207 CookieSignature(const std::string& name,
208 const std::string& domain,
[email protected]1655ba342010-07-14 18:17:42209 const std::string& path)
mkwstbe84af312015-02-20 08:52:45210 : name(name), domain(domain), path(path) {}
[email protected]1655ba342010-07-14 18:17:42211
212 // To be a key for a map this class needs to be assignable, copyable,
213 // and have an operator<. The default assignment operator
214 // and copy constructor are exactly what we want.
215
216 bool operator<(const CookieSignature& cs) const {
217 // Name compare dominates, then domain, then path.
218 int diff = name.compare(cs.name);
219 if (diff != 0)
220 return diff < 0;
221
222 diff = domain.compare(cs.domain);
223 if (diff != 0)
224 return diff < 0;
225
226 return path.compare(cs.path) < 0;
227 }
228
229 std::string name;
230 std::string domain;
231 std::string path;
232};
[email protected]f48b9432011-01-11 07:25:40233
[email protected]8ad5d462013-05-02 08:45:26234// For a CookieItVector iterator range [|it_begin|, |it_end|),
mmenkef4721d992017-06-07 17:13:59235// sorts the first |num_sort| elements by LastAccessDate().
mkwstbe84af312015-02-20 08:52:45236void SortLeastRecentlyAccessed(CookieMonster::CookieItVector::iterator it_begin,
237 CookieMonster::CookieItVector::iterator it_end,
238 size_t num_sort) {
mmenkef4721d992017-06-07 17:13:59239 DCHECK_LE(static_cast<int>(num_sort), it_end - it_begin);
240 std::partial_sort(it_begin, it_begin + num_sort, it_end, LRACookieSorter);
[email protected]8ad5d462013-05-02 08:45:26241}
[email protected]f48b9432011-01-11 07:25:40242
jww82d99c12015-11-25 18:39:53243// Given a single cookie vector |cookie_its|, pushs all of the secure cookies in
244// |cookie_its| into |secure_cookie_its| and all of the non-secure cookies into
245// |non_secure_cookie_its|. Both |secure_cookie_its| and |non_secure_cookie_its|
246// must be non-NULL.
247void SplitCookieVectorIntoSecureAndNonSecure(
248 const CookieMonster::CookieItVector& cookie_its,
249 CookieMonster::CookieItVector* secure_cookie_its,
250 CookieMonster::CookieItVector* non_secure_cookie_its) {
251 DCHECK(secure_cookie_its && non_secure_cookie_its);
252 for (const auto& curit : cookie_its) {
253 if (curit->second->IsSecure())
254 secure_cookie_its->push_back(curit);
255 else
256 non_secure_cookie_its->push_back(curit);
257 }
258}
259
mkwstbe84af312015-02-20 08:52:45260bool LowerBoundAccessDateComparator(const CookieMonster::CookieMap::iterator it,
261 const Time& access_date) {
[email protected]8ad5d462013-05-02 08:45:26262 return it->second->LastAccessDate() < access_date;
263}
264
265// For a CookieItVector iterator range [|it_begin|, |it_end|)
266// from a CookieItVector sorted by LastAccessDate(), returns the
267// first iterator with access date >= |access_date|, or cookie_its_end if this
268// holds for all.
269CookieMonster::CookieItVector::iterator LowerBoundAccessDate(
270 const CookieMonster::CookieItVector::iterator its_begin,
271 const CookieMonster::CookieItVector::iterator its_end,
272 const Time& access_date) {
273 return std::lower_bound(its_begin, its_end, access_date,
274 LowerBoundAccessDateComparator);
[email protected]7a964a72010-09-07 19:33:26275}
276
Victor Costan14f47c12018-03-01 08:02:24277// Mapping between DeletionCause and CookieChangeCause; the
[email protected]7c4b66b2014-01-04 12:28:13278// mapping also provides a boolean that specifies whether or not an
Victor Costan14f47c12018-03-01 08:02:24279// OnCookieChange notification ought to be generated.
[email protected]8bb846f2011-03-23 12:08:18280typedef struct ChangeCausePair_struct {
Victor Costan14f47c12018-03-01 08:02:24281 CookieChangeCause cause;
[email protected]8bb846f2011-03-23 12:08:18282 bool notify;
283} ChangeCausePair;
nharper352933e2016-09-30 18:24:57284const ChangeCausePair kChangeCauseMapping[] = {
mkwstbe84af312015-02-20 08:52:45285 // DELETE_COOKIE_EXPLICIT
Victor Costan14f47c12018-03-01 08:02:24286 {CookieChangeCause::EXPLICIT, true},
mkwstbe84af312015-02-20 08:52:45287 // DELETE_COOKIE_OVERWRITE
Victor Costan14f47c12018-03-01 08:02:24288 {CookieChangeCause::OVERWRITE, true},
mkwstbe84af312015-02-20 08:52:45289 // DELETE_COOKIE_EXPIRED
Victor Costan14f47c12018-03-01 08:02:24290 {CookieChangeCause::EXPIRED, true},
mkwstbe84af312015-02-20 08:52:45291 // DELETE_COOKIE_EVICTED
Victor Costan14f47c12018-03-01 08:02:24292 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45293 // DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE
Victor Costan14f47c12018-03-01 08:02:24294 {CookieChangeCause::EXPLICIT, false},
mkwstbe84af312015-02-20 08:52:45295 // DELETE_COOKIE_DONT_RECORD
Victor Costan14f47c12018-03-01 08:02:24296 {CookieChangeCause::EXPLICIT, false},
mkwstbe84af312015-02-20 08:52:45297 // DELETE_COOKIE_EVICTED_DOMAIN
Victor Costan14f47c12018-03-01 08:02:24298 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45299 // DELETE_COOKIE_EVICTED_GLOBAL
Victor Costan14f47c12018-03-01 08:02:24300 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45301 // DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE
Victor Costan14f47c12018-03-01 08:02:24302 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45303 // DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE
Victor Costan14f47c12018-03-01 08:02:24304 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45305 // DELETE_COOKIE_EXPIRED_OVERWRITE
Victor Costan14f47c12018-03-01 08:02:24306 {CookieChangeCause::EXPIRED_OVERWRITE, true},
mkwstbe84af312015-02-20 08:52:45307 // DELETE_COOKIE_CONTROL_CHAR
Victor Costan14f47c12018-03-01 08:02:24308 {CookieChangeCause::EVICTED, true},
jww82d99c12015-11-25 18:39:53309 // DELETE_COOKIE_NON_SECURE
Victor Costan14f47c12018-03-01 08:02:24310 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45311 // DELETE_COOKIE_LAST_ENTRY
Victor Costan14f47c12018-03-01 08:02:24312 {CookieChangeCause::EXPLICIT, false}};
ellyjones399e35a22014-10-27 11:09:56313
jwwc00ac712016-05-05 22:21:44314bool IsCookieEligibleForEviction(CookiePriority current_priority_level,
315 bool protect_secure_cookies,
316 const CanonicalCookie* cookie) {
mmenke645ca6772016-06-17 18:46:43317 if (cookie->Priority() == current_priority_level && protect_secure_cookies)
318 return !cookie->IsSecure();
jwwc00ac712016-05-05 22:21:44319
mmenke645ca6772016-06-17 18:46:43320 return cookie->Priority() == current_priority_level;
321}
jwwc00ac712016-05-05 22:21:44322
mmenke645ca6772016-06-17 18:46:43323size_t CountCookiesForPossibleDeletion(
324 CookiePriority priority,
325 const CookieMonster::CookieItVector* cookies,
326 bool protect_secure_cookies) {
327 size_t cookies_count = 0U;
328 for (const auto& cookie : *cookies) {
329 if (cookie->second->Priority() == priority) {
330 if (!protect_secure_cookies || cookie->second->IsSecure())
331 cookies_count++;
332 }
333 }
334 return cookies_count;
jwwc00ac712016-05-05 22:21:44335}
336
[email protected]f48b9432011-01-11 07:25:40337} // namespace
338
Pritam8354cf702018-03-10 08:55:41339CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
Helen Lifb313a92018-08-14 15:46:44340 ChannelIDService* channel_id_service,
341 NetLog* net_log)
Randy Smithb78e0922018-03-01 21:19:54342 : CookieMonster(
Pritam8354cf702018-03-10 08:55:41343 std::move(store),
Randy Smithb78e0922018-03-01 21:19:54344 channel_id_service,
Helen Lifb313a92018-08-14 15:46:44345 base::TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds),
346 net_log) {}
Randy Smithb78e0922018-03-01 21:19:54347
Pritam8354cf702018-03-10 08:55:41348CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
Helen Lifb313a92018-08-14 15:46:44349 base::TimeDelta last_access_threshold,
350 NetLog* net_log)
351 : CookieMonster(std::move(store), nullptr, last_access_threshold, net_log) {
352}
Randy Smithb78e0922018-03-01 21:19:54353
Pritam8354cf702018-03-10 08:55:41354CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
Randy Smithb78e0922018-03-01 21:19:54355 ChannelIDService* channel_id_service,
Helen Lifb313a92018-08-14 15:46:44356 base::TimeDelta last_access_threshold,
357 NetLog* net_log)
[email protected]f48b9432011-01-11 07:25:40358 : initialized_(false),
erikchen1dd72a72015-05-06 20:45:05359 started_fetching_all_cookies_(false),
360 finished_fetching_all_cookies_(false),
mmenkef49fca0e2016-03-08 12:46:24361 seen_global_task_(false),
Helen Lifb313a92018-08-14 15:46:44362 net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::COOKIE_STORE)),
Pritam8354cf702018-03-10 08:55:41363 store_(std::move(store)),
shessf0bc1182016-05-19 04:35:58364 last_access_threshold_(last_access_threshold),
nharper2b0ad9a2017-05-22 18:33:45365 channel_id_service_(channel_id_service),
[email protected]82388662011-03-10 21:04:06366 last_statistic_record_time_(base::Time::Now()),
mmenkebe0910d2016-03-01 19:09:09367 persist_session_cookies_(false),
368 weak_ptr_factory_(this) {
[email protected]f48b9432011-01-11 07:25:40369 InitializeHistograms();
mmenke18dd8ba2016-02-01 18:42:10370 cookieable_schemes_.insert(
371 cookieable_schemes_.begin(), kDefaultCookieableSchemes,
372 kDefaultCookieableSchemes + kDefaultCookieableSchemesCount);
Nick Harper14e23332017-07-28 00:27:23373 if (channel_id_service_ && store_) {
374 // |store_| can outlive this CookieMonster, but there are no guarantees
375 // about the lifetime of |channel_id_service_| relative to |store_|. The
376 // only guarantee is that |channel_id_service_| will outlive this
377 // CookieMonster. To avoid the PersistentCookieStore retaining a pointer to
378 // the ChannelIDStore via this callback after this CookieMonster is
379 // destroyed, CookieMonster's d'tor sets the callback to a null callback.
380 store_->SetBeforeFlushCallback(
381 base::Bind(&ChannelIDStore::Flush,
382 base::Unretained(channel_id_service_->GetChannelIDStore())));
383 }
Helen Licd0fab862018-08-13 16:07:53384 net_log_.BeginEvent(
385 NetLogEventType::COOKIE_STORE_ALIVE,
386 base::BindRepeating(&NetLogCookieMonsterConstructorCallback,
387 store != nullptr, channel_id_service != nullptr));
initial.commit586acc5fe2008-07-26 22:42:52388}
389
[email protected]218aa6a12011-09-13 17:38:38390// Asynchronous CookieMonster API
391
rdsmith7ac81712017-06-22 17:09:54392void CookieMonster::FlushStore(base::OnceClosure callback) {
mmenkebe0910d2016-03-01 19:09:09393 DCHECK(thread_checker_.CalledOnValidThread());
mmenke606c59c2016-03-07 18:20:55394
nharper2b0ad9a2017-05-22 18:33:45395 if (initialized_ && store_.get()) {
rdsmith7ac81712017-06-22 17:09:54396 store_->Flush(std::move(callback));
rdsmithe5c701d2017-07-12 21:50:00397 } else if (callback) {
rdsmith7ac81712017-06-22 17:09:54398 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
399 std::move(callback));
nharper2b0ad9a2017-05-22 18:33:45400 }
mmenke74bcbd52016-01-21 17:17:56401}
402
mmenkeded79da2016-02-06 08:28:51403void CookieMonster::SetForceKeepSessionState() {
mmenkebe0910d2016-03-01 19:09:09404 DCHECK(thread_checker_.CalledOnValidThread());
mmenke606c59c2016-03-07 18:20:55405
mmenkeded79da2016-02-06 08:28:51406 if (store_)
407 store_->SetForceKeepSessionState();
408}
409
drogerd5d1278c2015-03-17 19:21:51410void CookieMonster::SetAllCookiesAsync(const CookieList& list,
rdsmith7ac81712017-06-22 17:09:54411 SetCookiesCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00412 DoCookieCallback(base::BindOnce(
413 // base::Unretained is safe as DoCookieCallbackForURL stores
414 // the callback on |*this|, so the callback will not outlive
415 // the object.
416 &CookieMonster::SetAllCookies, base::Unretained(this), list,
417 std::move(callback)));
drogerd5d1278c2015-03-17 19:21:51418}
419
rdsmitha6ce4442017-06-21 17:11:05420void CookieMonster::SetCanonicalCookieAsync(
421 std::unique_ptr<CanonicalCookie> cookie,
422 bool secure_source,
423 bool modify_http_only,
rdsmith7ac81712017-06-22 17:09:54424 SetCookiesCallback callback) {
rdsmitha6ce4442017-06-21 17:11:05425 DCHECK(cookie->IsCanonical());
rdsmitha6ce4442017-06-21 17:11:05426
Maks Orlovich323efaf2018-03-06 02:56:39427 std::string domain = cookie->Domain();
428 DoCookieCallbackForHostOrDomain(
429 base::BindOnce(
430 // base::Unretained is safe as DoCookieCallbackForURL stores
431 // the callback on |*this|, so the callback will not outlive
432 // the object.
433 &CookieMonster::SetCanonicalCookie, base::Unretained(this),
434 std::move(cookie), secure_source, modify_http_only,
435 std::move(callback)),
436 domain);
rdsmitha6ce4442017-06-21 17:11:05437}
438
rdsmith7ac81712017-06-22 17:09:54439void CookieMonster::SetCookieWithOptionsAsync(const GURL& url,
440 const std::string& cookie_line,
441 const CookieOptions& options,
442 SetCookiesCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00443 DoCookieCallbackForURL(
444 base::BindOnce(
445 // base::Unretained is safe as DoCookieCallbackForURL stores
446 // the callback on |*this|, so the callback will not outlive
447 // the object.
448 &CookieMonster::SetCookieWithOptions, base::Unretained(this), url,
449 cookie_line, options, std::move(callback)),
450 url);
[email protected]218aa6a12011-09-13 17:38:38451}
452
mkwstc611e6d2016-02-23 15:45:55453void CookieMonster::GetCookieListWithOptionsAsync(
mmenke74bcbd52016-01-21 17:17:56454 const GURL& url,
mkwstc611e6d2016-02-23 15:45:55455 const CookieOptions& options,
rdsmith7ac81712017-06-22 17:09:54456 GetCookieListCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00457 DoCookieCallbackForURL(
Ken Rockotec216e3dd2019-02-20 00:43:59458 base::BindOnce(
rdsmithe5c701d2017-07-12 21:50:00459 // base::Unretained is safe as DoCookieCallbackForURL stores
460 // the callback on |*this|, so the callback will not outlive
461 // the object.
462 &CookieMonster::GetCookieListWithOptions, base::Unretained(this), url,
Ken Rockotec216e3dd2019-02-20 00:43:59463 options, std::move(callback)),
rdsmithe5c701d2017-07-12 21:50:00464 url);
mmenke74bcbd52016-01-21 17:17:56465}
466
rdsmith7ac81712017-06-22 17:09:54467void CookieMonster::GetAllCookiesAsync(GetCookieListCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00468 DoCookieCallback(base::BindOnce(
469 // base::Unretained is safe as DoCookieCallbackForURL stores
470 // the callback on |*this|, so the callback will not outlive
471 // the object.
472 &CookieMonster::GetAllCookies, base::Unretained(this),
473 std::move(callback)));
mmenke9fa44f2d2016-01-22 23:36:39474}
475
mmenke24379d52016-02-05 23:50:17476void CookieMonster::DeleteCanonicalCookieAsync(const CanonicalCookie& cookie,
rdsmith7ac81712017-06-22 17:09:54477 DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00478 DoCookieCallback(base::BindOnce(
479 // base::Unretained is safe as DoCookieCallbackForURL stores
480 // the callback on |*this|, so the callback will not outlive
481 // the object.
482 &CookieMonster::DeleteCanonicalCookie, base::Unretained(this), cookie,
483 std::move(callback)));
mmenke24379d52016-02-05 23:50:17484}
485
Chris Mumford800caa62018-04-20 19:34:44486void CookieMonster::DeleteAllCreatedInTimeRangeAsync(
487 const TimeRange& creation_range,
488 DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00489 DoCookieCallback(base::BindOnce(
490 // base::Unretained is safe as DoCookieCallbackForURL stores
491 // the callback on |*this|, so the callback will not outlive
492 // the object.
Chris Mumford800caa62018-04-20 19:34:44493 &CookieMonster::DeleteAllCreatedInTimeRange, base::Unretained(this),
494 creation_range, std::move(callback)));
mmenke74bcbd52016-01-21 17:17:56495}
496
Chris Mumford800caa62018-04-20 19:34:44497void CookieMonster::DeleteAllMatchingInfoAsync(CookieDeletionInfo delete_info,
498 DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00499 DoCookieCallback(base::BindOnce(
500 // base::Unretained is safe as DoCookieCallbackForURL stores
501 // the callback on |*this|, so the callback will not outlive
502 // the object.
Chris Mumford800caa62018-04-20 19:34:44503 &CookieMonster::DeleteAllMatchingInfo, base::Unretained(this),
504 std::move(delete_info), std::move(callback)));
mmenke74bcbd52016-01-21 17:17:56505}
506
[email protected]264807b2012-04-25 14:49:37507void CookieMonster::DeleteSessionCookiesAsync(
rdsmith7ac81712017-06-22 17:09:54508 CookieStore::DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00509 DoCookieCallback(base::BindOnce(
510 // base::Unretained is safe as DoCookieCallbackForURL stores
511 // the callback on |*this|, so the callback will not outlive
512 // the object.
513 &CookieMonster::DeleteSessionCookies, base::Unretained(this),
514 std::move(callback)));
[email protected]264807b2012-04-25 14:49:37515}
516
mmenke18dd8ba2016-02-01 18:42:10517void CookieMonster::SetCookieableSchemes(
518 const std::vector<std::string>& schemes) {
mmenkebe0910d2016-03-01 19:09:09519 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56520
521 // Calls to this method will have no effect if made after a WebView or
522 // CookieManager instance has been created.
mmenke18dd8ba2016-02-01 18:42:10523 if (initialized_)
mmenke74bcbd52016-01-21 17:17:56524 return;
mmenke74bcbd52016-01-21 17:17:56525
mmenke18dd8ba2016-02-01 18:42:10526 cookieable_schemes_ = schemes;
mmenke74bcbd52016-01-21 17:17:56527}
528
mmenke74bcbd52016-01-21 17:17:56529// This function must be called before the CookieMonster is used.
530void CookieMonster::SetPersistSessionCookies(bool persist_session_cookies) {
mmenkebe0910d2016-03-01 19:09:09531 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56532 DCHECK(!initialized_);
Helen Licd0fab862018-08-13 16:07:53533 net_log_.AddEvent(
534 NetLogEventType::COOKIE_STORE_SESSION_PERSISTENCE,
535 NetLog::BoolCallback("persistence", persist_session_cookies));
mmenke74bcbd52016-01-21 17:17:56536 persist_session_cookies_ = persist_session_cookies;
537}
538
539bool CookieMonster::IsCookieableScheme(const std::string& scheme) {
mmenkebe0910d2016-03-01 19:09:09540 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56541
tripta.gdda72022017-06-19 05:16:23542 return base::ContainsValue(cookieable_schemes_, scheme);
mmenke74bcbd52016-01-21 17:17:56543}
544
mmenke18dd8ba2016-02-01 18:42:10545const char* const CookieMonster::kDefaultCookieableSchemes[] = {"http", "https",
546 "ws", "wss"};
mmenke74bcbd52016-01-21 17:17:56547const int CookieMonster::kDefaultCookieableSchemesCount =
Ryan Sleevi435a3a22018-05-15 02:16:07548 base::size(kDefaultCookieableSchemes);
mmenke74bcbd52016-01-21 17:17:56549
Victor Costan14f47c12018-03-01 08:02:24550CookieChangeDispatcher& CookieMonster::GetChangeDispatcher() {
551 return change_dispatcher_;
Randy Smithd32dc8c2017-08-30 18:03:40552}
553
nharper5babb5e62016-03-09 18:58:07554bool CookieMonster::IsEphemeral() {
555 return store_.get() == nullptr;
556}
557
Maks Orlovich5cf437b02018-03-27 04:40:42558void CookieMonster::DumpMemoryStats(
559 base::trace_event::ProcessMemoryDump* pmd,
560 const std::string& parent_absolute_name) const {
561 const char kRelPath[] = "/cookie_monster";
562
563 pmd->CreateAllocatorDump(parent_absolute_name + kRelPath + "/cookies")
564 ->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
565 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
566 cookies_.size());
567
568 pmd->CreateAllocatorDump(parent_absolute_name + kRelPath +
569 "/tasks_pending_global")
570 ->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
571 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
572 tasks_pending_.size());
573
574 size_t total_pending_for_key = 0;
575 for (const auto& kv : tasks_pending_for_key_)
576 total_pending_for_key += kv.second.size();
577 pmd->CreateAllocatorDump(parent_absolute_name + kRelPath +
578 "/tasks_pending_for_key")
579 ->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
580 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
581 total_pending_for_key);
582}
583
mmenke74bcbd52016-01-21 17:17:56584CookieMonster::~CookieMonster() {
mmenkebe0910d2016-03-01 19:09:09585 DCHECK(thread_checker_.CalledOnValidThread());
mmenke05255cf2016-02-03 15:49:31586
Nick Harper14e23332017-07-28 00:27:23587 if (channel_id_service_ && store_) {
588 store_->SetBeforeFlushCallback(base::Closure());
589 }
590
Randy Smith0a522662017-08-30 19:35:34591 // TODO(mmenke): Does it really make sense to run
mmenke606c59c2016-03-07 18:20:55592 // CookieChanged callbacks when the CookieStore is destroyed?
jdoerrie22a91d8b92018-10-05 08:43:26593 for (auto cookie_it = cookies_.begin(); cookie_it != cookies_.end();) {
594 auto current_cookie_it = cookie_it;
mmenke05255cf2016-02-03 15:49:31595 ++cookie_it;
596 InternalDeleteCookie(current_cookie_it, false /* sync_to_store */,
597 DELETE_COOKIE_DONT_RECORD);
598 }
Helen Licd0fab862018-08-13 16:07:53599 net_log_.EndEvent(NetLogEventType::COOKIE_STORE_ALIVE);
[email protected]8562034e2011-10-17 17:35:04600}
601
rdsmithe5c701d2017-07-12 21:50:00602void CookieMonster::GetAllCookies(GetCookieListCallback callback) {
mmenkebe0910d2016-03-01 19:09:09603 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40604
605 // This function is being called to scrape the cookie list for management UI
606 // or similar. We shouldn't show expired cookies in this list since it will
607 // just be confusing to users, and this function is called rarely enough (and
608 // is already slow enough) that it's OK to take the time to garbage collect
609 // the expired cookies now.
610 //
611 // Note that this does not prune cookies to be below our limits (if we've
612 // exceeded them) the way that calling GarbageCollect() would.
mkwstbe84af312015-02-20 08:52:45613 GarbageCollectExpired(
614 Time::Now(), CookieMapItPair(cookies_.begin(), cookies_.end()), NULL);
[email protected]f48b9432011-01-11 07:25:40615
616 // Copy the CanonicalCookie pointers from the map so that we can use the same
617 // sorter as elsewhere, then copy the result out.
618 std::vector<CanonicalCookie*> cookie_ptrs;
619 cookie_ptrs.reserve(cookies_.size());
avie7cd11a2016-10-11 02:00:35620 for (const auto& cookie : cookies_)
621 cookie_ptrs.push_back(cookie.second.get());
[email protected]f48b9432011-01-11 07:25:40622 std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
623
624 CookieList cookie_list;
625 cookie_list.reserve(cookie_ptrs.size());
vmpstr6d9996c82017-02-23 00:43:25626 for (auto* cookie_ptr : cookie_ptrs)
avie7cd11a2016-10-11 02:00:35627 cookie_list.push_back(*cookie_ptr);
[email protected]f48b9432011-01-11 07:25:40628
Aaron Tagliaboschia4c64b52019-01-25 03:28:49629 MaybeRunCookieCallback(std::move(callback), cookie_list, CookieStatusList());
[email protected]f325f1e12010-04-30 22:38:55630}
631
rdsmithe5c701d2017-07-12 21:50:00632void CookieMonster::GetCookieListWithOptions(const GURL& url,
633 const CookieOptions& options,
634 GetCookieListCallback callback) {
mmenkebe0910d2016-03-01 19:09:09635 DCHECK(thread_checker_.CalledOnValidThread());
initial.commit586acc5fe2008-07-26 22:42:52636
mkwstc611e6d2016-02-23 15:45:55637 CookieList cookies;
Aaron Tagliaboschia4c64b52019-01-25 03:28:49638 CookieStatusList excluded_cookies;
rdsmithe5c701d2017-07-12 21:50:00639 if (HasCookieableScheme(url)) {
640 std::vector<CanonicalCookie*> cookie_ptrs;
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:52641 FindCookiesForRegistryControlledHost(url, &cookie_ptrs);
Aaron Tagliaboschi29033b7f2019-01-31 19:58:20642 std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
mkwstc611e6d2016-02-23 15:45:55643
rdsmithe5c701d2017-07-12 21:50:00644 cookies.reserve(cookie_ptrs.size());
Aaron Tagliaboschi29033b7f2019-01-31 19:58:20645 std::vector<CanonicalCookie*> included_cookie_ptrs;
646 FilterCookiesWithOptions(url, options, &cookie_ptrs, &included_cookie_ptrs,
647 &excluded_cookies);
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:52648
Aaron Tagliaboschi29033b7f2019-01-31 19:58:20649 for (auto* cookie : included_cookie_ptrs) {
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:52650 cookies.push_back(*cookie);
651 }
rdsmithe5c701d2017-07-12 21:50:00652 }
Aaron Tagliaboschi29033b7f2019-01-31 19:58:20653
Aaron Tagliaboschia4c64b52019-01-25 03:28:49654 MaybeRunCookieCallback(std::move(callback), cookies, excluded_cookies);
initial.commit586acc5fe2008-07-26 22:42:52655}
656
Chris Mumford800caa62018-04-20 19:34:44657void CookieMonster::DeleteAllCreatedInTimeRange(const TimeRange& creation_range,
658 DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09659 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]d0980332010-11-16 17:08:53660
rdsmitha5beda162017-07-08 13:55:42661 uint32_t num_deleted = 0;
jdoerrie22a91d8b92018-10-05 08:43:26662 for (auto it = cookies_.begin(); it != cookies_.end();) {
663 auto curit = it;
avie7cd11a2016-10-11 02:00:35664 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:40665 ++it;
[email protected]d0980332010-11-16 17:08:53666
Chris Mumford800caa62018-04-20 19:34:44667 if (creation_range.Contains(cc->CreationDate())) {
mkwstbe84af312015-02-20 08:52:45668 InternalDeleteCookie(curit, true, /*sync_to_store*/
Nick Harper7a6683a2018-01-30 20:42:52669 DELETE_COOKIE_EXPLICIT);
[email protected]f48b9432011-01-11 07:25:40670 ++num_deleted;
initial.commit586acc5fe2008-07-26 22:42:52671 }
672 }
673
rdsmithe5c701d2017-07-12 21:50:00674 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39675 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00676 callback ? base::BindOnce(std::move(callback), num_deleted)
677 : base::OnceClosure()));
[email protected]f48b9432011-01-11 07:25:40678}
679
Chris Mumford800caa62018-04-20 19:34:44680void CookieMonster::DeleteAllMatchingInfo(CookieDeletionInfo delete_info,
681 DeleteCallback callback) {
rdsmitha5beda162017-07-08 13:55:42682 uint32_t num_deleted = 0;
jdoerrie22a91d8b92018-10-05 08:43:26683 for (auto it = cookies_.begin(); it != cookies_.end();) {
684 auto curit = it;
avie7cd11a2016-10-11 02:00:35685 CanonicalCookie* cc = curit->second.get();
dmurphfaea244c2016-04-09 00:42:30686 ++it;
[email protected]f48b9432011-01-11 07:25:40687
Chris Mumford800caa62018-04-20 19:34:44688 if (delete_info.Matches(*cc)) {
dmurphfaea244c2016-04-09 00:42:30689 InternalDeleteCookie(curit, true, /*sync_to_store*/
Nick Harper7a6683a2018-01-30 20:42:52690 DELETE_COOKIE_EXPLICIT);
dmurphfaea244c2016-04-09 00:42:30691 ++num_deleted;
[email protected]f48b9432011-01-11 07:25:40692 }
693 }
dmurphfaea244c2016-04-09 00:42:30694
rdsmithe5c701d2017-07-12 21:50:00695 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39696 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00697 callback ? base::BindOnce(std::move(callback), num_deleted)
698 : base::OnceClosure()));
[email protected]f48b9432011-01-11 07:25:40699}
700
rdsmithe5c701d2017-07-12 21:50:00701void CookieMonster::SetCookieWithOptions(const GURL& url,
[email protected]f48b9432011-01-11 07:25:40702 const std::string& cookie_line,
rdsmithe5c701d2017-07-12 21:50:00703 const CookieOptions& options,
704 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:09705 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40706
707 if (!HasCookieableScheme(url)) {
rdsmithe5c701d2017-07-12 21:50:00708 MaybeRunCookieCallback(std::move(callback), false);
709 return;
[email protected]f48b9432011-01-11 07:25:40710 }
711
Oscar Johansson63e83cf2018-07-02 08:47:26712 VLOG(net::cookie_util::kVlogSetCookies)
713 << "SetCookie() line: " << cookie_line;
Maks Orlovicha61ed022018-03-01 18:24:24714
Maks Orlovicha61ed022018-03-01 18:24:24715 std::unique_ptr<CanonicalCookie> cc(
Maks Orlovichc86cf292019-02-11 19:25:17716 CanonicalCookie::Create(url, cookie_line, Time::Now(), options));
Maks Orlovicha61ed022018-03-01 18:24:24717
718 if (!cc.get()) {
Oscar Johansson63e83cf2018-07-02 08:47:26719 VLOG(net::cookie_util::kVlogSetCookies)
720 << "WARNING: Failed to allocate CanonicalCookie";
Maks Orlovicha61ed022018-03-01 18:24:24721 MaybeRunCookieCallback(std::move(callback), false);
722 return;
723 }
724 SetCanonicalCookie(std::move(cc), url.SchemeIsCryptographic(),
725 !options.exclude_httponly(), std::move(callback));
[email protected]f48b9432011-01-11 07:25:40726}
727
rdsmithe5c701d2017-07-12 21:50:00728void CookieMonster::DeleteCanonicalCookie(const CanonicalCookie& cookie,
729 DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09730 DCHECK(thread_checker_.CalledOnValidThread());
mmenke24379d52016-02-05 23:50:17731
rdsmithe5c701d2017-07-12 21:50:00732 uint32_t result = 0u;
mmenke24379d52016-02-05 23:50:17733 for (CookieMapItPair its = cookies_.equal_range(GetKey(cookie.Domain()));
734 its.first != its.second; ++its.first) {
Maks Orlovich2896ec3f2018-04-06 13:34:27735 const std::unique_ptr<CanonicalCookie>& candidate = its.first->second;
736 // Historically, this has refused modification if the cookie has changed
737 // value in between the CanonicalCookie object was returned by a getter
738 // and when this ran. The later parts of the conditional (everything but
739 // the equivalence check) attempt to preserve this behavior.
740 if (candidate->IsEquivalent(cookie) &&
Maks Orlovich2896ec3f2018-04-06 13:34:27741 candidate->Value() == cookie.Value()) {
Nick Harper7a6683a2018-01-30 20:42:52742 InternalDeleteCookie(its.first, true, DELETE_COOKIE_EXPLICIT);
rdsmithe5c701d2017-07-12 21:50:00743 result = 1u;
744 break;
mmenke24379d52016-02-05 23:50:17745 }
746 }
rdsmithe5c701d2017-07-12 21:50:00747 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39748 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00749 callback ? base::BindOnce(std::move(callback), result)
750 : base::OnceClosure()));
mmenke24379d52016-02-05 23:50:17751}
752
rdsmithe5c701d2017-07-12 21:50:00753void CookieMonster::DeleteSessionCookies(DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09754 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]264807b2012-04-25 14:49:37755
rdsmitha5beda162017-07-08 13:55:42756 uint32_t num_deleted = 0;
jdoerrie22a91d8b92018-10-05 08:43:26757 for (auto it = cookies_.begin(); it != cookies_.end();) {
758 auto curit = it;
avie7cd11a2016-10-11 02:00:35759 CanonicalCookie* cc = curit->second.get();
[email protected]264807b2012-04-25 14:49:37760 ++it;
761
762 if (!cc->IsPersistent()) {
mkwstbe84af312015-02-20 08:52:45763 InternalDeleteCookie(curit, true, /*sync_to_store*/
[email protected]264807b2012-04-25 14:49:37764 DELETE_COOKIE_EXPIRED);
765 ++num_deleted;
766 }
767 }
768
rdsmithe5c701d2017-07-12 21:50:00769 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39770 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00771 callback ? base::BindOnce(std::move(callback), num_deleted)
772 : base::OnceClosure()));
[email protected]264807b2012-04-25 14:49:37773}
774
erikchen1dd72a72015-05-06 20:45:05775void CookieMonster::MarkCookieStoreAsInitialized() {
mmenkebe0910d2016-03-01 19:09:09776 DCHECK(thread_checker_.CalledOnValidThread());
erikchen1dd72a72015-05-06 20:45:05777 initialized_ = true;
778}
779
780void CookieMonster::FetchAllCookiesIfNecessary() {
mmenkebe0910d2016-03-01 19:09:09781 DCHECK(thread_checker_.CalledOnValidThread());
erikchen1dd72a72015-05-06 20:45:05782 if (store_.get() && !started_fetching_all_cookies_) {
783 started_fetching_all_cookies_ = true;
784 FetchAllCookies();
785 }
786}
787
mmenke74bcbd52016-01-21 17:17:56788void CookieMonster::FetchAllCookies() {
mmenkebe0910d2016-03-01 19:09:09789 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56790 DCHECK(store_.get()) << "Store must exist to initialize";
791 DCHECK(!finished_fetching_all_cookies_)
792 << "All cookies have already been fetched.";
793
794 // We bind in the current time so that we can report the wall-clock time for
795 // loading cookies.
mmenkebe0910d2016-03-01 19:09:09796 store_->Load(base::Bind(&CookieMonster::OnLoaded,
Helen Li92a29f102018-08-15 23:02:26797 weak_ptr_factory_.GetWeakPtr(), TimeTicks::Now()),
798 net_log_);
mmenke74bcbd52016-01-21 17:17:56799}
800
avie7cd11a2016-10-11 02:00:35801void CookieMonster::OnLoaded(
802 TimeTicks beginning_time,
803 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:09804 DCHECK(thread_checker_.CalledOnValidThread());
avie7cd11a2016-10-11 02:00:35805 StoreLoadedCookies(std::move(cookies));
[email protected]c7593fb22011-11-14 23:54:27806 histogram_time_blocked_on_load_->AddTime(TimeTicks::Now() - beginning_time);
[email protected]218aa6a12011-09-13 17:38:38807
808 // Invoke the task queue of cookie request.
809 InvokeQueue();
810}
811
avie7cd11a2016-10-11 02:00:35812void CookieMonster::OnKeyLoaded(
813 const std::string& key,
814 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:09815 DCHECK(thread_checker_.CalledOnValidThread());
816
avie7cd11a2016-10-11 02:00:35817 StoreLoadedCookies(std::move(cookies));
[email protected]8562034e2011-10-17 17:35:04818
mmenkebe0910d2016-03-01 19:09:09819 auto tasks_pending_for_key = tasks_pending_for_key_.find(key);
[email protected]8562034e2011-10-17 17:35:04820
mmenkebe0910d2016-03-01 19:09:09821 // TODO(mmenke): Can this be turned into a DCHECK?
822 if (tasks_pending_for_key == tasks_pending_for_key_.end())
823 return;
[email protected]bab72ec2013-10-30 20:50:02824
mmenkebe0910d2016-03-01 19:09:09825 // Run all tasks for the key. Note that running a task can result in multiple
826 // tasks being added to the back of the deque.
827 while (!tasks_pending_for_key->second.empty()) {
rdsmithe5c701d2017-07-12 21:50:00828 base::OnceClosure task = std::move(tasks_pending_for_key->second.front());
mmenkebe0910d2016-03-01 19:09:09829 tasks_pending_for_key->second.pop_front();
rdsmithe5c701d2017-07-12 21:50:00830 std::move(task).Run();
[email protected]8562034e2011-10-17 17:35:04831 }
mmenkebe0910d2016-03-01 19:09:09832
833 tasks_pending_for_key_.erase(tasks_pending_for_key);
834
835 // This has to be done last, in case running a task queues a new task for the
836 // key, to ensure tasks are run in the correct order.
837 keys_loaded_.insert(key);
[email protected]8562034e2011-10-17 17:35:04838}
839
[email protected]218aa6a12011-09-13 17:38:38840void CookieMonster::StoreLoadedCookies(
avie7cd11a2016-10-11 02:00:35841 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:09842 DCHECK(thread_checker_.CalledOnValidThread());
843
mmenkebe0910d2016-03-01 19:09:09844 // Even if a key is expired, insert it so it can be garbage collected,
845 // removed, and sync'd.
[email protected]6210ce52013-09-20 03:33:14846 CookieItVector cookies_with_control_chars;
847
avie7cd11a2016-10-11 02:00:35848 for (auto& cookie : cookies) {
Maks Orlovich2b0d5b12018-04-10 19:33:47849 CanonicalCookie* cookie_ptr = cookie.get();
jdoerrie22a91d8b92018-10-05 08:43:26850 auto inserted = InternalInsertCookie(GetKey(cookie_ptr->Domain()),
851 std::move(cookie), false);
Maks Orlovich2b0d5b12018-04-10 19:33:47852 const Time cookie_access_time(cookie_ptr->LastAccessDate());
853 if (earliest_access_time_.is_null() ||
Helen Lid84010b2018-08-22 16:27:44854 cookie_access_time < earliest_access_time_) {
Maks Orlovich2b0d5b12018-04-10 19:33:47855 earliest_access_time_ = cookie_access_time;
Helen Lid84010b2018-08-22 16:27:44856 }
[email protected]f48b9432011-01-11 07:25:40857
Maks Orlovich2b0d5b12018-04-10 19:33:47858 if (ContainsControlCharacter(cookie_ptr->Name()) ||
859 ContainsControlCharacter(cookie_ptr->Value())) {
860 cookies_with_control_chars.push_back(inserted);
[email protected]f48b9432011-01-11 07:25:40861 }
862 }
[email protected]f48b9432011-01-11 07:25:40863
[email protected]6210ce52013-09-20 03:33:14864 // Any cookies that contain control characters that we have loaded from the
865 // persistent store should be deleted. See http://crbug.com/238041.
jdoerrie22a91d8b92018-10-05 08:43:26866 for (auto it = cookies_with_control_chars.begin();
[email protected]6210ce52013-09-20 03:33:14867 it != cookies_with_control_chars.end();) {
jdoerrie22a91d8b92018-10-05 08:43:26868 auto curit = it;
[email protected]6210ce52013-09-20 03:33:14869 ++it;
870
871 InternalDeleteCookie(*curit, true, DELETE_COOKIE_CONTROL_CHAR);
872 }
873
[email protected]f48b9432011-01-11 07:25:40874 // After importing cookies from the PersistentCookieStore, verify that
875 // none of our other constraints are violated.
[email protected]f48b9432011-01-11 07:25:40876 // In particular, the backing store might have given us duplicate cookies.
[email protected]8562034e2011-10-17 17:35:04877
878 // This method could be called multiple times due to priority loading, thus
879 // cookies loaded in previous runs will be validated again, but this is OK
880 // since they are expected to be much fewer than total DB.
[email protected]f48b9432011-01-11 07:25:40881 EnsureCookiesMapIsValid();
[email protected]218aa6a12011-09-13 17:38:38882}
[email protected]f48b9432011-01-11 07:25:40883
[email protected]218aa6a12011-09-13 17:38:38884void CookieMonster::InvokeQueue() {
mmenkebe0910d2016-03-01 19:09:09885 DCHECK(thread_checker_.CalledOnValidThread());
886
mmenkef49fca0e2016-03-08 12:46:24887 // Move all per-key tasks into the global queue, if there are any. This is
888 // protection about a race where the store learns about all cookies loading
889 // before it learned about the cookies for a key loading.
890
891 // Needed to prevent any recursively queued tasks from going back into the
892 // per-key queues.
893 seen_global_task_ = true;
rdsmithe5c701d2017-07-12 21:50:00894 for (auto& tasks_for_key : tasks_pending_for_key_) {
895 tasks_pending_.insert(tasks_pending_.begin(),
896 std::make_move_iterator(tasks_for_key.second.begin()),
897 std::make_move_iterator(tasks_for_key.second.end()));
mmenkef49fca0e2016-03-08 12:46:24898 }
899 tasks_pending_for_key_.clear();
900
mmenkebe0910d2016-03-01 19:09:09901 while (!tasks_pending_.empty()) {
rdsmithe5c701d2017-07-12 21:50:00902 base::OnceClosure request_task = std::move(tasks_pending_.front());
mmenkef49fca0e2016-03-08 12:46:24903 tasks_pending_.pop_front();
rdsmithe5c701d2017-07-12 21:50:00904 std::move(request_task).Run();
[email protected]218aa6a12011-09-13 17:38:38905 }
mmenkebe0910d2016-03-01 19:09:09906
mmenkef49fca0e2016-03-08 12:46:24907 DCHECK(tasks_pending_for_key_.empty());
908
mmenkebe0910d2016-03-01 19:09:09909 finished_fetching_all_cookies_ = true;
mmenkebe0910d2016-03-01 19:09:09910 keys_loaded_.clear();
[email protected]f48b9432011-01-11 07:25:40911}
912
913void CookieMonster::EnsureCookiesMapIsValid() {
mmenkebe0910d2016-03-01 19:09:09914 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40915
[email protected]f48b9432011-01-11 07:25:40916 // Iterate through all the of the cookies, grouped by host.
jdoerrie22a91d8b92018-10-05 08:43:26917 auto prev_range_end = cookies_.begin();
[email protected]f48b9432011-01-11 07:25:40918 while (prev_range_end != cookies_.end()) {
jdoerrie22a91d8b92018-10-05 08:43:26919 auto cur_range_begin = prev_range_end;
[email protected]f48b9432011-01-11 07:25:40920 const std::string key = cur_range_begin->first; // Keep a copy.
jdoerrie22a91d8b92018-10-05 08:43:26921 auto cur_range_end = cookies_.upper_bound(key);
[email protected]f48b9432011-01-11 07:25:40922 prev_range_end = cur_range_end;
923
924 // Ensure no equivalent cookies for this host.
ellyjonescabf57422015-08-21 18:44:51925 TrimDuplicateCookiesForKey(key, cur_range_begin, cur_range_end);
[email protected]f48b9432011-01-11 07:25:40926 }
[email protected]f48b9432011-01-11 07:25:40927}
928
ellyjonescabf57422015-08-21 18:44:51929void CookieMonster::TrimDuplicateCookiesForKey(const std::string& key,
930 CookieMap::iterator begin,
931 CookieMap::iterator end) {
mmenkebe0910d2016-03-01 19:09:09932 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40933
934 // Set of cookies ordered by creation time.
Maks Orlovich2b0d5b12018-04-10 19:33:47935 typedef std::multiset<CookieMap::iterator, OrderByCreationTimeDesc> CookieSet;
[email protected]f48b9432011-01-11 07:25:40936
937 // Helper map we populate to find the duplicates.
938 typedef std::map<CookieSignature, CookieSet> EquivalenceMap;
939 EquivalenceMap equivalent_cookies;
940
941 // The number of duplicate cookies that have been found.
942 int num_duplicates = 0;
943
944 // Iterate through all of the cookies in our range, and insert them into
945 // the equivalence map.
jdoerrie22a91d8b92018-10-05 08:43:26946 for (auto it = begin; it != end; ++it) {
[email protected]f48b9432011-01-11 07:25:40947 DCHECK_EQ(key, it->first);
avie7cd11a2016-10-11 02:00:35948 CanonicalCookie* cookie = it->second.get();
[email protected]f48b9432011-01-11 07:25:40949
mkwstbe84af312015-02-20 08:52:45950 CookieSignature signature(cookie->Name(), cookie->Domain(), cookie->Path());
[email protected]f48b9432011-01-11 07:25:40951 CookieSet& set = equivalent_cookies[signature];
952
953 // We found a duplicate!
954 if (!set.empty())
955 num_duplicates++;
956
957 // We save the iterator into |cookies_| rather than the actual cookie
958 // pointer, since we may need to delete it later.
Maks Orlovich2b0d5b12018-04-10 19:33:47959 set.insert(it);
[email protected]f48b9432011-01-11 07:25:40960 }
961
962 // If there were no duplicates, we are done!
963 if (num_duplicates == 0)
ellyjonescabf57422015-08-21 18:44:51964 return;
[email protected]f48b9432011-01-11 07:25:40965
966 // Make sure we find everything below that we did above.
967 int num_duplicates_found = 0;
968
969 // Otherwise, delete all the duplicate cookies, both from our in-memory store
970 // and from the backing store.
jdoerrie22a91d8b92018-10-05 08:43:26971 for (auto it = equivalent_cookies.begin(); it != equivalent_cookies.end();
972 ++it) {
[email protected]f48b9432011-01-11 07:25:40973 const CookieSignature& signature = it->first;
974 CookieSet& dupes = it->second;
975
976 if (dupes.size() <= 1)
977 continue; // This cookiename/path has no duplicates.
978 num_duplicates_found += dupes.size() - 1;
979
Maks Orlovich2b0d5b12018-04-10 19:33:47980 // Since |dupes| is sorted by creation time (descending), the first cookie
981 // is the most recent one (or tied for it), so we will keep it. The rest are
982 // duplicates.
[email protected]f48b9432011-01-11 07:25:40983 dupes.erase(dupes.begin());
984
985 LOG(ERROR) << base::StringPrintf(
986 "Found %d duplicate cookies for host='%s', "
987 "with {name='%s', domain='%s', path='%s'}",
mkwstbe84af312015-02-20 08:52:45988 static_cast<int>(dupes.size()), key.c_str(), signature.name.c_str(),
989 signature.domain.c_str(), signature.path.c_str());
[email protected]f48b9432011-01-11 07:25:40990
991 // Remove all the cookies identified by |dupes|. It is valid to delete our
992 // list of iterators one at a time, since |cookies_| is a multimap (they
993 // don't invalidate existing iterators following deletion).
jdoerrie22a91d8b92018-10-05 08:43:26994 for (auto dupes_it = dupes.begin(); dupes_it != dupes.end(); ++dupes_it) {
[email protected]218aa6a12011-09-13 17:38:38995 InternalDeleteCookie(*dupes_it, true,
[email protected]f48b9432011-01-11 07:25:40996 DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE);
997 }
998 }
999 DCHECK_EQ(num_duplicates, num_duplicates_found);
[email protected]f48b9432011-01-11 07:25:401000}
1001
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521002void CookieMonster::FindCookiesForRegistryControlledHost(
[email protected]f48b9432011-01-11 07:25:401003 const GURL& url,
[email protected]f48b9432011-01-11 07:25:401004 std::vector<CanonicalCookie*>* cookies) {
mmenkebe0910d2016-03-01 19:09:091005 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401006
Maks Orlovichc86cf292019-02-11 19:25:171007 Time current_time = Time::Now();
[email protected]f48b9432011-01-11 07:25:401008
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521009 // Retrieve all cookies for a given key
Maks Orlovich323efaf2018-03-06 02:56:391010 const std::string key(GetKey(url.host_piece()));
Aaron Tagliaboschi9e1de1b2019-01-15 14:40:061011
[email protected]f48b9432011-01-11 07:25:401012 for (CookieMapItPair its = cookies_.equal_range(key);
mkwstbe84af312015-02-20 08:52:451013 its.first != its.second;) {
jdoerrie22a91d8b92018-10-05 08:43:261014 auto curit = its.first;
avie7cd11a2016-10-11 02:00:351015 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:401016 ++its.first;
1017
1018 // If the cookie is expired, delete it.
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521019 if (cc->IsExpired(current_time)) {
[email protected]f48b9432011-01-11 07:25:401020 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
1021 continue;
1022 }
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521023 cookies->push_back(cc);
Aaron Tagliaboschi9e1de1b2019-01-15 14:40:061024 }
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521025}
[email protected]f48b9432011-01-11 07:25:401026
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521027void CookieMonster::FilterCookiesWithOptions(
1028 const GURL url,
1029 const CookieOptions options,
1030 std::vector<CanonicalCookie*>* cookie_ptrs,
Aaron Tagliaboschi29033b7f2019-01-31 19:58:201031 std::vector<CanonicalCookie*>* included_cookie_ptrs,
1032 CookieStatusList* excluded_cookies) {
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521033 DCHECK(thread_checker_.CalledOnValidThread());
1034
1035 // Probe to save statistics relatively frequently. We do it here rather
1036 // than in the set path as many websites won't set cookies, and we
1037 // want to collect statistics whenever the browser's being used.
Maks Orlovichc86cf292019-02-11 19:25:171038 Time current_time = Time::Now();
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521039 RecordPeriodicStats(current_time);
1040
1041 for (std::vector<CanonicalCookie*>::iterator it = cookie_ptrs->begin();
1042 it != cookie_ptrs->end(); it++) {
[email protected]65f4e7e2012-12-12 21:56:541043 // Filter out cookies that should not be included for a request to the
1044 // given |url|. HTTP only cookies are filtered depending on the passed
1045 // cookie |options|.
Aaron Tagliaboschi29033b7f2019-01-31 19:58:201046 CanonicalCookie::CookieInclusionStatus status =
1047 (*it)->IncludeForRequestURL(url, options);
1048
1049 if (status != CanonicalCookie::CookieInclusionStatus::INCLUDE) {
1050 if (options.return_excluded_cookies())
1051 excluded_cookies->push_back({**it, status});
[email protected]f48b9432011-01-11 07:25:401052 continue;
[email protected]f48b9432011-01-11 07:25:401053 }
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521054
1055 if (options.update_access_time())
1056 InternalUpdateCookieAccessTime(*it, current_time);
1057
Aaron Tagliaboschi29033b7f2019-01-31 19:58:201058 included_cookie_ptrs->push_back(*it);
[email protected]f48b9432011-01-11 07:25:401059 }
1060}
1061
Mike Westc4a777b2017-10-06 14:04:201062bool CookieMonster::DeleteAnyEquivalentCookie(
1063 const std::string& key,
1064 const CanonicalCookie& ecc,
1065 bool source_secure,
1066 bool skip_httponly,
1067 bool already_expired,
1068 base::Time* creation_date_to_inherit) {
mmenkebe0910d2016-03-01 19:09:091069 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401070
1071 bool found_equivalent_cookie = false;
1072 bool skipped_httponly = false;
jww601411a2015-11-20 19:46:571073 bool skipped_secure_cookie = false;
jww31e32632015-12-16 23:38:341074
1075 histogram_cookie_delete_equivalent_->Add(COOKIE_DELETE_EQUIVALENT_ATTEMPT);
1076
Lily Chen22707642b2018-10-02 17:27:211077 CookieMap::iterator cookie_it_to_possibly_delete = cookies_.end();
1078 CanonicalCookie* cc_skipped_secure = nullptr;
[email protected]f48b9432011-01-11 07:25:401079 for (CookieMapItPair its = cookies_.equal_range(key);
mkwstbe84af312015-02-20 08:52:451080 its.first != its.second;) {
jdoerrie22a91d8b92018-10-05 08:43:261081 auto curit = its.first;
avie7cd11a2016-10-11 02:00:351082 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:401083 ++its.first;
1084
jwwa26e439d2017-01-27 18:17:271085 // If the cookie is being set from an insecure scheme, then if a cookie
1086 // already exists with the same name and it is Secure, then the cookie
1087 // should *not* be updated if they domain-match and ignoring the path
1088 // attribute.
jww601411a2015-11-20 19:46:571089 //
jwwa26e439d2017-01-27 18:17:271090 // See: https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone
rdsmith2709eee2017-06-20 22:43:271091 if (cc->IsSecure() && !source_secure &&
mmenke2830b0722016-07-20 16:02:501092 ecc.IsEquivalentForSecureCookieMatching(*cc)) {
jww601411a2015-11-20 19:46:571093 skipped_secure_cookie = true;
Lily Chen22707642b2018-10-02 17:27:211094 cc_skipped_secure = cc;
jww31e32632015-12-16 23:38:341095 histogram_cookie_delete_equivalent_->Add(
1096 COOKIE_DELETE_EQUIVALENT_SKIPPING_SECURE);
Helen Licd0fab862018-08-13 16:07:531097 net_log_.AddEvent(
1098 NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_SECURE,
1099 base::BindRepeating(&NetLogCookieMonsterCookieRejectedSecure, cc,
1100 &ecc));
jww31e32632015-12-16 23:38:341101 // If the cookie is equivalent to the new cookie and wouldn't have been
1102 // skipped for being HTTP-only, record that it is a skipped secure cookie
1103 // that would have been deleted otherwise.
1104 if (ecc.IsEquivalent(*cc)) {
jwwa9a0d482015-12-16 18:19:411105 found_equivalent_cookie = true;
jww31e32632015-12-16 23:38:341106
1107 if (!skip_httponly || !cc->IsHttpOnly()) {
1108 histogram_cookie_delete_equivalent_->Add(
1109 COOKIE_DELETE_EQUIVALENT_WOULD_HAVE_DELETED);
1110 }
1111 }
jww601411a2015-11-20 19:46:571112 } else if (ecc.IsEquivalent(*cc)) {
[email protected]f48b9432011-01-11 07:25:401113 // We should never have more than one equivalent cookie, since they should
jww601411a2015-11-20 19:46:571114 // overwrite each other, unless secure cookies require secure scheme is
1115 // being enforced. In that case, cookies with different paths might exist
1116 // and be considered equivalent.
mkwstbe84af312015-02-20 08:52:451117 CHECK(!found_equivalent_cookie)
1118 << "Duplicate equivalent cookies found, cookie store is corrupted.";
Lily Chen22707642b2018-10-02 17:27:211119 DCHECK(cookie_it_to_possibly_delete == cookies_.end());
[email protected]f48b9432011-01-11 07:25:401120 if (skip_httponly && cc->IsHttpOnly()) {
1121 skipped_httponly = true;
Helen Licd0fab862018-08-13 16:07:531122 net_log_.AddEvent(
1123 NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_HTTPONLY,
1124 base::BindRepeating(&NetLogCookieMonsterCookieRejectedHttponly, cc,
1125 &ecc));
[email protected]f48b9432011-01-11 07:25:401126 } else {
Lily Chen22707642b2018-10-02 17:27:211127 cookie_it_to_possibly_delete = curit;
[email protected]f48b9432011-01-11 07:25:401128 }
1129 found_equivalent_cookie = true;
1130 }
1131 }
Lily Chen22707642b2018-10-02 17:27:211132
1133 if (cookie_it_to_possibly_delete != cookies_.end()) {
1134 CanonicalCookie* cc_to_possibly_delete =
1135 cookie_it_to_possibly_delete->second.get();
1136 // If a secure cookie was encountered (and left alone), don't actually
1137 // modify any of the pre-existing cookies. Only delete if no secure cookies
1138 // were skipped.
1139 if (!skipped_secure_cookie) {
1140 histogram_cookie_delete_equivalent_->Add(COOKIE_DELETE_EQUIVALENT_FOUND);
1141 if (cc_to_possibly_delete->Value() == ecc.Value()) {
1142 *creation_date_to_inherit = cc_to_possibly_delete->CreationDate();
1143 histogram_cookie_delete_equivalent_->Add(
1144 COOKIE_DELETE_EQUIVALENT_FOUND_WITH_SAME_VALUE);
1145 }
1146 InternalDeleteCookie(cookie_it_to_possibly_delete, true,
1147 already_expired ? DELETE_COOKIE_EXPIRED_OVERWRITE
1148 : DELETE_COOKIE_OVERWRITE);
1149 } else {
1150 // If any secure cookie was skipped, preserve the pre-existing cookie.
1151 DCHECK(cc_skipped_secure);
1152 net_log_.AddEvent(
1153 NetLogEventType::COOKIE_STORE_COOKIE_PRESERVED_SKIPPED_SECURE,
1154 base::BindRepeating(&NetLogCookieMonsterCookiePreservedSkippedSecure,
1155 cc_skipped_secure, cc_to_possibly_delete, &ecc));
1156 }
1157 }
1158
jww601411a2015-11-20 19:46:571159 return skipped_httponly || skipped_secure_cookie;
[email protected]f48b9432011-01-11 07:25:401160}
1161
[email protected]6210ce52013-09-20 03:33:141162CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie(
1163 const std::string& key,
avie7cd11a2016-10-11 02:00:351164 std::unique_ptr<CanonicalCookie> cc,
[email protected]6210ce52013-09-20 03:33:141165 bool sync_to_store) {
mmenkebe0910d2016-03-01 19:09:091166 DCHECK(thread_checker_.CalledOnValidThread());
avie7cd11a2016-10-11 02:00:351167 CanonicalCookie* cc_ptr = cc.get();
mmenkebe0910d2016-03-01 19:09:091168
Helen Licd0fab862018-08-13 16:07:531169 net_log_.AddEvent(NetLogEventType::COOKIE_STORE_COOKIE_ADDED,
1170 base::BindRepeating(&NetLogCookieMonsterCookieAdded,
1171 cc.get(), sync_to_store));
avie7cd11a2016-10-11 02:00:351172 if ((cc_ptr->IsPersistent() || persist_session_cookies_) && store_.get() &&
Helen Lid84010b2018-08-22 16:27:441173 sync_to_store) {
avie7cd11a2016-10-11 02:00:351174 store_->AddCookie(*cc_ptr);
Helen Lid84010b2018-08-22 16:27:441175 }
jdoerrie22a91d8b92018-10-05 08:43:261176 auto inserted = cookies_.insert(CookieMap::value_type(key, std::move(cc)));
mkwstc1aa4cc2015-04-03 19:57:451177
1178 // See InitializeHistograms() for details.
avie7cd11a2016-10-11 02:00:351179 int32_t type_sample = cc_ptr->SameSite() != CookieSameSite::NO_RESTRICTION
mkwste1a29582016-03-15 10:07:521180 ? 1 << COOKIE_TYPE_SAME_SITE
1181 : 0;
avie7cd11a2016-10-11 02:00:351182 type_sample |= cc_ptr->IsHttpOnly() ? 1 << COOKIE_TYPE_HTTPONLY : 0;
1183 type_sample |= cc_ptr->IsSecure() ? 1 << COOKIE_TYPE_SECURE : 0;
mkwst46549412016-02-01 10:05:371184 histogram_cookie_type_->Add(type_sample);
estark7feb65c2b2015-08-21 23:38:201185
Victor Costan14f47c12018-03-01 08:02:241186 change_dispatcher_.DispatchChange(*cc_ptr, CookieChangeCause::INSERTED, true);
[email protected]6210ce52013-09-20 03:33:141187
1188 return inserted;
[email protected]f48b9432011-01-11 07:25:401189}
1190
rdsmithe5c701d2017-07-12 21:50:001191void CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc,
rdsmith2709eee2017-06-20 22:43:271192 bool secure_source,
rdsmithe5c701d2017-07-12 21:50:001193 bool modify_http_only,
1194 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:091195 DCHECK(thread_checker_.CalledOnValidThread());
1196
Randy Smith10400072017-08-03 04:08:311197 if ((cc->IsSecure() && !secure_source) ||
1198 (cc->IsHttpOnly() && !modify_http_only)) {
rdsmithe5c701d2017-07-12 21:50:001199 MaybeRunCookieCallback(std::move(callback), false);
1200 return;
1201 }
rdsmith2709eee2017-06-20 22:43:271202
mmenkeea4cd402016-02-02 04:03:101203 const std::string key(GetKey(cc->Domain()));
rdsmitha6ce4442017-06-21 17:11:051204
rdsmitha6ce4442017-06-21 17:11:051205 base::Time creation_date = cc->CreationDate();
1206 if (creation_date.is_null()) {
Maks Orlovichc86cf292019-02-11 19:25:171207 creation_date = Time::Now();
rdsmitha6ce4442017-06-21 17:11:051208 cc->SetCreationDate(creation_date);
rdsmitha6ce4442017-06-21 17:11:051209 }
1210 bool already_expired = cc->IsExpired(creation_date);
ellyjones399e35a22014-10-27 11:09:561211
Mike Westc4a777b2017-10-06 14:04:201212 base::Time creation_date_to_inherit;
rdsmith2709eee2017-06-20 22:43:271213 if (DeleteAnyEquivalentCookie(key, *cc, secure_source, !modify_http_only,
Mike Westc4a777b2017-10-06 14:04:201214 already_expired, &creation_date_to_inherit)) {
jww601411a2015-11-20 19:46:571215 std::string error;
jwwa26e439d2017-01-27 18:17:271216 error =
1217 "SetCookie() not clobbering httponly cookie or secure cookie for "
1218 "insecure scheme";
jww601411a2015-11-20 19:46:571219
Oscar Johansson63e83cf2018-07-02 08:47:261220 VLOG(net::cookie_util::kVlogSetCookies) << error;
rdsmithe5c701d2017-07-12 21:50:001221 MaybeRunCookieCallback(std::move(callback), false);
1222 return;
[email protected]3a96c742008-11-19 19:46:271223 }
initial.commit586acc5fe2008-07-26 22:42:521224
Oscar Johansson63e83cf2018-07-02 08:47:261225 VLOG(net::cookie_util::kVlogSetCookies)
1226 << "SetCookie() key: " << key << " cc: " << cc->DebugString();
initial.commit586acc5fe2008-07-26 22:42:521227
1228 // Realize that we might be setting an expired cookie, and the only point
1229 // was to delete the cookie which we've already done.
mmenke3c79a652016-02-12 14:39:201230 if (!already_expired) {
[email protected]374f58b2010-07-20 15:29:261231 // See InitializeHistograms() for details.
mmenkeea4cd402016-02-02 04:03:101232 if (cc->IsPersistent()) {
[email protected]8475bee2011-03-17 18:40:241233 histogram_expiration_duration_minutes_->Add(
rdsmitha6ce4442017-06-21 17:11:051234 (cc->ExpiryDate() - creation_date).InMinutes());
[email protected]8475bee2011-03-17 18:40:241235 }
1236
rdsmith2709eee2017-06-20 22:43:271237 // Histogram the type of scheme used on URLs that set cookies. This
1238 // intentionally includes cookies that are set or overwritten by
1239 // http:// URLs, but not cookies that are cleared by http:// URLs, to
1240 // understand if the former behavior can be deprecated for Secure
1241 // cookies.
1242 CookieSource cookie_source_sample =
1243 (secure_source
1244 ? (cc->IsSecure()
1245 ? COOKIE_SOURCE_SECURE_COOKIE_CRYPTOGRAPHIC_SCHEME
1246 : COOKIE_SOURCE_NONSECURE_COOKIE_CRYPTOGRAPHIC_SCHEME)
1247 : (cc->IsSecure()
1248 ? COOKIE_SOURCE_SECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME
1249 : COOKIE_SOURCE_NONSECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME));
1250 histogram_cookie_source_scheme_->Add(cookie_source_sample);
1251
Mike Westc4a777b2017-10-06 14:04:201252 if (!creation_date_to_inherit.is_null()) {
1253 cc->SetCreationDate(creation_date_to_inherit);
Mike Westc4a777b2017-10-06 14:04:201254 }
1255
rdsmith2709eee2017-06-20 22:43:271256 InternalInsertCookie(key, std::move(cc), true);
[email protected]348dd662013-03-13 20:25:071257 } else {
Oscar Johansson63e83cf2018-07-02 08:47:261258 VLOG(net::cookie_util::kVlogSetCookies)
1259 << "SetCookie() not storing already expired cookie.";
[email protected]c4058fb2010-06-22 17:25:261260 }
initial.commit586acc5fe2008-07-26 22:42:521261
1262 // We assume that hopefully setting a cookie will be less common than
1263 // querying a cookie. Since setting a cookie can put us over our limits,
1264 // make sure that we garbage collect... We can also make the assumption that
1265 // if a cookie was set, in the common case it will be used soon after,
1266 // and we will purge the expired cookies in GetCookies().
rdsmitha6ce4442017-06-21 17:11:051267 GarbageCollect(creation_date, key);
initial.commit586acc5fe2008-07-26 22:42:521268
rdsmithe5c701d2017-07-12 21:50:001269 MaybeRunCookieCallback(std::move(callback), true);
initial.commit586acc5fe2008-07-26 22:42:521270}
1271
rdsmithe5c701d2017-07-12 21:50:001272void CookieMonster::SetAllCookies(CookieList list,
1273 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:091274 DCHECK(thread_checker_.CalledOnValidThread());
rdsmithe5c701d2017-07-12 21:50:001275
rdsmith0e84cea2017-07-13 03:09:531276 // Nuke the existing store.
1277 while (!cookies_.empty()) {
1278 // TODO(rdsmith): The CANONICAL is a lie.
Nick Harper7a6683a2018-01-30 20:42:521279 InternalDeleteCookie(cookies_.begin(), true, DELETE_COOKIE_EXPLICIT);
rdsmithe5c701d2017-07-12 21:50:001280 }
1281
rdsmith0e84cea2017-07-13 03:09:531282 // Set all passed in cookies.
mmenkeea4cd402016-02-02 04:03:101283 for (const auto& cookie : list) {
rdsmith2709eee2017-06-20 22:43:271284 const std::string key(GetKey(cookie.Domain()));
1285 Time creation_time = cookie.CreationDate();
rdsmith0e84cea2017-07-13 03:09:531286 if (cookie.IsExpired(creation_time))
rdsmith2709eee2017-06-20 22:43:271287 continue;
1288
1289 if (cookie.IsPersistent()) {
1290 histogram_expiration_duration_minutes_->Add(
1291 (cookie.ExpiryDate() - creation_time).InMinutes());
mmenkeea4cd402016-02-02 04:03:101292 }
rdsmith2709eee2017-06-20 22:43:271293
Jeremy Roman0579ed62017-08-29 15:56:191294 InternalInsertCookie(key, std::make_unique<CanonicalCookie>(cookie), true);
rdsmith2709eee2017-06-20 22:43:271295 GarbageCollect(creation_time, key);
drogerd5d1278c2015-03-17 19:21:511296 }
1297
rdsmith2709eee2017-06-20 22:43:271298 // TODO(rdsmith): If this function always returns the same value, it
1299 // shouldn't have a return value. But it should also be deleted (see
1300 // https://codereview.chromium.org/2882063002/#msg64), which would
1301 // solve the return value problem.
rdsmithe5c701d2017-07-12 21:50:001302 MaybeRunCookieCallback(std::move(callback), true);
drogerd5d1278c2015-03-17 19:21:511303}
1304
[email protected]7a964a72010-09-07 19:33:261305void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc,
1306 const Time& current) {
mmenkebe0910d2016-03-01 19:09:091307 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041308
[email protected]77e0a462008-11-01 00:43:351309 // Based off the Mozilla code. When a cookie has been accessed recently,
1310 // don't bother updating its access time again. This reduces the number of
1311 // updates we do during pageload, which in turn reduces the chance our storage
1312 // backend will hit its batch thresholds and be forced to update.
[email protected]77e0a462008-11-01 00:43:351313 if ((current - cc->LastAccessDate()) < last_access_threshold_)
1314 return;
1315
1316 cc->SetLastAccessDate(current);
[email protected]90499482013-06-01 00:39:501317 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get())
[email protected]77e0a462008-11-01 00:43:351318 store_->UpdateCookieAccessTime(*cc);
1319}
1320
[email protected]6210ce52013-09-20 03:33:141321// InternalDeleteCookies must not invalidate iterators other than the one being
1322// deleted.
initial.commit586acc5fe2008-07-26 22:42:521323void CookieMonster::InternalDeleteCookie(CookieMap::iterator it,
[email protected]c4058fb2010-06-22 17:25:261324 bool sync_to_store,
1325 DeletionCause deletion_cause) {
mmenkebe0910d2016-03-01 19:09:091326 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041327
nharper352933e2016-09-30 18:24:571328 // Ideally, this would be asserted up where we define kChangeCauseMapping,
[email protected]8bb846f2011-03-23 12:08:181329 // but DeletionCause's visibility (or lack thereof) forces us to make
1330 // this check here.
Ryan Sleevi435a3a22018-05-15 02:16:071331 static_assert(base::size(kChangeCauseMapping) == DELETE_COOKIE_LAST_ENTRY + 1,
nharper352933e2016-09-30 18:24:571332 "kChangeCauseMapping size should match DeletionCause size");
[email protected]8bb846f2011-03-23 12:08:181333
avie7cd11a2016-10-11 02:00:351334 CanonicalCookie* cc = it->second.get();
Oscar Johansson63e83cf2018-07-02 08:47:261335 VLOG(net::cookie_util::kVlogSetCookies)
1336 << "InternalDeleteCookie()"
1337 << ", cause:" << deletion_cause << ", cc: " << cc->DebugString();
[email protected]7a964a72010-09-07 19:33:261338
Helen Licd0fab862018-08-13 16:07:531339 ChangeCausePair mapping = kChangeCauseMapping[deletion_cause];
1340 if (deletion_cause != DELETE_COOKIE_DONT_RECORD) {
1341 net_log_.AddEvent(NetLogEventType::COOKIE_STORE_COOKIE_DELETED,
1342 base::BindRepeating(&NetLogCookieMonsterCookieDeleted, cc,
1343 mapping.cause, sync_to_store));
1344 }
1345
[email protected]90499482013-06-01 00:39:501346 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get() &&
Helen Lid84010b2018-08-22 16:27:441347 sync_to_store) {
initial.commit586acc5fe2008-07-26 22:42:521348 store_->DeleteCookie(*cc);
Helen Lid84010b2018-08-22 16:27:441349 }
Victor Costan14f47c12018-03-01 08:02:241350 change_dispatcher_.DispatchChange(*cc, mapping.cause, mapping.notify);
initial.commit586acc5fe2008-07-26 22:42:521351 cookies_.erase(it);
initial.commit586acc5fe2008-07-26 22:42:521352}
1353
[email protected]8807b322010-10-01 17:10:141354// Domain expiry behavior is unchanged by key/expiry scheme (the
[email protected]8ad5d462013-05-02 08:45:261355// meaning of the key is different, but that's not visible to this routine).
jww82d99c12015-11-25 18:39:531356size_t CookieMonster::GarbageCollect(const Time& current,
jwwa26e439d2017-01-27 18:17:271357 const std::string& key) {
mmenkebe0910d2016-03-01 19:09:091358 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041359
jww82d99c12015-11-25 18:39:531360 size_t num_deleted = 0;
mkwstbe84af312015-02-20 08:52:451361 Time safe_date(Time::Now() - TimeDelta::FromDays(kSafeFromGlobalPurgeDays));
initial.commit586acc5fe2008-07-26 22:42:521362
[email protected]8ad5d462013-05-02 08:45:261363 // Collect garbage for this key, minding cookie priorities.
[email protected]7a964a72010-09-07 19:33:261364 if (cookies_.count(key) > kDomainMaxCookies) {
Oscar Johansson63e83cf2018-07-02 08:47:261365 VLOG(net::cookie_util::kVlogGarbageCollection)
1366 << "GarbageCollect() key: " << key;
[email protected]7a964a72010-09-07 19:33:261367
mkwst87734352016-03-03 17:36:231368 CookieItVector* cookie_its;
jww601411a2015-11-20 19:46:571369
mkwst87734352016-03-03 17:36:231370 CookieItVector non_expired_cookie_its;
1371 cookie_its = &non_expired_cookie_its;
jww82d99c12015-11-25 18:39:531372 num_deleted +=
mkwst87734352016-03-03 17:36:231373 GarbageCollectExpired(current, cookies_.equal_range(key), cookie_its);
jww82d99c12015-11-25 18:39:531374
mkwst87734352016-03-03 17:36:231375 if (cookie_its->size() > kDomainMaxCookies) {
Oscar Johansson63e83cf2018-07-02 08:47:261376 VLOG(net::cookie_util::kVlogGarbageCollection)
1377 << "Deep Garbage Collect domain.";
[email protected]8ad5d462013-05-02 08:45:261378 size_t purge_goal =
mkwst87734352016-03-03 17:36:231379 cookie_its->size() - (kDomainMaxCookies - kDomainPurgeCookies);
[email protected]8ad5d462013-05-02 08:45:261380 DCHECK(purge_goal > kDomainPurgeCookies);
1381
mkwste079ac412016-03-11 09:04:061382 // Sort the cookies by access date, from least-recent to most-recent.
1383 std::sort(cookie_its->begin(), cookie_its->end(), LRACookieSorter);
[email protected]8ad5d462013-05-02 08:45:261384
mkwste079ac412016-03-11 09:04:061385 // Remove all but the kDomainCookiesQuotaLow most-recently accessed
1386 // cookies with low-priority. Then, if cookies still need to be removed,
1387 // bump the quota and remove low- and medium-priority. Then, if cookies
1388 // _still_ need to be removed, bump the quota and remove cookies with
1389 // any priority.
jwwc00ac712016-05-05 22:21:441390 //
1391 // 1. Low-priority non-secure cookies.
1392 // 2. Low-priority secure cookies.
1393 // 3. Medium-priority non-secure cookies.
1394 // 4. High-priority non-secure cookies.
1395 // 5. Medium-priority secure cookies.
1396 // 6. High-priority secure cookies.
1397 const static struct {
1398 CookiePriority priority;
1399 bool protect_secure_cookies;
1400 } purge_rounds[] = {
1401 // 1. Low-priority non-secure cookies.
1402 {COOKIE_PRIORITY_LOW, true},
1403 // 2. Low-priority secure cookies.
1404 {COOKIE_PRIORITY_LOW, false},
1405 // 3. Medium-priority non-secure cookies.
1406 {COOKIE_PRIORITY_MEDIUM, true},
1407 // 4. High-priority non-secure cookies.
1408 {COOKIE_PRIORITY_HIGH, true},
1409 // 5. Medium-priority secure cookies.
1410 {COOKIE_PRIORITY_MEDIUM, false},
1411 // 6. High-priority secure cookies.
1412 {COOKIE_PRIORITY_HIGH, false},
1413 };
1414
mkwste079ac412016-03-11 09:04:061415 size_t quota = 0;
jwwc00ac712016-05-05 22:21:441416 for (const auto& purge_round : purge_rounds) {
mmenke645ca6772016-06-17 18:46:431417 // Adjust quota according to the priority of cookies. Each round should
1418 // protect certain number of cookies in order to avoid starvation.
1419 // For example, when each round starts to remove cookies, the number of
1420 // cookies of that priority are counted and a decision whether they
1421 // should be deleted or not is made. If yes, some number of cookies of
1422 // that priority are deleted considering the quota.
jwwc00ac712016-05-05 22:21:441423 switch (purge_round.priority) {
1424 case COOKIE_PRIORITY_LOW:
mmenke645ca6772016-06-17 18:46:431425 quota = kDomainCookiesQuotaLow;
jwwc00ac712016-05-05 22:21:441426 break;
1427 case COOKIE_PRIORITY_MEDIUM:
mmenke645ca6772016-06-17 18:46:431428 quota = kDomainCookiesQuotaMedium;
jwwc00ac712016-05-05 22:21:441429 break;
1430 case COOKIE_PRIORITY_HIGH:
mmenke645ca6772016-06-17 18:46:431431 quota = kDomainCookiesQuotaHigh;
jwwc00ac712016-05-05 22:21:441432 break;
1433 }
jwwc00ac712016-05-05 22:21:441434 size_t just_deleted = 0u;
jwwa26e439d2017-01-27 18:17:271435 // Purge up to |purge_goal| for all cookies at the given priority. This
1436 // path will be taken only if the initial non-secure purge did not evict
1437 // enough cookies.
jwwc00ac712016-05-05 22:21:441438 if (purge_goal > 0) {
1439 just_deleted = PurgeLeastRecentMatches(
1440 cookie_its, purge_round.priority, quota, purge_goal,
1441 purge_round.protect_secure_cookies);
1442 DCHECK_LE(just_deleted, purge_goal);
1443 purge_goal -= just_deleted;
1444 num_deleted += just_deleted;
1445 }
mkwst162d2712016-02-18 18:21:291446 }
mkwste079ac412016-03-11 09:04:061447
jwwc00ac712016-05-05 22:21:441448 DCHECK_EQ(0u, purge_goal);
[email protected]8807b322010-10-01 17:10:141449 }
initial.commit586acc5fe2008-07-26 22:42:521450 }
1451
[email protected]8ad5d462013-05-02 08:45:261452 // Collect garbage for everything. With firefox style we want to preserve
1453 // cookies accessed in kSafeFromGlobalPurgeDays, otherwise evict.
mkwstbe84af312015-02-20 08:52:451454 if (cookies_.size() > kMaxCookies && earliest_access_time_ < safe_date) {
Oscar Johansson63e83cf2018-07-02 08:47:261455 VLOG(net::cookie_util::kVlogGarbageCollection)
1456 << "GarbageCollect() everything";
[email protected]8ad5d462013-05-02 08:45:261457 CookieItVector cookie_its;
jww82d99c12015-11-25 18:39:531458
[email protected]7a964a72010-09-07 19:33:261459 num_deleted += GarbageCollectExpired(
1460 current, CookieMapItPair(cookies_.begin(), cookies_.end()),
1461 &cookie_its);
jww82d99c12015-11-25 18:39:531462
[email protected]8ad5d462013-05-02 08:45:261463 if (cookie_its.size() > kMaxCookies) {
Oscar Johansson63e83cf2018-07-02 08:47:261464 VLOG(net::cookie_util::kVlogGarbageCollection)
1465 << "Deep Garbage Collect everything.";
[email protected]8ad5d462013-05-02 08:45:261466 size_t purge_goal = cookie_its.size() - (kMaxCookies - kPurgeCookies);
1467 DCHECK(purge_goal > kPurgeCookies);
jww82d99c12015-11-25 18:39:531468
jwwa26e439d2017-01-27 18:17:271469 CookieItVector secure_cookie_its;
1470 CookieItVector non_secure_cookie_its;
1471 SplitCookieVectorIntoSecureAndNonSecure(cookie_its, &secure_cookie_its,
1472 &non_secure_cookie_its);
1473 size_t non_secure_purge_goal =
mmenkef4721d992017-06-07 17:13:591474 std::min<size_t>(purge_goal, non_secure_cookie_its.size());
jww82d99c12015-11-25 18:39:531475
mmenkef4721d992017-06-07 17:13:591476 base::Time earliest_non_secure_access_time;
jwwa26e439d2017-01-27 18:17:271477 size_t just_deleted = GarbageCollectLeastRecentlyAccessed(
mmenkef4721d992017-06-07 17:13:591478 current, safe_date, non_secure_purge_goal, non_secure_cookie_its,
1479 &earliest_non_secure_access_time);
jwwa26e439d2017-01-27 18:17:271480 num_deleted += just_deleted;
jww82d99c12015-11-25 18:39:531481
mmenkef4721d992017-06-07 17:13:591482 if (secure_cookie_its.size() == 0) {
1483 // This case is unlikely, but should still update
1484 // |earliest_access_time_| if only have non-secure cookies.
1485 earliest_access_time_ = earliest_non_secure_access_time;
1486 // Garbage collection can't delete all cookies.
1487 DCHECK(!earliest_access_time_.is_null());
1488 } else if (just_deleted < purge_goal) {
1489 size_t secure_purge_goal = std::min<size_t>(purge_goal - just_deleted,
1490 secure_cookie_its.size());
1491 base::Time earliest_secure_access_time;
jww82d99c12015-11-25 18:39:531492 num_deleted += GarbageCollectLeastRecentlyAccessed(
mmenkef4721d992017-06-07 17:13:591493 current, safe_date, secure_purge_goal, secure_cookie_its,
1494 &earliest_secure_access_time);
1495
1496 if (!earliest_non_secure_access_time.is_null() &&
1497 earliest_non_secure_access_time < earliest_secure_access_time) {
1498 earliest_access_time_ = earliest_non_secure_access_time;
1499 } else {
1500 earliest_access_time_ = earliest_secure_access_time;
1501 }
1502
1503 // Garbage collection can't delete all cookies.
1504 DCHECK(!earliest_access_time_.is_null());
jww82d99c12015-11-25 18:39:531505 }
mmenkef4721d992017-06-07 17:13:591506
1507 // If there are secure cookies, but deleting non-secure cookies was enough
1508 // to meet the purge goal, secure cookies are never examined, so
1509 // |earliest_access_time_| can't be determined. Leaving it alone will mean
1510 // it's no later than the real earliest last access time, so this won't
1511 // lead to any problems.
[email protected]8807b322010-10-01 17:10:141512 }
[email protected]c890ed192008-10-30 23:45:531513 }
1514
1515 return num_deleted;
1516}
1517
mkwste079ac412016-03-11 09:04:061518size_t CookieMonster::PurgeLeastRecentMatches(CookieItVector* cookies,
1519 CookiePriority priority,
1520 size_t to_protect,
jwwc00ac712016-05-05 22:21:441521 size_t purge_goal,
1522 bool protect_secure_cookies) {
mkwste079ac412016-03-11 09:04:061523 DCHECK(thread_checker_.CalledOnValidThread());
1524
mmenke645ca6772016-06-17 18:46:431525 // 1. Count number of the cookies at |priority|
1526 size_t cookies_count_possibly_to_be_deleted = CountCookiesForPossibleDeletion(
1527 priority, cookies, false /* count all cookies */);
1528
1529 // 2. If |cookies_count_possibly_to_be_deleted| at |priority| is less than or
1530 // equal |to_protect|, skip round in order to preserve the quota. This
1531 // involves secure and non-secure cookies at |priority|.
1532 if (cookies_count_possibly_to_be_deleted <= to_protect)
1533 return 0u;
1534
1535 // 3. Calculate number of secure cookies at |priority|
1536 // and number of cookies at |priority| that can possibly be deleted.
1537 // It is guaranteed we do not delete more than |purge_goal| even if
1538 // |cookies_count_possibly_to_be_deleted| is higher.
1539 size_t secure_cookies = 0u;
jwwc00ac712016-05-05 22:21:441540 if (protect_secure_cookies) {
mmenke645ca6772016-06-17 18:46:431541 secure_cookies = CountCookiesForPossibleDeletion(
1542 priority, cookies, protect_secure_cookies /* count secure cookies */);
1543 cookies_count_possibly_to_be_deleted -=
1544 std::max(secure_cookies, to_protect - secure_cookies);
1545 } else {
1546 cookies_count_possibly_to_be_deleted -= to_protect;
jwwc00ac712016-05-05 22:21:441547 }
1548
mmenke645ca6772016-06-17 18:46:431549 size_t removed = 0u;
1550 size_t current = 0u;
1551 while ((removed < purge_goal && current < cookies->size()) &&
1552 cookies_count_possibly_to_be_deleted > 0) {
avie7cd11a2016-10-11 02:00:351553 const CanonicalCookie* current_cookie = cookies->at(current)->second.get();
mmenke645ca6772016-06-17 18:46:431554 // Only delete the current cookie if the priority is equal to
1555 // the current level.
jwwc00ac712016-05-05 22:21:441556 if (IsCookieEligibleForEviction(priority, protect_secure_cookies,
1557 current_cookie)) {
mkwstaa07ee82016-03-11 15:32:141558 InternalDeleteCookie(cookies->at(current), true,
1559 DELETE_COOKIE_EVICTED_DOMAIN);
mkwste079ac412016-03-11 09:04:061560 cookies->erase(cookies->begin() + current);
1561 removed++;
mmenke645ca6772016-06-17 18:46:431562 cookies_count_possibly_to_be_deleted--;
mkwste079ac412016-03-11 09:04:061563 } else {
1564 current++;
1565 }
1566 }
1567 return removed;
1568}
1569
jww82d99c12015-11-25 18:39:531570size_t CookieMonster::GarbageCollectExpired(const Time& current,
1571 const CookieMapItPair& itpair,
1572 CookieItVector* cookie_its) {
mmenkebe0910d2016-03-01 19:09:091573 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041574
[email protected]c890ed192008-10-30 23:45:531575 int num_deleted = 0;
1576 for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) {
jdoerrie22a91d8b92018-10-05 08:43:261577 auto curit = it;
[email protected]c890ed192008-10-30 23:45:531578 ++it;
1579
1580 if (curit->second->IsExpired(current)) {
[email protected]2f3f3592010-07-07 20:11:511581 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
[email protected]c890ed192008-10-30 23:45:531582 ++num_deleted;
1583 } else if (cookie_its) {
1584 cookie_its->push_back(curit);
1585 }
initial.commit586acc5fe2008-07-26 22:42:521586 }
1587
1588 return num_deleted;
1589}
1590
jww82d99c12015-11-25 18:39:531591size_t CookieMonster::GarbageCollectDeleteRange(
1592 const Time& current,
1593 DeletionCause cause,
1594 CookieItVector::iterator it_begin,
1595 CookieItVector::iterator it_end) {
mmenkebe0910d2016-03-01 19:09:091596 DCHECK(thread_checker_.CalledOnValidThread());
1597
jdoerrie22a91d8b92018-10-05 08:43:261598 for (auto it = it_begin; it != it_end; it++) {
[email protected]8ad5d462013-05-02 08:45:261599 InternalDeleteCookie((*it), true, cause);
[email protected]c10da4b02010-03-25 14:38:321600 }
[email protected]8ad5d462013-05-02 08:45:261601 return it_end - it_begin;
[email protected]c10da4b02010-03-25 14:38:321602}
1603
mmenke74bcbd52016-01-21 17:17:561604size_t CookieMonster::GarbageCollectLeastRecentlyAccessed(
1605 const base::Time& current,
1606 const base::Time& safe_date,
1607 size_t purge_goal,
mmenkef4721d992017-06-07 17:13:591608 CookieItVector cookie_its,
1609 base::Time* earliest_time) {
1610 DCHECK_LE(purge_goal, cookie_its.size());
mmenkebe0910d2016-03-01 19:09:091611 DCHECK(thread_checker_.CalledOnValidThread());
1612
mmenkef4721d992017-06-07 17:13:591613 // Sorts up to *and including* |cookie_its[purge_goal]| (if it exists), so
1614 // |earliest_time| will be properly assigned even if
mmenke74bcbd52016-01-21 17:17:561615 // |global_purge_it| == |cookie_its.begin() + purge_goal|.
mmenkef4721d992017-06-07 17:13:591616 SortLeastRecentlyAccessed(
1617 cookie_its.begin(), cookie_its.end(),
1618 cookie_its.size() < purge_goal ? purge_goal + 1 : purge_goal);
mmenke74bcbd52016-01-21 17:17:561619 // Find boundary to cookies older than safe_date.
jdoerrie22a91d8b92018-10-05 08:43:261620 auto global_purge_it = LowerBoundAccessDate(
mmenke74bcbd52016-01-21 17:17:561621 cookie_its.begin(), cookie_its.begin() + purge_goal, safe_date);
jwwa26e439d2017-01-27 18:17:271622 // Only delete the old cookies and delete non-secure ones first.
mmenke74bcbd52016-01-21 17:17:561623 size_t num_deleted =
1624 GarbageCollectDeleteRange(current, DELETE_COOKIE_EVICTED_GLOBAL,
1625 cookie_its.begin(), global_purge_it);
mmenkef4721d992017-06-07 17:13:591626 if (global_purge_it != cookie_its.end())
1627 *earliest_time = (*global_purge_it)->second->LastAccessDate();
mmenke74bcbd52016-01-21 17:17:561628 return num_deleted;
1629}
1630
[email protected]ed32c212013-05-14 20:49:291631// A wrapper around registry_controlled_domains::GetDomainAndRegistry
Maks Orlovich323efaf2018-03-06 02:56:391632// to make clear we're creating a key for our local map or for the persistent
Aaron Tagliaboschibd34cc0c2019-01-31 01:19:521633// store's use. Here and in FindCookiesForRegistryControlledHost() are the only
1634// two places where we need to conditionalize based on key type.
[email protected]f48b9432011-01-11 07:25:401635//
1636// Note that this key algorithm explicitly ignores the scheme. This is
1637// because when we're entering cookies into the map from the backing store,
1638// we in general won't have the scheme at that point.
1639// In practical terms, this means that file cookies will be stored
1640// in the map either by an empty string or by UNC name (and will be
1641// limited by kMaxCookiesPerHost), and extension cookies will be stored
1642// based on the single extension id, as the extension id won't have the
1643// form of a DNS host and hence GetKey() will return it unchanged.
1644//
1645// Arguably the right thing to do here is to make the key
1646// algorithm dependent on the scheme, and make sure that the scheme is
1647// available everywhere the key must be obtained (specfically at backing
1648// store load time). This would require either changing the backing store
1649// database schema to include the scheme (far more trouble than it's worth), or
1650// separating out file cookies into their own CookieMonster instance and
1651// thus restricting each scheme to a single cookie monster (which might
1652// be worth it, but is still too much trouble to solve what is currently a
1653// non-problem).
Maks Orlovich323efaf2018-03-06 02:56:391654//
1655// static
1656std::string CookieMonster::GetKey(base::StringPiece domain) {
[email protected]f48b9432011-01-11 07:25:401657 std::string effective_domain(
[email protected]ed32c212013-05-14 20:49:291658 registry_controlled_domains::GetDomainAndRegistry(
[email protected]aabe1792014-01-30 21:37:461659 domain, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES));
[email protected]f48b9432011-01-11 07:25:401660 if (effective_domain.empty())
Maks Orlovich323efaf2018-03-06 02:56:391661 domain.CopyToString(&effective_domain);
[email protected]f48b9432011-01-11 07:25:401662
1663 if (!effective_domain.empty() && effective_domain[0] == '.')
1664 return effective_domain.substr(1);
1665 return effective_domain;
1666}
1667
1668bool CookieMonster::HasCookieableScheme(const GURL& url) {
mmenkebe0910d2016-03-01 19:09:091669 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401670
1671 // Make sure the request is on a cookie-able url scheme.
1672 for (size_t i = 0; i < cookieable_schemes_.size(); ++i) {
1673 // We matched a scheme.
1674 if (url.SchemeIs(cookieable_schemes_[i].c_str())) {
1675 // We've matched a supported scheme.
initial.commit586acc5fe2008-07-26 22:42:521676 return true;
1677 }
1678 }
[email protected]f48b9432011-01-11 07:25:401679
1680 // The scheme didn't match any in our whitelist.
Oscar Johansson63e83cf2018-07-02 08:47:261681 VLOG(net::cookie_util::kVlogPerCookieMonster)
mkwstbe84af312015-02-20 08:52:451682 << "WARNING: Unsupported cookie scheme: " << url.scheme();
initial.commit586acc5fe2008-07-26 22:42:521683 return false;
1684}
1685
[email protected]c4058fb2010-06-22 17:25:261686// Test to see if stats should be recorded, and record them if so.
1687// The goal here is to get sampling for the average browser-hour of
1688// activity. We won't take samples when the web isn't being surfed,
1689// and when the web is being surfed, we'll take samples about every
1690// kRecordStatisticsIntervalSeconds.
1691// last_statistic_record_time_ is initialized to Now() rather than null
1692// in the constructor so that we won't take statistics right after
1693// startup, to avoid bias from browsers that are started but not used.
1694void CookieMonster::RecordPeriodicStats(const base::Time& current_time) {
mmenkebe0910d2016-03-01 19:09:091695 DCHECK(thread_checker_.CalledOnValidThread());
1696
[email protected]c4058fb2010-06-22 17:25:261697 const base::TimeDelta kRecordStatisticsIntervalTime(
1698 base::TimeDelta::FromSeconds(kRecordStatisticsIntervalSeconds));
1699
[email protected]7a964a72010-09-07 19:33:261700 // If we've taken statistics recently, return.
1701 if (current_time - last_statistic_record_time_ <=
[email protected]c4058fb2010-06-22 17:25:261702 kRecordStatisticsIntervalTime) {
[email protected]7a964a72010-09-07 19:33:261703 return;
[email protected]c4058fb2010-06-22 17:25:261704 }
[email protected]7a964a72010-09-07 19:33:261705
1706 // See InitializeHistograms() for details.
1707 histogram_count_->Add(cookies_.size());
1708
1709 // More detailed statistics on cookie counts at different granularities.
[email protected]7a964a72010-09-07 19:33:261710 last_statistic_record_time_ = current_time;
[email protected]c4058fb2010-06-22 17:25:261711}
1712
[email protected]f48b9432011-01-11 07:25:401713// Initialize all histogram counter variables used in this class.
1714//
1715// Normal histogram usage involves using the macros defined in
1716// histogram.h, which automatically takes care of declaring these
1717// variables (as statics), initializing them, and accumulating into
1718// them, all from a single entry point. Unfortunately, that solution
1719// doesn't work for the CookieMonster, as it's vulnerable to races between
1720// separate threads executing the same functions and hence initializing the
1721// same static variables. There isn't a race danger in the histogram
1722// accumulation calls; they are written to be resilient to simultaneous
1723// calls from multiple threads.
1724//
1725// The solution taken here is to have per-CookieMonster instance
1726// variables that are constructed during CookieMonster construction.
1727// Note that these variables refer to the same underlying histogram,
1728// so we still race (but safely) with other CookieMonster instances
1729// for accumulation.
1730//
1731// To do this we've expanded out the individual histogram macros calls,
1732// with declarations of the variables in the class decl, initialization here
1733// (done from the class constructor) and direct calls to the accumulation
1734// methods where needed. The specific histogram macro calls on which the
1735// initialization is based are included in comments below.
1736void CookieMonster::InitializeHistograms() {
mmenkebe0910d2016-03-01 19:09:091737 DCHECK(thread_checker_.CalledOnValidThread());
1738
[email protected]f48b9432011-01-11 07:25:401739 // From UMA_HISTOGRAM_CUSTOM_COUNTS
1740 histogram_expiration_duration_minutes_ = base::Histogram::FactoryGet(
mkwstbe84af312015-02-20 08:52:451741 "Cookie.ExpirationDurationMinutes", 1, kMinutesInTenYears, 50,
[email protected]f48b9432011-01-11 07:25:401742 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401743 histogram_count_ = base::Histogram::FactoryGet(
mkwstbe84af312015-02-20 08:52:451744 "Cookie.Count", 1, 4000, 50, base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401745
1746 // From UMA_HISTOGRAM_ENUMERATION
mkwstc1aa4cc2015-04-03 19:57:451747 histogram_cookie_type_ = base::LinearHistogram::FactoryGet(
mkwst87378d92015-04-10 21:22:111748 "Cookie.Type", 1, (1 << COOKIE_TYPE_LAST_ENTRY) - 1,
1749 1 << COOKIE_TYPE_LAST_ENTRY, base::Histogram::kUmaTargetedHistogramFlag);
estark7feb65c2b2015-08-21 23:38:201750 histogram_cookie_source_scheme_ = base::LinearHistogram::FactoryGet(
1751 "Cookie.CookieSourceScheme", 1, COOKIE_SOURCE_LAST_ENTRY - 1,
1752 COOKIE_SOURCE_LAST_ENTRY, base::Histogram::kUmaTargetedHistogramFlag);
jww31e32632015-12-16 23:38:341753 histogram_cookie_delete_equivalent_ = base::LinearHistogram::FactoryGet(
1754 "Cookie.CookieDeleteEquivalent", 1,
1755 COOKIE_DELETE_EQUIVALENT_LAST_ENTRY - 1,
1756 COOKIE_DELETE_EQUIVALENT_LAST_ENTRY,
1757 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401758
1759 // From UMA_HISTOGRAM_{CUSTOM_,}TIMES
[email protected]c7593fb22011-11-14 23:54:271760 histogram_time_blocked_on_load_ = base::Histogram::FactoryTimeGet(
mkwstbe84af312015-02-20 08:52:451761 "Cookie.TimeBlockedOnLoad", base::TimeDelta::FromMilliseconds(1),
1762 base::TimeDelta::FromMinutes(1), 50,
1763 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401764}
1765
rdsmithe5c701d2017-07-12 21:50:001766void CookieMonster::DoCookieCallback(base::OnceClosure callback) {
mmenkebe0910d2016-03-01 19:09:091767 DCHECK(thread_checker_.CalledOnValidThread());
1768
1769 MarkCookieStoreAsInitialized();
1770 FetchAllCookiesIfNecessary();
mmenkef49fca0e2016-03-08 12:46:241771 seen_global_task_ = true;
mmenkebe0910d2016-03-01 19:09:091772
1773 if (!finished_fetching_all_cookies_ && store_.get()) {
rdsmithe5c701d2017-07-12 21:50:001774 tasks_pending_.push_back(std::move(callback));
mmenkebe0910d2016-03-01 19:09:091775 return;
mmenke74bcbd52016-01-21 17:17:561776 }
1777
rdsmithe5c701d2017-07-12 21:50:001778 std::move(callback).Run();
mmenke74bcbd52016-01-21 17:17:561779}
1780
rdsmithe5c701d2017-07-12 21:50:001781void CookieMonster::DoCookieCallbackForURL(base::OnceClosure callback,
1782 const GURL& url) {
Maks Orlovich323efaf2018-03-06 02:56:391783 DoCookieCallbackForHostOrDomain(std::move(callback), url.host_piece());
1784}
1785
1786void CookieMonster::DoCookieCallbackForHostOrDomain(
1787 base::OnceClosure callback,
1788 base::StringPiece host_or_domain) {
mmenkebe0910d2016-03-01 19:09:091789 MarkCookieStoreAsInitialized();
erikchende4c39e2018-01-29 21:33:361790 FetchAllCookiesIfNecessary();
mmenkebe0910d2016-03-01 19:09:091791
1792 // If cookies for the requested domain key (eTLD+1) have been loaded from DB
1793 // then run the task, otherwise load from DB.
1794 if (!finished_fetching_all_cookies_ && store_.get()) {
mmenkef49fca0e2016-03-08 12:46:241795 // If a global task has been previously seen, queue the task as a global
1796 // task. Note that the CookieMonster may be in the middle of executing
1797 // the global queue, |tasks_pending_| may be empty, which is why another
1798 // bool is needed.
1799 if (seen_global_task_) {
rdsmithe5c701d2017-07-12 21:50:001800 tasks_pending_.push_back(std::move(callback));
mmenkef49fca0e2016-03-08 12:46:241801 return;
1802 }
1803
mmenkebe0910d2016-03-01 19:09:091804 // Checks if the domain key has been loaded.
Maks Orlovich323efaf2018-03-06 02:56:391805 std::string key = GetKey(host_or_domain);
mmenkebe0910d2016-03-01 19:09:091806 if (keys_loaded_.find(key) == keys_loaded_.end()) {
jdoerrie22a91d8b92018-10-05 08:43:261807 auto it = tasks_pending_for_key_.find(key);
mmenkebe0910d2016-03-01 19:09:091808 if (it == tasks_pending_for_key_.end()) {
1809 store_->LoadCookiesForKey(
1810 key, base::Bind(&CookieMonster::OnKeyLoaded,
1811 weak_ptr_factory_.GetWeakPtr(), key));
1812 it = tasks_pending_for_key_
Brett Wilsonc6a0c822017-09-12 00:04:291813 .insert(std::make_pair(
1814 key, base::circular_deque<base::OnceClosure>()))
mmenkebe0910d2016-03-01 19:09:091815 .first;
mmenke74bcbd52016-01-21 17:17:561816 }
rdsmithe5c701d2017-07-12 21:50:001817 it->second.push_back(std::move(callback));
mmenkebe0910d2016-03-01 19:09:091818 return;
mmenke74bcbd52016-01-21 17:17:561819 }
1820 }
mmenkebe0910d2016-03-01 19:09:091821
rdsmithe5c701d2017-07-12 21:50:001822 std::move(callback).Run();
mmenke74bcbd52016-01-21 17:17:561823}
1824
[email protected]63725312012-07-19 08:24:161825} // namespace net