blob: 40f30163370037f393ae8fec933894685f7b77ef [file] [log] [blame]
[email protected]8e1583672012-02-11 04:39:411// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit586acc5fe2008-07-26 22:42:524
5// Portions of this code based on Mozilla:
6// (netwerk/cookie/src/nsCookieService.cpp)
7/* ***** BEGIN LICENSE BLOCK *****
8 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
9 *
10 * The contents of this file are subject to the Mozilla Public License Version
11 * 1.1 (the "License"); you may not use this file except in compliance with
12 * the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
14 *
15 * Software distributed under the License is distributed on an "AS IS" basis,
16 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
17 * for the specific language governing rights and limitations under the
18 * License.
19 *
20 * The Original Code is mozilla.org code.
21 *
22 * The Initial Developer of the Original Code is
23 * Netscape Communications Corporation.
24 * Portions created by the Initial Developer are Copyright (C) 2003
25 * the Initial Developer. All Rights Reserved.
26 *
27 * Contributor(s):
28 * Daniel Witte ([email protected])
29 * Michiel van Leeuwen ([email protected])
30 *
31 * Alternatively, the contents of this file may be used under the terms of
32 * either the GNU General Public License Version 2 or later (the "GPL"), or
33 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
34 * in which case the provisions of the GPL or the LGPL are applicable instead
35 * of those above. If you wish to allow use of your version of this file only
36 * under the terms of either the GPL or the LGPL, and not to allow others to
37 * use your version of this file under the terms of the MPL, indicate your
38 * decision by deleting the provisions above and replace them with the notice
39 * and other provisions required by the GPL or the LGPL. If you do not delete
40 * the provisions above, a recipient may use your version of this file under
41 * the terms of any one of the MPL, the GPL or the LGPL.
42 *
43 * ***** END LICENSE BLOCK ***** */
44
[email protected]63ee33bd2012-03-15 09:29:5845#include "net/cookies/cookie_monster.h"
initial.commit586acc5fe2008-07-26 22:42:5246
[email protected]8ad5d462013-05-02 08:45:2647#include <functional>
[email protected]09666482011-07-12 12:50:4048#include <set>
initial.commit586acc5fe2008-07-26 22:42:5249
[email protected]218aa6a12011-09-13 17:38:3850#include "base/bind.h"
[email protected]85620342011-10-17 17:35:0451#include "base/callback.h"
Ken Rockotc2048612018-03-29 01:43:3252#include "base/debug/dump_without_crashing.h"
skyostil4891b25b2015-06-11 11:43:4553#include "base/location.h"
initial.commit586acc5fe2008-07-26 22:42:5254#include "base/logging.h"
Avi Drissman13fc8932015-12-20 04:40:4655#include "base/macros.h"
erikchen1dd72a72015-05-06 20:45:0556#include "base/metrics/field_trial.h"
[email protected]835d7c82010-10-14 04:38:3857#include "base/metrics/histogram.h"
Ken Rockotc2048612018-03-29 01:43:3258#include "base/metrics/histogram_macros.h"
anujk.sharmaafc45172015-05-15 00:50:3459#include "base/single_thread_task_runner.h"
tripta.gdda72022017-06-19 05:16:2360#include "base/stl_util.h"
Maks Orlovich323efaf2018-03-06 02:56:3961#include "base/strings/string_piece.h"
[email protected]4b355212013-06-11 10:35:1962#include "base/strings/string_util.h"
63#include "base/strings/stringprintf.h"
gabf767595f2016-05-11 18:50:3564#include "base/threading/thread_task_runner_handle.h"
Ken Rockotc2048612018-03-29 01:43:3265#include "base/timer/elapsed_timer.h"
Maks Orlovich5cf437b02018-03-27 04:40:4266#include "base/trace_event/process_memory_dump.h"
[email protected]be28b5f42012-07-20 11:31:2567#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
[email protected]4b355212013-06-11 10:35:1968#include "net/cookies/canonical_cookie.h"
Victor Costan14f47c12018-03-01 08:02:2469#include "net/cookies/cookie_monster_change_dispatcher.h"
Helen Licd0fab862018-08-13 16:07:5370#include "net/cookies/cookie_monster_netlog_params.h"
[email protected]63ee33bd2012-03-15 09:29:5871#include "net/cookies/cookie_util.h"
[email protected]ebfe3172012-07-12 12:21:4172#include "net/cookies/parsed_cookie.h"
Helen Licd0fab862018-08-13 16:07:5373#include "net/log/net_log.h"
nharper2b0ad9a2017-05-22 18:33:4574#include "net/ssl/channel_id_service.h"
mkwst8241a122015-10-20 07:15:1075#include "url/origin.h"
initial.commit586acc5fe2008-07-26 22:42:5276
[email protected]e1acf6f2008-10-27 20:43:3377using base::Time;
78using base::TimeDelta;
[email protected]7a964a72010-09-07 19:33:2679using base::TimeTicks;
Chris Mumfordd8ed9f82018-05-01 15:43:1380using TimeRange = net::CookieDeletionInfo::TimeRange;
[email protected]e1acf6f2008-10-27 20:43:3381
[email protected]85620342011-10-17 17:35:0482// In steady state, most cookie requests can be satisfied by the in memory
erikchen1dd72a72015-05-06 20:45:0583// cookie monster store. If the cookie request cannot be satisfied by the in
84// memory store, the relevant cookies must be fetched from the persistent
85// store. The task is queued in CookieMonster::tasks_pending_ if it requires
86// all cookies to be loaded from the backend, or tasks_pending_for_key_ if it
87// only requires all cookies associated with an eTLD+1.
[email protected]85620342011-10-17 17:35:0488//
89// On the browser critical paths (e.g. for loading initial web pages in a
90// session restore) it may take too long to wait for the full load. If a cookie
rdsmithe5c701d2017-07-12 21:50:0091// request is for a specific URL, DoCookieCallbackForURL is called, which
92// triggers a priority load if the key is not loaded yet by calling
93// PersistentCookieStore::LoadCookiesForKey. The request is queued in
[email protected]0184df32013-05-14 00:53:5594// CookieMonster::tasks_pending_for_key_ and executed upon receiving
95// notification of key load completion via CookieMonster::OnKeyLoaded(). If
96// multiple requests for the same eTLD+1 are received before key load
97// completion, only the first request calls
[email protected]85620342011-10-17 17:35:0498// PersistentCookieStore::LoadCookiesForKey, all subsequent requests are queued
[email protected]0184df32013-05-14 00:53:5599// in CookieMonster::tasks_pending_for_key_ and executed upon receiving
100// notification of key load completion triggered by the first request for the
101// same eTLD+1.
[email protected]85620342011-10-17 17:35:04102
[email protected]c4058fb2010-06-22 17:25:26103static const int kMinutesInTenYears = 10 * 365 * 24 * 60;
104
erikchen1dd72a72015-05-06 20:45:05105namespace {
106
Maks Orlovichf97d1b92018-03-06 17:25:39107void MaybeRunDeleteCallback(base::WeakPtr<net::CookieMonster> cookie_monster,
108 base::OnceClosure callback) {
rdsmithe5c701d2017-07-12 21:50:00109 if (cookie_monster && callback)
110 std::move(callback).Run();
111}
112
113void MaybeRunCookieCallback(base::OnceClosure callback) {
114 if (callback)
115 std::move(callback).Run();
116}
117
118template <typename T>
119void MaybeRunCookieCallback(base::OnceCallback<void(const T&)> callback,
120 const T& result) {
121 if (callback)
122 std::move(callback).Run(result);
123}
124
125template <typename T>
126void MaybeRunCookieCallback(base::OnceCallback<void(T)> callback,
127 const T& result) {
128 if (callback)
129 std::move(callback).Run(result);
130}
131
Ken Rockotc2048612018-03-29 01:43:32132// Wraps a OnceClosure -- specifically one used by
133// |GetCookieListWithOptionsAsync()| -- with additional bound state to track the
Ken Rockot36ac3d02018-04-03 18:54:08134// duration between when its creation and destruction time.
Ken Rockotc2048612018-03-29 01:43:32135// See https://crbug.com/824024 for context.
136base::OnceClosure InstrumentGetCookieListClosure(base::OnceClosure closure) {
137 return base::BindOnce(
Ken Rockot36ac3d02018-04-03 18:54:08138 [](std::unique_ptr<base::ElapsedTimer> timer, base::OnceClosure closure) {
139 UMA_HISTOGRAM_CUSTOM_TIMES("Cookie.GetCookieListCompletionTime",
140 timer->Elapsed(),
141 base::TimeDelta::FromMilliseconds(10),
142 base::TimeDelta::FromSeconds(60), 50);
143 std::move(closure).Run();
144 },
145 std::make_unique<base::ElapsedTimer>(), std::move(closure));
Ken Rockotc2048612018-03-29 01:43:32146}
147
erikchen1dd72a72015-05-06 20:45:05148} // namespace
149
[email protected]8ac1a752008-07-31 19:40:37150namespace net {
151
[email protected]7a964a72010-09-07 19:33:26152// See comments at declaration of these variables in cookie_monster.h
153// for details.
mkwstbe84af312015-02-20 08:52:45154const size_t CookieMonster::kDomainMaxCookies = 180;
155const size_t CookieMonster::kDomainPurgeCookies = 30;
156const size_t CookieMonster::kMaxCookies = 3300;
157const size_t CookieMonster::kPurgeCookies = 300;
[email protected]8ad5d462013-05-02 08:45:26158
mkwst87734352016-03-03 17:36:23159const size_t CookieMonster::kDomainCookiesQuotaLow = 30;
160const size_t CookieMonster::kDomainCookiesQuotaMedium = 50;
161const size_t CookieMonster::kDomainCookiesQuotaHigh =
162 kDomainMaxCookies - kDomainPurgeCookies - kDomainCookiesQuotaLow -
163 kDomainCookiesQuotaMedium;
[email protected]8ad5d462013-05-02 08:45:26164
mkwstbe84af312015-02-20 08:52:45165const int CookieMonster::kSafeFromGlobalPurgeDays = 30;
[email protected]297a4ed02010-02-12 08:12:52166
[email protected]7a964a72010-09-07 19:33:26167namespace {
[email protected]e32306c52008-11-06 16:59:05168
[email protected]6210ce52013-09-20 03:33:14169bool ContainsControlCharacter(const std::string& s) {
170 for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
171 if ((*i >= 0) && (*i <= 31))
172 return true;
173 }
174
175 return false;
176}
177
[email protected]5b9bc352012-07-18 13:13:34178typedef std::vector<CanonicalCookie*> CanonicalCookieVector;
[email protected]34a160d2011-05-12 22:12:49179
[email protected]77e0a462008-11-01 00:43:35180// Default minimum delay after updating a cookie's LastAccessDate before we
181// will update it again.
[email protected]297a4ed02010-02-12 08:12:52182const int kDefaultAccessUpdateThresholdSeconds = 60;
183
184// Comparator to sort cookies from highest creation date to lowest
185// creation date.
186struct OrderByCreationTimeDesc {
187 bool operator()(const CookieMonster::CookieMap::iterator& a,
188 const CookieMonster::CookieMap::iterator& b) const {
189 return a->second->CreationDate() > b->second->CreationDate();
190 }
191};
192
[email protected]f48b9432011-01-11 07:25:40193// Mozilla sorts on the path length (longest first), and then it
194// sorts by creation time (oldest first).
195// The RFC says the sort order for the domain attribute is undefined.
[email protected]5b9bc352012-07-18 13:13:34196bool CookieSorter(CanonicalCookie* cc1, CanonicalCookie* cc2) {
[email protected]f48b9432011-01-11 07:25:40197 if (cc1->Path().length() == cc2->Path().length())
198 return cc1->CreationDate() < cc2->CreationDate();
199 return cc1->Path().length() > cc2->Path().length();
initial.commit586acc5fe2008-07-26 22:42:52200}
201
[email protected]8ad5d462013-05-02 08:45:26202bool LRACookieSorter(const CookieMonster::CookieMap::iterator& it1,
[email protected]f48b9432011-01-11 07:25:40203 const CookieMonster::CookieMap::iterator& it2) {
[email protected]f48b9432011-01-11 07:25:40204 if (it1->second->LastAccessDate() != it2->second->LastAccessDate())
205 return it1->second->LastAccessDate() < it2->second->LastAccessDate();
initial.commit586acc5fe2008-07-26 22:42:52206
mkwste079ac412016-03-11 09:04:06207 // Ensure stability for == last access times by falling back to creation.
[email protected]f48b9432011-01-11 07:25:40208 return it1->second->CreationDate() < it2->second->CreationDate();
[email protected]297a4ed02010-02-12 08:12:52209}
210
211// Our strategy to find duplicates is:
212// (1) Build a map from (cookiename, cookiepath) to
213// {list of cookies with this signature, sorted by creation time}.
214// (2) For each list with more than 1 entry, keep the cookie having the
215// most recent creation time, and delete the others.
[email protected]f48b9432011-01-11 07:25:40216//
[email protected]1655ba342010-07-14 18:17:42217// Two cookies are considered equivalent if they have the same domain,
218// name, and path.
219struct CookieSignature {
220 public:
[email protected]dedec0b2013-02-28 04:50:10221 CookieSignature(const std::string& name,
222 const std::string& domain,
[email protected]1655ba342010-07-14 18:17:42223 const std::string& path)
mkwstbe84af312015-02-20 08:52:45224 : name(name), domain(domain), path(path) {}
[email protected]1655ba342010-07-14 18:17:42225
226 // To be a key for a map this class needs to be assignable, copyable,
227 // and have an operator<. The default assignment operator
228 // and copy constructor are exactly what we want.
229
230 bool operator<(const CookieSignature& cs) const {
231 // Name compare dominates, then domain, then path.
232 int diff = name.compare(cs.name);
233 if (diff != 0)
234 return diff < 0;
235
236 diff = domain.compare(cs.domain);
237 if (diff != 0)
238 return diff < 0;
239
240 return path.compare(cs.path) < 0;
241 }
242
243 std::string name;
244 std::string domain;
245 std::string path;
246};
[email protected]f48b9432011-01-11 07:25:40247
[email protected]8ad5d462013-05-02 08:45:26248// For a CookieItVector iterator range [|it_begin|, |it_end|),
mmenkef4721d992017-06-07 17:13:59249// sorts the first |num_sort| elements by LastAccessDate().
mkwstbe84af312015-02-20 08:52:45250void SortLeastRecentlyAccessed(CookieMonster::CookieItVector::iterator it_begin,
251 CookieMonster::CookieItVector::iterator it_end,
252 size_t num_sort) {
mmenkef4721d992017-06-07 17:13:59253 DCHECK_LE(static_cast<int>(num_sort), it_end - it_begin);
254 std::partial_sort(it_begin, it_begin + num_sort, it_end, LRACookieSorter);
[email protected]8ad5d462013-05-02 08:45:26255}
[email protected]f48b9432011-01-11 07:25:40256
jww82d99c12015-11-25 18:39:53257// Given a single cookie vector |cookie_its|, pushs all of the secure cookies in
258// |cookie_its| into |secure_cookie_its| and all of the non-secure cookies into
259// |non_secure_cookie_its|. Both |secure_cookie_its| and |non_secure_cookie_its|
260// must be non-NULL.
261void SplitCookieVectorIntoSecureAndNonSecure(
262 const CookieMonster::CookieItVector& cookie_its,
263 CookieMonster::CookieItVector* secure_cookie_its,
264 CookieMonster::CookieItVector* non_secure_cookie_its) {
265 DCHECK(secure_cookie_its && non_secure_cookie_its);
266 for (const auto& curit : cookie_its) {
267 if (curit->second->IsSecure())
268 secure_cookie_its->push_back(curit);
269 else
270 non_secure_cookie_its->push_back(curit);
271 }
272}
273
mkwstbe84af312015-02-20 08:52:45274bool LowerBoundAccessDateComparator(const CookieMonster::CookieMap::iterator it,
275 const Time& access_date) {
[email protected]8ad5d462013-05-02 08:45:26276 return it->second->LastAccessDate() < access_date;
277}
278
279// For a CookieItVector iterator range [|it_begin|, |it_end|)
280// from a CookieItVector sorted by LastAccessDate(), returns the
281// first iterator with access date >= |access_date|, or cookie_its_end if this
282// holds for all.
283CookieMonster::CookieItVector::iterator LowerBoundAccessDate(
284 const CookieMonster::CookieItVector::iterator its_begin,
285 const CookieMonster::CookieItVector::iterator its_end,
286 const Time& access_date) {
287 return std::lower_bound(its_begin, its_end, access_date,
288 LowerBoundAccessDateComparator);
[email protected]7a964a72010-09-07 19:33:26289}
290
Victor Costan14f47c12018-03-01 08:02:24291// Mapping between DeletionCause and CookieChangeCause; the
[email protected]7c4b66b2014-01-04 12:28:13292// mapping also provides a boolean that specifies whether or not an
Victor Costan14f47c12018-03-01 08:02:24293// OnCookieChange notification ought to be generated.
[email protected]8bb846f2011-03-23 12:08:18294typedef struct ChangeCausePair_struct {
Victor Costan14f47c12018-03-01 08:02:24295 CookieChangeCause cause;
[email protected]8bb846f2011-03-23 12:08:18296 bool notify;
297} ChangeCausePair;
nharper352933e2016-09-30 18:24:57298const ChangeCausePair kChangeCauseMapping[] = {
mkwstbe84af312015-02-20 08:52:45299 // DELETE_COOKIE_EXPLICIT
Victor Costan14f47c12018-03-01 08:02:24300 {CookieChangeCause::EXPLICIT, true},
mkwstbe84af312015-02-20 08:52:45301 // DELETE_COOKIE_OVERWRITE
Victor Costan14f47c12018-03-01 08:02:24302 {CookieChangeCause::OVERWRITE, true},
mkwstbe84af312015-02-20 08:52:45303 // DELETE_COOKIE_EXPIRED
Victor Costan14f47c12018-03-01 08:02:24304 {CookieChangeCause::EXPIRED, true},
mkwstbe84af312015-02-20 08:52:45305 // DELETE_COOKIE_EVICTED
Victor Costan14f47c12018-03-01 08:02:24306 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45307 // DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE
Victor Costan14f47c12018-03-01 08:02:24308 {CookieChangeCause::EXPLICIT, false},
mkwstbe84af312015-02-20 08:52:45309 // DELETE_COOKIE_DONT_RECORD
Victor Costan14f47c12018-03-01 08:02:24310 {CookieChangeCause::EXPLICIT, false},
mkwstbe84af312015-02-20 08:52:45311 // DELETE_COOKIE_EVICTED_DOMAIN
Victor Costan14f47c12018-03-01 08:02:24312 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45313 // DELETE_COOKIE_EVICTED_GLOBAL
Victor Costan14f47c12018-03-01 08:02:24314 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45315 // DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE
Victor Costan14f47c12018-03-01 08:02:24316 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45317 // DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE
Victor Costan14f47c12018-03-01 08:02:24318 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45319 // DELETE_COOKIE_EXPIRED_OVERWRITE
Victor Costan14f47c12018-03-01 08:02:24320 {CookieChangeCause::EXPIRED_OVERWRITE, true},
mkwstbe84af312015-02-20 08:52:45321 // DELETE_COOKIE_CONTROL_CHAR
Victor Costan14f47c12018-03-01 08:02:24322 {CookieChangeCause::EVICTED, true},
jww82d99c12015-11-25 18:39:53323 // DELETE_COOKIE_NON_SECURE
Victor Costan14f47c12018-03-01 08:02:24324 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45325 // DELETE_COOKIE_LAST_ENTRY
Victor Costan14f47c12018-03-01 08:02:24326 {CookieChangeCause::EXPLICIT, false}};
ellyjones399e35a22014-10-27 11:09:56327
jwwc00ac712016-05-05 22:21:44328bool IsCookieEligibleForEviction(CookiePriority current_priority_level,
329 bool protect_secure_cookies,
330 const CanonicalCookie* cookie) {
mmenke645ca6772016-06-17 18:46:43331 if (cookie->Priority() == current_priority_level && protect_secure_cookies)
332 return !cookie->IsSecure();
jwwc00ac712016-05-05 22:21:44333
mmenke645ca6772016-06-17 18:46:43334 return cookie->Priority() == current_priority_level;
335}
jwwc00ac712016-05-05 22:21:44336
mmenke645ca6772016-06-17 18:46:43337size_t CountCookiesForPossibleDeletion(
338 CookiePriority priority,
339 const CookieMonster::CookieItVector* cookies,
340 bool protect_secure_cookies) {
341 size_t cookies_count = 0U;
342 for (const auto& cookie : *cookies) {
343 if (cookie->second->Priority() == priority) {
344 if (!protect_secure_cookies || cookie->second->IsSecure())
345 cookies_count++;
346 }
347 }
348 return cookies_count;
jwwc00ac712016-05-05 22:21:44349}
350
[email protected]f48b9432011-01-11 07:25:40351} // namespace
352
Pritam8354cf702018-03-10 08:55:41353CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
Helen Lifb313a92018-08-14 15:46:44354 ChannelIDService* channel_id_service,
355 NetLog* net_log)
Randy Smithb78e0922018-03-01 21:19:54356 : CookieMonster(
Pritam8354cf702018-03-10 08:55:41357 std::move(store),
Randy Smithb78e0922018-03-01 21:19:54358 channel_id_service,
Helen Lifb313a92018-08-14 15:46:44359 base::TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds),
360 net_log) {}
Randy Smithb78e0922018-03-01 21:19:54361
Pritam8354cf702018-03-10 08:55:41362CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
Helen Lifb313a92018-08-14 15:46:44363 base::TimeDelta last_access_threshold,
364 NetLog* net_log)
365 : CookieMonster(std::move(store), nullptr, last_access_threshold, net_log) {
366}
Randy Smithb78e0922018-03-01 21:19:54367
Pritam8354cf702018-03-10 08:55:41368CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
Randy Smithb78e0922018-03-01 21:19:54369 ChannelIDService* channel_id_service,
Helen Lifb313a92018-08-14 15:46:44370 base::TimeDelta last_access_threshold,
371 NetLog* net_log)
[email protected]f48b9432011-01-11 07:25:40372 : initialized_(false),
erikchen1dd72a72015-05-06 20:45:05373 started_fetching_all_cookies_(false),
374 finished_fetching_all_cookies_(false),
mmenkef49fca0e2016-03-08 12:46:24375 seen_global_task_(false),
Helen Lifb313a92018-08-14 15:46:44376 net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::COOKIE_STORE)),
Pritam8354cf702018-03-10 08:55:41377 store_(std::move(store)),
shessf0bc1182016-05-19 04:35:58378 last_access_threshold_(last_access_threshold),
nharper2b0ad9a2017-05-22 18:33:45379 channel_id_service_(channel_id_service),
[email protected]82388662011-03-10 21:04:06380 last_statistic_record_time_(base::Time::Now()),
mmenkebe0910d2016-03-01 19:09:09381 persist_session_cookies_(false),
382 weak_ptr_factory_(this) {
[email protected]f48b9432011-01-11 07:25:40383 InitializeHistograms();
mmenke18dd8ba2016-02-01 18:42:10384 cookieable_schemes_.insert(
385 cookieable_schemes_.begin(), kDefaultCookieableSchemes,
386 kDefaultCookieableSchemes + kDefaultCookieableSchemesCount);
Nick Harper14e23332017-07-28 00:27:23387 if (channel_id_service_ && store_) {
388 // |store_| can outlive this CookieMonster, but there are no guarantees
389 // about the lifetime of |channel_id_service_| relative to |store_|. The
390 // only guarantee is that |channel_id_service_| will outlive this
391 // CookieMonster. To avoid the PersistentCookieStore retaining a pointer to
392 // the ChannelIDStore via this callback after this CookieMonster is
393 // destroyed, CookieMonster's d'tor sets the callback to a null callback.
394 store_->SetBeforeFlushCallback(
395 base::Bind(&ChannelIDStore::Flush,
396 base::Unretained(channel_id_service_->GetChannelIDStore())));
397 }
Helen Licd0fab862018-08-13 16:07:53398 net_log_.BeginEvent(
399 NetLogEventType::COOKIE_STORE_ALIVE,
400 base::BindRepeating(&NetLogCookieMonsterConstructorCallback,
401 store != nullptr, channel_id_service != nullptr));
initial.commit586acc5fe2008-07-26 22:42:52402}
403
[email protected]218aa6a12011-09-13 17:38:38404// Asynchronous CookieMonster API
405
rdsmith7ac81712017-06-22 17:09:54406void CookieMonster::FlushStore(base::OnceClosure callback) {
mmenkebe0910d2016-03-01 19:09:09407 DCHECK(thread_checker_.CalledOnValidThread());
mmenke606c59c2016-03-07 18:20:55408
nharper2b0ad9a2017-05-22 18:33:45409 if (initialized_ && store_.get()) {
rdsmith7ac81712017-06-22 17:09:54410 store_->Flush(std::move(callback));
rdsmithe5c701d2017-07-12 21:50:00411 } else if (callback) {
rdsmith7ac81712017-06-22 17:09:54412 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
413 std::move(callback));
nharper2b0ad9a2017-05-22 18:33:45414 }
mmenke74bcbd52016-01-21 17:17:56415}
416
mmenkeded79da2016-02-06 08:28:51417void CookieMonster::SetForceKeepSessionState() {
mmenkebe0910d2016-03-01 19:09:09418 DCHECK(thread_checker_.CalledOnValidThread());
mmenke606c59c2016-03-07 18:20:55419
mmenkeded79da2016-02-06 08:28:51420 if (store_)
421 store_->SetForceKeepSessionState();
422}
423
drogerd5d1278c2015-03-17 19:21:51424void CookieMonster::SetAllCookiesAsync(const CookieList& list,
rdsmith7ac81712017-06-22 17:09:54425 SetCookiesCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00426 DoCookieCallback(base::BindOnce(
427 // base::Unretained is safe as DoCookieCallbackForURL stores
428 // the callback on |*this|, so the callback will not outlive
429 // the object.
430 &CookieMonster::SetAllCookies, base::Unretained(this), list,
431 std::move(callback)));
drogerd5d1278c2015-03-17 19:21:51432}
433
rdsmitha6ce4442017-06-21 17:11:05434void CookieMonster::SetCanonicalCookieAsync(
435 std::unique_ptr<CanonicalCookie> cookie,
436 bool secure_source,
437 bool modify_http_only,
rdsmith7ac81712017-06-22 17:09:54438 SetCookiesCallback callback) {
rdsmitha6ce4442017-06-21 17:11:05439 DCHECK(cookie->IsCanonical());
rdsmitha6ce4442017-06-21 17:11:05440
Maks Orlovich323efaf2018-03-06 02:56:39441 std::string domain = cookie->Domain();
442 DoCookieCallbackForHostOrDomain(
443 base::BindOnce(
444 // base::Unretained is safe as DoCookieCallbackForURL stores
445 // the callback on |*this|, so the callback will not outlive
446 // the object.
447 &CookieMonster::SetCanonicalCookie, base::Unretained(this),
448 std::move(cookie), secure_source, modify_http_only,
449 std::move(callback)),
450 domain);
rdsmitha6ce4442017-06-21 17:11:05451}
452
rdsmith7ac81712017-06-22 17:09:54453void CookieMonster::SetCookieWithOptionsAsync(const GURL& url,
454 const std::string& cookie_line,
455 const CookieOptions& options,
456 SetCookiesCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00457 DoCookieCallbackForURL(
458 base::BindOnce(
459 // base::Unretained is safe as DoCookieCallbackForURL stores
460 // the callback on |*this|, so the callback will not outlive
461 // the object.
462 &CookieMonster::SetCookieWithOptions, base::Unretained(this), url,
463 cookie_line, options, std::move(callback)),
464 url);
[email protected]218aa6a12011-09-13 17:38:38465}
466
mkwstc611e6d2016-02-23 15:45:55467void CookieMonster::GetCookieListWithOptionsAsync(
mmenke74bcbd52016-01-21 17:17:56468 const GURL& url,
mkwstc611e6d2016-02-23 15:45:55469 const CookieOptions& options,
rdsmith7ac81712017-06-22 17:09:54470 GetCookieListCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00471 DoCookieCallbackForURL(
Ken Rockotc2048612018-03-29 01:43:32472 InstrumentGetCookieListClosure(base::BindOnce(
rdsmithe5c701d2017-07-12 21:50:00473 // base::Unretained is safe as DoCookieCallbackForURL stores
474 // the callback on |*this|, so the callback will not outlive
475 // the object.
476 &CookieMonster::GetCookieListWithOptions, base::Unretained(this), url,
Ken Rockotc2048612018-03-29 01:43:32477 options, std::move(callback))),
rdsmithe5c701d2017-07-12 21:50:00478 url);
mmenke74bcbd52016-01-21 17:17:56479}
480
rdsmith7ac81712017-06-22 17:09:54481void CookieMonster::GetAllCookiesAsync(GetCookieListCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00482 DoCookieCallback(base::BindOnce(
483 // base::Unretained is safe as DoCookieCallbackForURL stores
484 // the callback on |*this|, so the callback will not outlive
485 // the object.
486 &CookieMonster::GetAllCookies, base::Unretained(this),
487 std::move(callback)));
mmenke9fa44f2d2016-01-22 23:36:39488}
489
[email protected]218aa6a12011-09-13 17:38:38490void CookieMonster::DeleteCookieAsync(const GURL& url,
491 const std::string& cookie_name,
rdsmith7ac81712017-06-22 17:09:54492 base::OnceClosure callback) {
rdsmithe5c701d2017-07-12 21:50:00493 DoCookieCallbackForURL(
494 base::BindOnce(
495 // base::Unretained is safe as DoCookieCallbackForURL stores
496 // the callback on |*this|, so the callback will not outlive
497 // the object.
498 &CookieMonster::DeleteCookie, base::Unretained(this), url,
499 cookie_name, std::move(callback)),
500 url);
[email protected]218aa6a12011-09-13 17:38:38501}
502
mmenke24379d52016-02-05 23:50:17503void CookieMonster::DeleteCanonicalCookieAsync(const CanonicalCookie& cookie,
rdsmith7ac81712017-06-22 17:09:54504 DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00505 DoCookieCallback(base::BindOnce(
506 // base::Unretained is safe as DoCookieCallbackForURL stores
507 // the callback on |*this|, so the callback will not outlive
508 // the object.
509 &CookieMonster::DeleteCanonicalCookie, base::Unretained(this), cookie,
510 std::move(callback)));
mmenke24379d52016-02-05 23:50:17511}
512
Chris Mumford800caa62018-04-20 19:34:44513void CookieMonster::DeleteAllCreatedInTimeRangeAsync(
514 const TimeRange& creation_range,
515 DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00516 DoCookieCallback(base::BindOnce(
517 // base::Unretained is safe as DoCookieCallbackForURL stores
518 // the callback on |*this|, so the callback will not outlive
519 // the object.
Chris Mumford800caa62018-04-20 19:34:44520 &CookieMonster::DeleteAllCreatedInTimeRange, base::Unretained(this),
521 creation_range, std::move(callback)));
mmenke74bcbd52016-01-21 17:17:56522}
523
Chris Mumford800caa62018-04-20 19:34:44524void CookieMonster::DeleteAllMatchingInfoAsync(CookieDeletionInfo delete_info,
525 DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00526 DoCookieCallback(base::BindOnce(
527 // base::Unretained is safe as DoCookieCallbackForURL stores
528 // the callback on |*this|, so the callback will not outlive
529 // the object.
Chris Mumford800caa62018-04-20 19:34:44530 &CookieMonster::DeleteAllMatchingInfo, base::Unretained(this),
531 std::move(delete_info), std::move(callback)));
mmenke74bcbd52016-01-21 17:17:56532}
533
[email protected]264807b2012-04-25 14:49:37534void CookieMonster::DeleteSessionCookiesAsync(
rdsmith7ac81712017-06-22 17:09:54535 CookieStore::DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00536 DoCookieCallback(base::BindOnce(
537 // base::Unretained is safe as DoCookieCallbackForURL stores
538 // the callback on |*this|, so the callback will not outlive
539 // the object.
540 &CookieMonster::DeleteSessionCookies, base::Unretained(this),
541 std::move(callback)));
[email protected]264807b2012-04-25 14:49:37542}
543
mmenke18dd8ba2016-02-01 18:42:10544void CookieMonster::SetCookieableSchemes(
545 const std::vector<std::string>& schemes) {
mmenkebe0910d2016-03-01 19:09:09546 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56547
548 // Calls to this method will have no effect if made after a WebView or
549 // CookieManager instance has been created.
mmenke18dd8ba2016-02-01 18:42:10550 if (initialized_)
mmenke74bcbd52016-01-21 17:17:56551 return;
mmenke74bcbd52016-01-21 17:17:56552
mmenke18dd8ba2016-02-01 18:42:10553 cookieable_schemes_ = schemes;
mmenke74bcbd52016-01-21 17:17:56554}
555
mmenke74bcbd52016-01-21 17:17:56556// This function must be called before the CookieMonster is used.
557void CookieMonster::SetPersistSessionCookies(bool persist_session_cookies) {
mmenkebe0910d2016-03-01 19:09:09558 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56559 DCHECK(!initialized_);
Helen Licd0fab862018-08-13 16:07:53560 net_log_.AddEvent(
561 NetLogEventType::COOKIE_STORE_SESSION_PERSISTENCE,
562 NetLog::BoolCallback("persistence", persist_session_cookies));
mmenke74bcbd52016-01-21 17:17:56563 persist_session_cookies_ = persist_session_cookies;
564}
565
566bool CookieMonster::IsCookieableScheme(const std::string& scheme) {
mmenkebe0910d2016-03-01 19:09:09567 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56568
tripta.gdda72022017-06-19 05:16:23569 return base::ContainsValue(cookieable_schemes_, scheme);
mmenke74bcbd52016-01-21 17:17:56570}
571
mmenke18dd8ba2016-02-01 18:42:10572const char* const CookieMonster::kDefaultCookieableSchemes[] = {"http", "https",
573 "ws", "wss"};
mmenke74bcbd52016-01-21 17:17:56574const int CookieMonster::kDefaultCookieableSchemesCount =
Ryan Sleevi435a3a22018-05-15 02:16:07575 base::size(kDefaultCookieableSchemes);
mmenke74bcbd52016-01-21 17:17:56576
Victor Costan14f47c12018-03-01 08:02:24577CookieChangeDispatcher& CookieMonster::GetChangeDispatcher() {
578 return change_dispatcher_;
Randy Smithd32dc8c2017-08-30 18:03:40579}
580
nharper5babb5e62016-03-09 18:58:07581bool CookieMonster::IsEphemeral() {
582 return store_.get() == nullptr;
583}
584
Maks Orlovich5cf437b02018-03-27 04:40:42585void CookieMonster::DumpMemoryStats(
586 base::trace_event::ProcessMemoryDump* pmd,
587 const std::string& parent_absolute_name) const {
588 const char kRelPath[] = "/cookie_monster";
589
590 pmd->CreateAllocatorDump(parent_absolute_name + kRelPath + "/cookies")
591 ->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
592 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
593 cookies_.size());
594
595 pmd->CreateAllocatorDump(parent_absolute_name + kRelPath +
596 "/tasks_pending_global")
597 ->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
598 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
599 tasks_pending_.size());
600
601 size_t total_pending_for_key = 0;
602 for (const auto& kv : tasks_pending_for_key_)
603 total_pending_for_key += kv.second.size();
604 pmd->CreateAllocatorDump(parent_absolute_name + kRelPath +
605 "/tasks_pending_for_key")
606 ->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
607 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
608 total_pending_for_key);
609}
610
mmenke74bcbd52016-01-21 17:17:56611CookieMonster::~CookieMonster() {
mmenkebe0910d2016-03-01 19:09:09612 DCHECK(thread_checker_.CalledOnValidThread());
mmenke05255cf2016-02-03 15:49:31613
Nick Harper14e23332017-07-28 00:27:23614 if (channel_id_service_ && store_) {
615 store_->SetBeforeFlushCallback(base::Closure());
616 }
617
Randy Smith0a522662017-08-30 19:35:34618 // TODO(mmenke): Does it really make sense to run
mmenke606c59c2016-03-07 18:20:55619 // CookieChanged callbacks when the CookieStore is destroyed?
mmenke05255cf2016-02-03 15:49:31620 for (CookieMap::iterator cookie_it = cookies_.begin();
621 cookie_it != cookies_.end();) {
622 CookieMap::iterator current_cookie_it = cookie_it;
623 ++cookie_it;
624 InternalDeleteCookie(current_cookie_it, false /* sync_to_store */,
625 DELETE_COOKIE_DONT_RECORD);
626 }
Helen Licd0fab862018-08-13 16:07:53627 net_log_.EndEvent(NetLogEventType::COOKIE_STORE_ALIVE);
[email protected]85620342011-10-17 17:35:04628}
629
rdsmithe5c701d2017-07-12 21:50:00630void CookieMonster::GetAllCookies(GetCookieListCallback callback) {
mmenkebe0910d2016-03-01 19:09:09631 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40632
633 // This function is being called to scrape the cookie list for management UI
634 // or similar. We shouldn't show expired cookies in this list since it will
635 // just be confusing to users, and this function is called rarely enough (and
636 // is already slow enough) that it's OK to take the time to garbage collect
637 // the expired cookies now.
638 //
639 // Note that this does not prune cookies to be below our limits (if we've
640 // exceeded them) the way that calling GarbageCollect() would.
mkwstbe84af312015-02-20 08:52:45641 GarbageCollectExpired(
642 Time::Now(), CookieMapItPair(cookies_.begin(), cookies_.end()), NULL);
[email protected]f48b9432011-01-11 07:25:40643
644 // Copy the CanonicalCookie pointers from the map so that we can use the same
645 // sorter as elsewhere, then copy the result out.
646 std::vector<CanonicalCookie*> cookie_ptrs;
647 cookie_ptrs.reserve(cookies_.size());
avie7cd11a2016-10-11 02:00:35648 for (const auto& cookie : cookies_)
649 cookie_ptrs.push_back(cookie.second.get());
[email protected]f48b9432011-01-11 07:25:40650 std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
651
652 CookieList cookie_list;
653 cookie_list.reserve(cookie_ptrs.size());
vmpstr6d9996c82017-02-23 00:43:25654 for (auto* cookie_ptr : cookie_ptrs)
avie7cd11a2016-10-11 02:00:35655 cookie_list.push_back(*cookie_ptr);
[email protected]f48b9432011-01-11 07:25:40656
rdsmithe5c701d2017-07-12 21:50:00657 MaybeRunCookieCallback(std::move(callback), cookie_list);
[email protected]f325f1e12010-04-30 22:38:55658}
659
rdsmithe5c701d2017-07-12 21:50:00660void CookieMonster::GetCookieListWithOptions(const GURL& url,
661 const CookieOptions& options,
662 GetCookieListCallback callback) {
mmenkebe0910d2016-03-01 19:09:09663 DCHECK(thread_checker_.CalledOnValidThread());
initial.commit586acc5fe2008-07-26 22:42:52664
mkwstc611e6d2016-02-23 15:45:55665 CookieList cookies;
rdsmithe5c701d2017-07-12 21:50:00666 if (HasCookieableScheme(url)) {
667 std::vector<CanonicalCookie*> cookie_ptrs;
668 FindCookiesForHostAndDomain(url, options, &cookie_ptrs);
669 std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
mkwstc611e6d2016-02-23 15:45:55670
rdsmithe5c701d2017-07-12 21:50:00671 cookies.reserve(cookie_ptrs.size());
672 for (std::vector<CanonicalCookie*>::const_iterator it = cookie_ptrs.begin();
673 it != cookie_ptrs.end(); it++)
674 cookies.push_back(**it);
675 }
676 MaybeRunCookieCallback(std::move(callback), cookies);
initial.commit586acc5fe2008-07-26 22:42:52677}
678
Chris Mumford800caa62018-04-20 19:34:44679void CookieMonster::DeleteAllCreatedInTimeRange(const TimeRange& creation_range,
680 DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09681 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]d0980332010-11-16 17:08:53682
rdsmitha5beda162017-07-08 13:55:42683 uint32_t num_deleted = 0;
[email protected]f48b9432011-01-11 07:25:40684 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
685 CookieMap::iterator curit = it;
avie7cd11a2016-10-11 02:00:35686 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:40687 ++it;
[email protected]d0980332010-11-16 17:08:53688
Chris Mumford800caa62018-04-20 19:34:44689 if (creation_range.Contains(cc->CreationDate())) {
mkwstbe84af312015-02-20 08:52:45690 InternalDeleteCookie(curit, true, /*sync_to_store*/
Nick Harper7a6683a2018-01-30 20:42:52691 DELETE_COOKIE_EXPLICIT);
[email protected]f48b9432011-01-11 07:25:40692 ++num_deleted;
initial.commit586acc5fe2008-07-26 22:42:52693 }
694 }
695
rdsmithe5c701d2017-07-12 21:50:00696 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39697 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00698 callback ? base::BindOnce(std::move(callback), num_deleted)
699 : base::OnceClosure()));
[email protected]f48b9432011-01-11 07:25:40700}
701
Chris Mumford800caa62018-04-20 19:34:44702void CookieMonster::DeleteAllMatchingInfo(CookieDeletionInfo delete_info,
703 DeleteCallback callback) {
rdsmitha5beda162017-07-08 13:55:42704 uint32_t num_deleted = 0;
dmurphfaea244c2016-04-09 00:42:30705 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
706 CookieMap::iterator curit = it;
avie7cd11a2016-10-11 02:00:35707 CanonicalCookie* cc = curit->second.get();
dmurphfaea244c2016-04-09 00:42:30708 ++it;
[email protected]f48b9432011-01-11 07:25:40709
Chris Mumford800caa62018-04-20 19:34:44710 if (delete_info.Matches(*cc)) {
dmurphfaea244c2016-04-09 00:42:30711 InternalDeleteCookie(curit, true, /*sync_to_store*/
Nick Harper7a6683a2018-01-30 20:42:52712 DELETE_COOKIE_EXPLICIT);
dmurphfaea244c2016-04-09 00:42:30713 ++num_deleted;
[email protected]f48b9432011-01-11 07:25:40714 }
715 }
dmurphfaea244c2016-04-09 00:42:30716
rdsmithe5c701d2017-07-12 21:50:00717 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39718 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00719 callback ? base::BindOnce(std::move(callback), num_deleted)
720 : base::OnceClosure()));
[email protected]f48b9432011-01-11 07:25:40721}
722
rdsmithe5c701d2017-07-12 21:50:00723void CookieMonster::SetCookieWithOptions(const GURL& url,
[email protected]f48b9432011-01-11 07:25:40724 const std::string& cookie_line,
rdsmithe5c701d2017-07-12 21:50:00725 const CookieOptions& options,
726 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:09727 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40728
729 if (!HasCookieableScheme(url)) {
rdsmithe5c701d2017-07-12 21:50:00730 MaybeRunCookieCallback(std::move(callback), false);
731 return;
[email protected]f48b9432011-01-11 07:25:40732 }
733
Oscar Johansson63e83cf2018-07-02 08:47:26734 VLOG(net::cookie_util::kVlogSetCookies)
735 << "SetCookie() line: " << cookie_line;
Maks Orlovicha61ed022018-03-01 18:24:24736
737 Time creation_time = CurrentTime();
738 last_time_seen_ = creation_time;
739
740 std::unique_ptr<CanonicalCookie> cc(
741 CanonicalCookie::Create(url, cookie_line, creation_time, options));
742
743 if (!cc.get()) {
Oscar Johansson63e83cf2018-07-02 08:47:26744 VLOG(net::cookie_util::kVlogSetCookies)
745 << "WARNING: Failed to allocate CanonicalCookie";
Maks Orlovicha61ed022018-03-01 18:24:24746 MaybeRunCookieCallback(std::move(callback), false);
747 return;
748 }
749 SetCanonicalCookie(std::move(cc), url.SchemeIsCryptographic(),
750 !options.exclude_httponly(), std::move(callback));
[email protected]f48b9432011-01-11 07:25:40751}
752
[email protected]f48b9432011-01-11 07:25:40753void CookieMonster::DeleteCookie(const GURL& url,
rdsmithe5c701d2017-07-12 21:50:00754 const std::string& cookie_name,
755 base::OnceClosure callback) {
mmenkebe0910d2016-03-01 19:09:09756 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40757
rdsmithe5c701d2017-07-12 21:50:00758 if (!HasCookieableScheme(url)) {
759 // TODO(rdsmith): Would be good to provide a failure indication here.
760 MaybeRunCookieCallback(std::move(callback));
[email protected]f48b9432011-01-11 07:25:40761 return;
rdsmithe5c701d2017-07-12 21:50:00762 }
[email protected]f48b9432011-01-11 07:25:40763
764 CookieOptions options;
765 options.set_include_httponly();
mkwstf71d0bd2016-03-21 14:15:24766 options.set_same_site_cookie_mode(
767 CookieOptions::SameSiteCookieMode::INCLUDE_STRICT_AND_LAX);
[email protected]f48b9432011-01-11 07:25:40768 // Get the cookies for this host and its domain(s).
769 std::vector<CanonicalCookie*> cookies;
mkwst72b65162016-02-22 19:58:54770 FindCookiesForHostAndDomain(url, options, &cookies);
[email protected]f48b9432011-01-11 07:25:40771 std::set<CanonicalCookie*> matching_cookies;
772
vmpstr6f21f242016-06-29 02:16:47773 for (auto* cookie : cookies) {
mmenke4379aeb2016-03-05 12:22:07774 if (cookie->Name() != cookie_name)
[email protected]f48b9432011-01-11 07:25:40775 continue;
mmenke4379aeb2016-03-05 12:22:07776 if (!cookie->IsOnPath(url.path()))
[email protected]f48b9432011-01-11 07:25:40777 continue;
mmenke4379aeb2016-03-05 12:22:07778 matching_cookies.insert(cookie);
[email protected]f48b9432011-01-11 07:25:40779 }
780
781 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
782 CookieMap::iterator curit = it;
783 ++it;
avie7cd11a2016-10-11 02:00:35784 if (matching_cookies.find(curit->second.get()) != matching_cookies.end()) {
Nick Harper7a6683a2018-01-30 20:42:52785 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPLICIT);
[email protected]f48b9432011-01-11 07:25:40786 }
787 }
rdsmithe5c701d2017-07-12 21:50:00788
Maks Orlovichf97d1b92018-03-06 17:25:39789 FlushStore(base::BindOnce(&MaybeRunDeleteCallback,
rdsmithe5c701d2017-07-12 21:50:00790 weak_ptr_factory_.GetWeakPtr(),
791 // No callback null check needed as BindOnce
792 // is not being called and MaybeRunDeleteCallback
793 // has its own check.
794 std::move(callback)));
[email protected]f48b9432011-01-11 07:25:40795}
796
rdsmithe5c701d2017-07-12 21:50:00797void CookieMonster::DeleteCanonicalCookie(const CanonicalCookie& cookie,
798 DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09799 DCHECK(thread_checker_.CalledOnValidThread());
mmenke24379d52016-02-05 23:50:17800
rdsmithe5c701d2017-07-12 21:50:00801 uint32_t result = 0u;
mmenke24379d52016-02-05 23:50:17802 for (CookieMapItPair its = cookies_.equal_range(GetKey(cookie.Domain()));
803 its.first != its.second; ++its.first) {
Maks Orlovich2896ec3f2018-04-06 13:34:27804 const std::unique_ptr<CanonicalCookie>& candidate = its.first->second;
805 // Historically, this has refused modification if the cookie has changed
806 // value in between the CanonicalCookie object was returned by a getter
807 // and when this ran. The later parts of the conditional (everything but
808 // the equivalence check) attempt to preserve this behavior.
809 if (candidate->IsEquivalent(cookie) &&
810 candidate->CreationDate() == cookie.CreationDate() &&
811 candidate->Value() == cookie.Value()) {
Nick Harper7a6683a2018-01-30 20:42:52812 InternalDeleteCookie(its.first, true, DELETE_COOKIE_EXPLICIT);
rdsmithe5c701d2017-07-12 21:50:00813 result = 1u;
814 break;
mmenke24379d52016-02-05 23:50:17815 }
816 }
rdsmithe5c701d2017-07-12 21:50:00817 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39818 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00819 callback ? base::BindOnce(std::move(callback), result)
820 : base::OnceClosure()));
mmenke24379d52016-02-05 23:50:17821}
822
rdsmithe5c701d2017-07-12 21:50:00823void CookieMonster::DeleteSessionCookies(DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09824 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]264807b2012-04-25 14:49:37825
rdsmitha5beda162017-07-08 13:55:42826 uint32_t num_deleted = 0;
[email protected]264807b2012-04-25 14:49:37827 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
828 CookieMap::iterator curit = it;
avie7cd11a2016-10-11 02:00:35829 CanonicalCookie* cc = curit->second.get();
[email protected]264807b2012-04-25 14:49:37830 ++it;
831
832 if (!cc->IsPersistent()) {
mkwstbe84af312015-02-20 08:52:45833 InternalDeleteCookie(curit, true, /*sync_to_store*/
[email protected]264807b2012-04-25 14:49:37834 DELETE_COOKIE_EXPIRED);
835 ++num_deleted;
836 }
837 }
838
rdsmithe5c701d2017-07-12 21:50:00839 FlushStore(
Maks Orlovichf97d1b92018-03-06 17:25:39840 base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
rdsmithe5c701d2017-07-12 21:50:00841 callback ? base::BindOnce(std::move(callback), num_deleted)
842 : base::OnceClosure()));
[email protected]264807b2012-04-25 14:49:37843}
844
erikchen1dd72a72015-05-06 20:45:05845void CookieMonster::MarkCookieStoreAsInitialized() {
mmenkebe0910d2016-03-01 19:09:09846 DCHECK(thread_checker_.CalledOnValidThread());
erikchen1dd72a72015-05-06 20:45:05847 initialized_ = true;
848}
849
850void CookieMonster::FetchAllCookiesIfNecessary() {
mmenkebe0910d2016-03-01 19:09:09851 DCHECK(thread_checker_.CalledOnValidThread());
erikchen1dd72a72015-05-06 20:45:05852 if (store_.get() && !started_fetching_all_cookies_) {
853 started_fetching_all_cookies_ = true;
854 FetchAllCookies();
855 }
856}
857
mmenke74bcbd52016-01-21 17:17:56858void CookieMonster::FetchAllCookies() {
mmenkebe0910d2016-03-01 19:09:09859 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56860 DCHECK(store_.get()) << "Store must exist to initialize";
861 DCHECK(!finished_fetching_all_cookies_)
862 << "All cookies have already been fetched.";
863
864 // We bind in the current time so that we can report the wall-clock time for
865 // loading cookies.
mmenkebe0910d2016-03-01 19:09:09866 store_->Load(base::Bind(&CookieMonster::OnLoaded,
Helen Li92a29f102018-08-15 23:02:26867 weak_ptr_factory_.GetWeakPtr(), TimeTicks::Now()),
868 net_log_);
mmenke74bcbd52016-01-21 17:17:56869}
870
avie7cd11a2016-10-11 02:00:35871void CookieMonster::OnLoaded(
872 TimeTicks beginning_time,
873 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:09874 DCHECK(thread_checker_.CalledOnValidThread());
avie7cd11a2016-10-11 02:00:35875 StoreLoadedCookies(std::move(cookies));
[email protected]c7593fb22011-11-14 23:54:27876 histogram_time_blocked_on_load_->AddTime(TimeTicks::Now() - beginning_time);
[email protected]218aa6a12011-09-13 17:38:38877
878 // Invoke the task queue of cookie request.
879 InvokeQueue();
880}
881
avie7cd11a2016-10-11 02:00:35882void CookieMonster::OnKeyLoaded(
883 const std::string& key,
884 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:09885 DCHECK(thread_checker_.CalledOnValidThread());
886
avie7cd11a2016-10-11 02:00:35887 StoreLoadedCookies(std::move(cookies));
[email protected]85620342011-10-17 17:35:04888
mmenkebe0910d2016-03-01 19:09:09889 auto tasks_pending_for_key = tasks_pending_for_key_.find(key);
[email protected]85620342011-10-17 17:35:04890
mmenkebe0910d2016-03-01 19:09:09891 // TODO(mmenke): Can this be turned into a DCHECK?
892 if (tasks_pending_for_key == tasks_pending_for_key_.end())
893 return;
[email protected]bab72ec2013-10-30 20:50:02894
mmenkebe0910d2016-03-01 19:09:09895 // Run all tasks for the key. Note that running a task can result in multiple
896 // tasks being added to the back of the deque.
897 while (!tasks_pending_for_key->second.empty()) {
rdsmithe5c701d2017-07-12 21:50:00898 base::OnceClosure task = std::move(tasks_pending_for_key->second.front());
mmenkebe0910d2016-03-01 19:09:09899 tasks_pending_for_key->second.pop_front();
rdsmithe5c701d2017-07-12 21:50:00900 std::move(task).Run();
[email protected]85620342011-10-17 17:35:04901 }
mmenkebe0910d2016-03-01 19:09:09902
903 tasks_pending_for_key_.erase(tasks_pending_for_key);
904
905 // This has to be done last, in case running a task queues a new task for the
906 // key, to ensure tasks are run in the correct order.
907 keys_loaded_.insert(key);
[email protected]85620342011-10-17 17:35:04908}
909
[email protected]218aa6a12011-09-13 17:38:38910void CookieMonster::StoreLoadedCookies(
avie7cd11a2016-10-11 02:00:35911 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:09912 DCHECK(thread_checker_.CalledOnValidThread());
913
mmenkebe0910d2016-03-01 19:09:09914 // Even if a key is expired, insert it so it can be garbage collected,
915 // removed, and sync'd.
[email protected]6210ce52013-09-20 03:33:14916 CookieItVector cookies_with_control_chars;
917
avie7cd11a2016-10-11 02:00:35918 for (auto& cookie : cookies) {
Maks Orlovich2b0d5b12018-04-10 19:33:47919 CanonicalCookie* cookie_ptr = cookie.get();
920 CookieMap::iterator inserted = InternalInsertCookie(
921 GetKey(cookie_ptr->Domain()), std::move(cookie), false);
922 const Time cookie_access_time(cookie_ptr->LastAccessDate());
923 if (earliest_access_time_.is_null() ||
Helen Lid84010b2018-08-22 16:27:44924 cookie_access_time < earliest_access_time_) {
Maks Orlovich2b0d5b12018-04-10 19:33:47925 earliest_access_time_ = cookie_access_time;
Helen Lid84010b2018-08-22 16:27:44926 }
[email protected]f48b9432011-01-11 07:25:40927
Maks Orlovich2b0d5b12018-04-10 19:33:47928 if (ContainsControlCharacter(cookie_ptr->Name()) ||
929 ContainsControlCharacter(cookie_ptr->Value())) {
930 cookies_with_control_chars.push_back(inserted);
[email protected]f48b9432011-01-11 07:25:40931 }
932 }
[email protected]f48b9432011-01-11 07:25:40933
[email protected]6210ce52013-09-20 03:33:14934 // Any cookies that contain control characters that we have loaded from the
935 // persistent store should be deleted. See http://crbug.com/238041.
936 for (CookieItVector::iterator it = cookies_with_control_chars.begin();
937 it != cookies_with_control_chars.end();) {
938 CookieItVector::iterator curit = it;
939 ++it;
940
941 InternalDeleteCookie(*curit, true, DELETE_COOKIE_CONTROL_CHAR);
942 }
943
[email protected]f48b9432011-01-11 07:25:40944 // After importing cookies from the PersistentCookieStore, verify that
945 // none of our other constraints are violated.
[email protected]f48b9432011-01-11 07:25:40946 // In particular, the backing store might have given us duplicate cookies.
[email protected]85620342011-10-17 17:35:04947
948 // This method could be called multiple times due to priority loading, thus
949 // cookies loaded in previous runs will be validated again, but this is OK
950 // since they are expected to be much fewer than total DB.
[email protected]f48b9432011-01-11 07:25:40951 EnsureCookiesMapIsValid();
[email protected]218aa6a12011-09-13 17:38:38952}
[email protected]f48b9432011-01-11 07:25:40953
[email protected]218aa6a12011-09-13 17:38:38954void CookieMonster::InvokeQueue() {
mmenkebe0910d2016-03-01 19:09:09955 DCHECK(thread_checker_.CalledOnValidThread());
956
mmenkef49fca0e2016-03-08 12:46:24957 // Move all per-key tasks into the global queue, if there are any. This is
958 // protection about a race where the store learns about all cookies loading
959 // before it learned about the cookies for a key loading.
960
961 // Needed to prevent any recursively queued tasks from going back into the
962 // per-key queues.
963 seen_global_task_ = true;
rdsmithe5c701d2017-07-12 21:50:00964 for (auto& tasks_for_key : tasks_pending_for_key_) {
965 tasks_pending_.insert(tasks_pending_.begin(),
966 std::make_move_iterator(tasks_for_key.second.begin()),
967 std::make_move_iterator(tasks_for_key.second.end()));
mmenkef49fca0e2016-03-08 12:46:24968 }
969 tasks_pending_for_key_.clear();
970
mmenkebe0910d2016-03-01 19:09:09971 while (!tasks_pending_.empty()) {
rdsmithe5c701d2017-07-12 21:50:00972 base::OnceClosure request_task = std::move(tasks_pending_.front());
mmenkef49fca0e2016-03-08 12:46:24973 tasks_pending_.pop_front();
rdsmithe5c701d2017-07-12 21:50:00974 std::move(request_task).Run();
[email protected]218aa6a12011-09-13 17:38:38975 }
mmenkebe0910d2016-03-01 19:09:09976
mmenkef49fca0e2016-03-08 12:46:24977 DCHECK(tasks_pending_for_key_.empty());
978
mmenkebe0910d2016-03-01 19:09:09979 finished_fetching_all_cookies_ = true;
mmenkebe0910d2016-03-01 19:09:09980 keys_loaded_.clear();
[email protected]f48b9432011-01-11 07:25:40981}
982
983void CookieMonster::EnsureCookiesMapIsValid() {
mmenkebe0910d2016-03-01 19:09:09984 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40985
[email protected]f48b9432011-01-11 07:25:40986 // Iterate through all the of the cookies, grouped by host.
987 CookieMap::iterator prev_range_end = cookies_.begin();
988 while (prev_range_end != cookies_.end()) {
989 CookieMap::iterator cur_range_begin = prev_range_end;
990 const std::string key = cur_range_begin->first; // Keep a copy.
991 CookieMap::iterator cur_range_end = cookies_.upper_bound(key);
992 prev_range_end = cur_range_end;
993
994 // Ensure no equivalent cookies for this host.
ellyjonescabf57422015-08-21 18:44:51995 TrimDuplicateCookiesForKey(key, cur_range_begin, cur_range_end);
[email protected]f48b9432011-01-11 07:25:40996 }
[email protected]f48b9432011-01-11 07:25:40997}
998
ellyjonescabf57422015-08-21 18:44:51999void CookieMonster::TrimDuplicateCookiesForKey(const std::string& key,
1000 CookieMap::iterator begin,
1001 CookieMap::iterator end) {
mmenkebe0910d2016-03-01 19:09:091002 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401003
1004 // Set of cookies ordered by creation time.
Maks Orlovich2b0d5b12018-04-10 19:33:471005 typedef std::multiset<CookieMap::iterator, OrderByCreationTimeDesc> CookieSet;
[email protected]f48b9432011-01-11 07:25:401006
1007 // Helper map we populate to find the duplicates.
1008 typedef std::map<CookieSignature, CookieSet> EquivalenceMap;
1009 EquivalenceMap equivalent_cookies;
1010
1011 // The number of duplicate cookies that have been found.
1012 int num_duplicates = 0;
1013
1014 // Iterate through all of the cookies in our range, and insert them into
1015 // the equivalence map.
1016 for (CookieMap::iterator it = begin; it != end; ++it) {
1017 DCHECK_EQ(key, it->first);
avie7cd11a2016-10-11 02:00:351018 CanonicalCookie* cookie = it->second.get();
[email protected]f48b9432011-01-11 07:25:401019
mkwstbe84af312015-02-20 08:52:451020 CookieSignature signature(cookie->Name(), cookie->Domain(), cookie->Path());
[email protected]f48b9432011-01-11 07:25:401021 CookieSet& set = equivalent_cookies[signature];
1022
1023 // We found a duplicate!
1024 if (!set.empty())
1025 num_duplicates++;
1026
1027 // We save the iterator into |cookies_| rather than the actual cookie
1028 // pointer, since we may need to delete it later.
Maks Orlovich2b0d5b12018-04-10 19:33:471029 set.insert(it);
[email protected]f48b9432011-01-11 07:25:401030 }
1031
1032 // If there were no duplicates, we are done!
1033 if (num_duplicates == 0)
ellyjonescabf57422015-08-21 18:44:511034 return;
[email protected]f48b9432011-01-11 07:25:401035
1036 // Make sure we find everything below that we did above.
1037 int num_duplicates_found = 0;
1038
1039 // Otherwise, delete all the duplicate cookies, both from our in-memory store
1040 // and from the backing store.
1041 for (EquivalenceMap::iterator it = equivalent_cookies.begin();
mkwstbe84af312015-02-20 08:52:451042 it != equivalent_cookies.end(); ++it) {
[email protected]f48b9432011-01-11 07:25:401043 const CookieSignature& signature = it->first;
1044 CookieSet& dupes = it->second;
1045
1046 if (dupes.size() <= 1)
1047 continue; // This cookiename/path has no duplicates.
1048 num_duplicates_found += dupes.size() - 1;
1049
Maks Orlovich2b0d5b12018-04-10 19:33:471050 // Since |dupes| is sorted by creation time (descending), the first cookie
1051 // is the most recent one (or tied for it), so we will keep it. The rest are
1052 // duplicates.
[email protected]f48b9432011-01-11 07:25:401053 dupes.erase(dupes.begin());
1054
1055 LOG(ERROR) << base::StringPrintf(
1056 "Found %d duplicate cookies for host='%s', "
1057 "with {name='%s', domain='%s', path='%s'}",
mkwstbe84af312015-02-20 08:52:451058 static_cast<int>(dupes.size()), key.c_str(), signature.name.c_str(),
1059 signature.domain.c_str(), signature.path.c_str());
[email protected]f48b9432011-01-11 07:25:401060
1061 // Remove all the cookies identified by |dupes|. It is valid to delete our
1062 // list of iterators one at a time, since |cookies_| is a multimap (they
1063 // don't invalidate existing iterators following deletion).
mkwstbe84af312015-02-20 08:52:451064 for (CookieSet::iterator dupes_it = dupes.begin(); dupes_it != dupes.end();
[email protected]f48b9432011-01-11 07:25:401065 ++dupes_it) {
[email protected]218aa6a12011-09-13 17:38:381066 InternalDeleteCookie(*dupes_it, true,
[email protected]f48b9432011-01-11 07:25:401067 DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE);
1068 }
1069 }
1070 DCHECK_EQ(num_duplicates, num_duplicates_found);
[email protected]f48b9432011-01-11 07:25:401071}
1072
[email protected]f48b9432011-01-11 07:25:401073void CookieMonster::FindCookiesForHostAndDomain(
1074 const GURL& url,
1075 const CookieOptions& options,
[email protected]f48b9432011-01-11 07:25:401076 std::vector<CanonicalCookie*>* cookies) {
mmenkebe0910d2016-03-01 19:09:091077 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401078
1079 const Time current_time(CurrentTime());
1080
1081 // Probe to save statistics relatively frequently. We do it here rather
1082 // than in the set path as many websites won't set cookies, and we
1083 // want to collect statistics whenever the browser's being used.
1084 RecordPeriodicStats(current_time);
1085
[email protected]8e1583672012-02-11 04:39:411086 // Can just dispatch to FindCookiesForKey
Maks Orlovich323efaf2018-03-06 02:56:391087 const std::string key(GetKey(url.host_piece()));
mkwst72b65162016-02-22 19:58:541088 FindCookiesForKey(key, url, options, current_time, cookies);
[email protected]f48b9432011-01-11 07:25:401089}
1090
[email protected]dedec0b2013-02-28 04:50:101091void CookieMonster::FindCookiesForKey(const std::string& key,
1092 const GURL& url,
1093 const CookieOptions& options,
1094 const Time& current,
[email protected]dedec0b2013-02-28 04:50:101095 std::vector<CanonicalCookie*>* cookies) {
mmenkebe0910d2016-03-01 19:09:091096 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401097
[email protected]f48b9432011-01-11 07:25:401098 for (CookieMapItPair its = cookies_.equal_range(key);
mkwstbe84af312015-02-20 08:52:451099 its.first != its.second;) {
[email protected]f48b9432011-01-11 07:25:401100 CookieMap::iterator curit = its.first;
avie7cd11a2016-10-11 02:00:351101 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:401102 ++its.first;
1103
1104 // If the cookie is expired, delete it.
mmenke3c79a652016-02-12 14:39:201105 if (cc->IsExpired(current)) {
[email protected]f48b9432011-01-11 07:25:401106 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
1107 continue;
1108 }
1109
[email protected]65f4e7e2012-12-12 21:56:541110 // Filter out cookies that should not be included for a request to the
1111 // given |url|. HTTP only cookies are filtered depending on the passed
1112 // cookie |options|.
1113 if (!cc->IncludeForRequestURL(url, options))
[email protected]f48b9432011-01-11 07:25:401114 continue;
1115
[email protected]65f4e7e2012-12-12 21:56:541116 // Add this cookie to the set of matching cookies. Update the access
[email protected]f48b9432011-01-11 07:25:401117 // time if we've been requested to do so.
mkwst72b65162016-02-22 19:58:541118 if (options.update_access_time()) {
[email protected]f48b9432011-01-11 07:25:401119 InternalUpdateCookieAccessTime(cc, current);
1120 }
1121 cookies->push_back(cc);
1122 }
1123}
1124
Mike Westc4a777b2017-10-06 14:04:201125bool CookieMonster::DeleteAnyEquivalentCookie(
1126 const std::string& key,
1127 const CanonicalCookie& ecc,
1128 bool source_secure,
1129 bool skip_httponly,
1130 bool already_expired,
1131 base::Time* creation_date_to_inherit) {
mmenkebe0910d2016-03-01 19:09:091132 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401133
1134 bool found_equivalent_cookie = false;
1135 bool skipped_httponly = false;
jww601411a2015-11-20 19:46:571136 bool skipped_secure_cookie = false;
jww31e32632015-12-16 23:38:341137
1138 histogram_cookie_delete_equivalent_->Add(COOKIE_DELETE_EQUIVALENT_ATTEMPT);
1139
[email protected]f48b9432011-01-11 07:25:401140 for (CookieMapItPair its = cookies_.equal_range(key);
mkwstbe84af312015-02-20 08:52:451141 its.first != its.second;) {
[email protected]f48b9432011-01-11 07:25:401142 CookieMap::iterator curit = its.first;
avie7cd11a2016-10-11 02:00:351143 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:401144 ++its.first;
1145
jwwa26e439d2017-01-27 18:17:271146 // If the cookie is being set from an insecure scheme, then if a cookie
1147 // already exists with the same name and it is Secure, then the cookie
1148 // should *not* be updated if they domain-match and ignoring the path
1149 // attribute.
jww601411a2015-11-20 19:46:571150 //
jwwa26e439d2017-01-27 18:17:271151 // See: https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone
rdsmith2709eee2017-06-20 22:43:271152 if (cc->IsSecure() && !source_secure &&
mmenke2830b0722016-07-20 16:02:501153 ecc.IsEquivalentForSecureCookieMatching(*cc)) {
jww601411a2015-11-20 19:46:571154 skipped_secure_cookie = true;
jww31e32632015-12-16 23:38:341155 histogram_cookie_delete_equivalent_->Add(
1156 COOKIE_DELETE_EQUIVALENT_SKIPPING_SECURE);
Helen Licd0fab862018-08-13 16:07:531157 net_log_.AddEvent(
1158 NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_SECURE,
1159 base::BindRepeating(&NetLogCookieMonsterCookieRejectedSecure, cc,
1160 &ecc));
jww31e32632015-12-16 23:38:341161 // If the cookie is equivalent to the new cookie and wouldn't have been
1162 // skipped for being HTTP-only, record that it is a skipped secure cookie
1163 // that would have been deleted otherwise.
1164 if (ecc.IsEquivalent(*cc)) {
jwwa9a0d482015-12-16 18:19:411165 found_equivalent_cookie = true;
jww31e32632015-12-16 23:38:341166
1167 if (!skip_httponly || !cc->IsHttpOnly()) {
1168 histogram_cookie_delete_equivalent_->Add(
1169 COOKIE_DELETE_EQUIVALENT_WOULD_HAVE_DELETED);
1170 }
1171 }
jww601411a2015-11-20 19:46:571172 } else if (ecc.IsEquivalent(*cc)) {
[email protected]f48b9432011-01-11 07:25:401173 // We should never have more than one equivalent cookie, since they should
jww601411a2015-11-20 19:46:571174 // overwrite each other, unless secure cookies require secure scheme is
1175 // being enforced. In that case, cookies with different paths might exist
1176 // and be considered equivalent.
mkwstbe84af312015-02-20 08:52:451177 CHECK(!found_equivalent_cookie)
1178 << "Duplicate equivalent cookies found, cookie store is corrupted.";
[email protected]f48b9432011-01-11 07:25:401179 if (skip_httponly && cc->IsHttpOnly()) {
1180 skipped_httponly = true;
Helen Licd0fab862018-08-13 16:07:531181 net_log_.AddEvent(
1182 NetLogEventType::COOKIE_STORE_COOKIE_REJECTED_HTTPONLY,
1183 base::BindRepeating(&NetLogCookieMonsterCookieRejectedHttponly, cc,
1184 &ecc));
[email protected]f48b9432011-01-11 07:25:401185 } else {
jww31e32632015-12-16 23:38:341186 histogram_cookie_delete_equivalent_->Add(
1187 COOKIE_DELETE_EQUIVALENT_FOUND);
Mike West86149882017-07-28 10:41:491188 if (cc->Value() == ecc.Value()) {
Mike Westc4a777b2017-10-06 14:04:201189 *creation_date_to_inherit = cc->CreationDate();
Mike West86149882017-07-28 10:41:491190 histogram_cookie_delete_equivalent_->Add(
1191 COOKIE_DELETE_EQUIVALENT_FOUND_WITH_SAME_VALUE);
1192 }
mkwstbe84af312015-02-20 08:52:451193 InternalDeleteCookie(curit, true, already_expired
1194 ? DELETE_COOKIE_EXPIRED_OVERWRITE
1195 : DELETE_COOKIE_OVERWRITE);
[email protected]f48b9432011-01-11 07:25:401196 }
1197 found_equivalent_cookie = true;
1198 }
1199 }
jww601411a2015-11-20 19:46:571200 return skipped_httponly || skipped_secure_cookie;
[email protected]f48b9432011-01-11 07:25:401201}
1202
[email protected]6210ce52013-09-20 03:33:141203CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie(
1204 const std::string& key,
avie7cd11a2016-10-11 02:00:351205 std::unique_ptr<CanonicalCookie> cc,
[email protected]6210ce52013-09-20 03:33:141206 bool sync_to_store) {
mmenkebe0910d2016-03-01 19:09:091207 DCHECK(thread_checker_.CalledOnValidThread());
avie7cd11a2016-10-11 02:00:351208 CanonicalCookie* cc_ptr = cc.get();
mmenkebe0910d2016-03-01 19:09:091209
Helen Licd0fab862018-08-13 16:07:531210 net_log_.AddEvent(NetLogEventType::COOKIE_STORE_COOKIE_ADDED,
1211 base::BindRepeating(&NetLogCookieMonsterCookieAdded,
1212 cc.get(), sync_to_store));
avie7cd11a2016-10-11 02:00:351213 if ((cc_ptr->IsPersistent() || persist_session_cookies_) && store_.get() &&
Helen Lid84010b2018-08-22 16:27:441214 sync_to_store) {
avie7cd11a2016-10-11 02:00:351215 store_->AddCookie(*cc_ptr);
Helen Lid84010b2018-08-22 16:27:441216 }
[email protected]6210ce52013-09-20 03:33:141217 CookieMap::iterator inserted =
avie7cd11a2016-10-11 02:00:351218 cookies_.insert(CookieMap::value_type(key, std::move(cc)));
mkwstc1aa4cc2015-04-03 19:57:451219
1220 // See InitializeHistograms() for details.
avie7cd11a2016-10-11 02:00:351221 int32_t type_sample = cc_ptr->SameSite() != CookieSameSite::NO_RESTRICTION
mkwste1a29582016-03-15 10:07:521222 ? 1 << COOKIE_TYPE_SAME_SITE
1223 : 0;
avie7cd11a2016-10-11 02:00:351224 type_sample |= cc_ptr->IsHttpOnly() ? 1 << COOKIE_TYPE_HTTPONLY : 0;
1225 type_sample |= cc_ptr->IsSecure() ? 1 << COOKIE_TYPE_SECURE : 0;
mkwst46549412016-02-01 10:05:371226 histogram_cookie_type_->Add(type_sample);
estark7feb65c2b2015-08-21 23:38:201227
Victor Costan14f47c12018-03-01 08:02:241228 change_dispatcher_.DispatchChange(*cc_ptr, CookieChangeCause::INSERTED, true);
[email protected]6210ce52013-09-20 03:33:141229
1230 return inserted;
[email protected]f48b9432011-01-11 07:25:401231}
1232
rdsmithe5c701d2017-07-12 21:50:001233void CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc,
rdsmith2709eee2017-06-20 22:43:271234 bool secure_source,
rdsmithe5c701d2017-07-12 21:50:001235 bool modify_http_only,
1236 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:091237 DCHECK(thread_checker_.CalledOnValidThread());
1238
Randy Smith10400072017-08-03 04:08:311239 if ((cc->IsSecure() && !secure_source) ||
1240 (cc->IsHttpOnly() && !modify_http_only)) {
rdsmithe5c701d2017-07-12 21:50:001241 MaybeRunCookieCallback(std::move(callback), false);
1242 return;
1243 }
rdsmith2709eee2017-06-20 22:43:271244
mmenkeea4cd402016-02-02 04:03:101245 const std::string key(GetKey(cc->Domain()));
rdsmitha6ce4442017-06-21 17:11:051246
1247 // TODO(mmenke): This class assumes each cookie to have a unique creation
1248 // time. Allowing the caller to set the creation time violates that
1249 // assumption. Worth fixing? Worth noting that time changes between browser
1250 // restarts can cause the same issue.
1251 base::Time creation_date = cc->CreationDate();
1252 if (creation_date.is_null()) {
1253 creation_date = CurrentTime();
1254 cc->SetCreationDate(creation_date);
1255 last_time_seen_ = creation_date;
1256 }
1257 bool already_expired = cc->IsExpired(creation_date);
ellyjones399e35a22014-10-27 11:09:561258
Mike Westc4a777b2017-10-06 14:04:201259 base::Time creation_date_to_inherit;
rdsmith2709eee2017-06-20 22:43:271260 if (DeleteAnyEquivalentCookie(key, *cc, secure_source, !modify_http_only,
Mike Westc4a777b2017-10-06 14:04:201261 already_expired, &creation_date_to_inherit)) {
jww601411a2015-11-20 19:46:571262 std::string error;
jwwa26e439d2017-01-27 18:17:271263 error =
1264 "SetCookie() not clobbering httponly cookie or secure cookie for "
1265 "insecure scheme";
jww601411a2015-11-20 19:46:571266
Oscar Johansson63e83cf2018-07-02 08:47:261267 VLOG(net::cookie_util::kVlogSetCookies) << error;
rdsmithe5c701d2017-07-12 21:50:001268 MaybeRunCookieCallback(std::move(callback), false);
1269 return;
[email protected]3a96c742008-11-19 19:46:271270 }
initial.commit586acc5fe2008-07-26 22:42:521271
Oscar Johansson63e83cf2018-07-02 08:47:261272 VLOG(net::cookie_util::kVlogSetCookies)
1273 << "SetCookie() key: " << key << " cc: " << cc->DebugString();
initial.commit586acc5fe2008-07-26 22:42:521274
1275 // Realize that we might be setting an expired cookie, and the only point
1276 // was to delete the cookie which we've already done.
mmenke3c79a652016-02-12 14:39:201277 if (!already_expired) {
[email protected]374f58b2010-07-20 15:29:261278 // See InitializeHistograms() for details.
mmenkeea4cd402016-02-02 04:03:101279 if (cc->IsPersistent()) {
[email protected]8475bee2011-03-17 18:40:241280 histogram_expiration_duration_minutes_->Add(
rdsmitha6ce4442017-06-21 17:11:051281 (cc->ExpiryDate() - creation_date).InMinutes());
[email protected]8475bee2011-03-17 18:40:241282 }
1283
rdsmith2709eee2017-06-20 22:43:271284 // Histogram the type of scheme used on URLs that set cookies. This
1285 // intentionally includes cookies that are set or overwritten by
1286 // http:// URLs, but not cookies that are cleared by http:// URLs, to
1287 // understand if the former behavior can be deprecated for Secure
1288 // cookies.
1289 CookieSource cookie_source_sample =
1290 (secure_source
1291 ? (cc->IsSecure()
1292 ? COOKIE_SOURCE_SECURE_COOKIE_CRYPTOGRAPHIC_SCHEME
1293 : COOKIE_SOURCE_NONSECURE_COOKIE_CRYPTOGRAPHIC_SCHEME)
1294 : (cc->IsSecure()
1295 ? COOKIE_SOURCE_SECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME
1296 : COOKIE_SOURCE_NONSECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME));
1297 histogram_cookie_source_scheme_->Add(cookie_source_sample);
1298
Mike Westc4a777b2017-10-06 14:04:201299 if (!creation_date_to_inherit.is_null()) {
1300 cc->SetCreationDate(creation_date_to_inherit);
1301 // |last_time_seen_| is intentionally not updated, as moving it into the
1302 // past might cause duplicate cookie creation dates. See
1303 // `CookieMonster::CurrentTime()` for details.
1304 }
1305
rdsmith2709eee2017-06-20 22:43:271306 InternalInsertCookie(key, std::move(cc), true);
[email protected]348dd662013-03-13 20:25:071307 } else {
Oscar Johansson63e83cf2018-07-02 08:47:261308 VLOG(net::cookie_util::kVlogSetCookies)
1309 << "SetCookie() not storing already expired cookie.";
[email protected]c4058fb2010-06-22 17:25:261310 }
initial.commit586acc5fe2008-07-26 22:42:521311
1312 // We assume that hopefully setting a cookie will be less common than
1313 // querying a cookie. Since setting a cookie can put us over our limits,
1314 // make sure that we garbage collect... We can also make the assumption that
1315 // if a cookie was set, in the common case it will be used soon after,
1316 // and we will purge the expired cookies in GetCookies().
rdsmitha6ce4442017-06-21 17:11:051317 GarbageCollect(creation_date, key);
initial.commit586acc5fe2008-07-26 22:42:521318
rdsmithe5c701d2017-07-12 21:50:001319 MaybeRunCookieCallback(std::move(callback), true);
initial.commit586acc5fe2008-07-26 22:42:521320}
1321
rdsmithe5c701d2017-07-12 21:50:001322void CookieMonster::SetAllCookies(CookieList list,
1323 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:091324 DCHECK(thread_checker_.CalledOnValidThread());
rdsmithe5c701d2017-07-12 21:50:001325
rdsmith0e84cea2017-07-13 03:09:531326 // Nuke the existing store.
1327 while (!cookies_.empty()) {
1328 // TODO(rdsmith): The CANONICAL is a lie.
Nick Harper7a6683a2018-01-30 20:42:521329 InternalDeleteCookie(cookies_.begin(), true, DELETE_COOKIE_EXPLICIT);
rdsmithe5c701d2017-07-12 21:50:001330 }
1331
rdsmith0e84cea2017-07-13 03:09:531332 // Set all passed in cookies.
mmenkeea4cd402016-02-02 04:03:101333 for (const auto& cookie : list) {
rdsmith2709eee2017-06-20 22:43:271334 const std::string key(GetKey(cookie.Domain()));
1335 Time creation_time = cookie.CreationDate();
rdsmith0e84cea2017-07-13 03:09:531336 if (cookie.IsExpired(creation_time))
rdsmith2709eee2017-06-20 22:43:271337 continue;
1338
1339 if (cookie.IsPersistent()) {
1340 histogram_expiration_duration_minutes_->Add(
1341 (cookie.ExpiryDate() - creation_time).InMinutes());
mmenkeea4cd402016-02-02 04:03:101342 }
rdsmith2709eee2017-06-20 22:43:271343
Jeremy Roman0579ed62017-08-29 15:56:191344 InternalInsertCookie(key, std::make_unique<CanonicalCookie>(cookie), true);
rdsmith2709eee2017-06-20 22:43:271345 GarbageCollect(creation_time, key);
drogerd5d1278c2015-03-17 19:21:511346 }
1347
rdsmith2709eee2017-06-20 22:43:271348 // TODO(rdsmith): If this function always returns the same value, it
1349 // shouldn't have a return value. But it should also be deleted (see
1350 // https://codereview.chromium.org/2882063002/#msg64), which would
1351 // solve the return value problem.
rdsmithe5c701d2017-07-12 21:50:001352 MaybeRunCookieCallback(std::move(callback), true);
drogerd5d1278c2015-03-17 19:21:511353}
1354
[email protected]7a964a72010-09-07 19:33:261355void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc,
1356 const Time& current) {
mmenkebe0910d2016-03-01 19:09:091357 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041358
[email protected]77e0a462008-11-01 00:43:351359 // Based off the Mozilla code. When a cookie has been accessed recently,
1360 // don't bother updating its access time again. This reduces the number of
1361 // updates we do during pageload, which in turn reduces the chance our storage
1362 // backend will hit its batch thresholds and be forced to update.
[email protected]77e0a462008-11-01 00:43:351363 if ((current - cc->LastAccessDate()) < last_access_threshold_)
1364 return;
1365
1366 cc->SetLastAccessDate(current);
[email protected]90499482013-06-01 00:39:501367 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get())
[email protected]77e0a462008-11-01 00:43:351368 store_->UpdateCookieAccessTime(*cc);
1369}
1370
[email protected]6210ce52013-09-20 03:33:141371// InternalDeleteCookies must not invalidate iterators other than the one being
1372// deleted.
initial.commit586acc5fe2008-07-26 22:42:521373void CookieMonster::InternalDeleteCookie(CookieMap::iterator it,
[email protected]c4058fb2010-06-22 17:25:261374 bool sync_to_store,
1375 DeletionCause deletion_cause) {
mmenkebe0910d2016-03-01 19:09:091376 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041377
nharper352933e2016-09-30 18:24:571378 // Ideally, this would be asserted up where we define kChangeCauseMapping,
[email protected]8bb846f2011-03-23 12:08:181379 // but DeletionCause's visibility (or lack thereof) forces us to make
1380 // this check here.
Ryan Sleevi435a3a22018-05-15 02:16:071381 static_assert(base::size(kChangeCauseMapping) == DELETE_COOKIE_LAST_ENTRY + 1,
nharper352933e2016-09-30 18:24:571382 "kChangeCauseMapping size should match DeletionCause size");
[email protected]8bb846f2011-03-23 12:08:181383
avie7cd11a2016-10-11 02:00:351384 CanonicalCookie* cc = it->second.get();
Oscar Johansson63e83cf2018-07-02 08:47:261385 VLOG(net::cookie_util::kVlogSetCookies)
1386 << "InternalDeleteCookie()"
1387 << ", cause:" << deletion_cause << ", cc: " << cc->DebugString();
[email protected]7a964a72010-09-07 19:33:261388
Helen Licd0fab862018-08-13 16:07:531389 ChangeCausePair mapping = kChangeCauseMapping[deletion_cause];
1390 if (deletion_cause != DELETE_COOKIE_DONT_RECORD) {
1391 net_log_.AddEvent(NetLogEventType::COOKIE_STORE_COOKIE_DELETED,
1392 base::BindRepeating(&NetLogCookieMonsterCookieDeleted, cc,
1393 mapping.cause, sync_to_store));
1394 }
1395
[email protected]90499482013-06-01 00:39:501396 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get() &&
Helen Lid84010b2018-08-22 16:27:441397 sync_to_store) {
initial.commit586acc5fe2008-07-26 22:42:521398 store_->DeleteCookie(*cc);
Helen Lid84010b2018-08-22 16:27:441399 }
Victor Costan14f47c12018-03-01 08:02:241400 change_dispatcher_.DispatchChange(*cc, mapping.cause, mapping.notify);
initial.commit586acc5fe2008-07-26 22:42:521401 cookies_.erase(it);
initial.commit586acc5fe2008-07-26 22:42:521402}
1403
[email protected]8807b322010-10-01 17:10:141404// Domain expiry behavior is unchanged by key/expiry scheme (the
[email protected]8ad5d462013-05-02 08:45:261405// meaning of the key is different, but that's not visible to this routine).
jww82d99c12015-11-25 18:39:531406size_t CookieMonster::GarbageCollect(const Time& current,
jwwa26e439d2017-01-27 18:17:271407 const std::string& key) {
mmenkebe0910d2016-03-01 19:09:091408 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041409
jww82d99c12015-11-25 18:39:531410 size_t num_deleted = 0;
mkwstbe84af312015-02-20 08:52:451411 Time safe_date(Time::Now() - TimeDelta::FromDays(kSafeFromGlobalPurgeDays));
initial.commit586acc5fe2008-07-26 22:42:521412
[email protected]8ad5d462013-05-02 08:45:261413 // Collect garbage for this key, minding cookie priorities.
[email protected]7a964a72010-09-07 19:33:261414 if (cookies_.count(key) > kDomainMaxCookies) {
Oscar Johansson63e83cf2018-07-02 08:47:261415 VLOG(net::cookie_util::kVlogGarbageCollection)
1416 << "GarbageCollect() key: " << key;
[email protected]7a964a72010-09-07 19:33:261417
mkwst87734352016-03-03 17:36:231418 CookieItVector* cookie_its;
jww601411a2015-11-20 19:46:571419
mkwst87734352016-03-03 17:36:231420 CookieItVector non_expired_cookie_its;
1421 cookie_its = &non_expired_cookie_its;
jww82d99c12015-11-25 18:39:531422 num_deleted +=
mkwst87734352016-03-03 17:36:231423 GarbageCollectExpired(current, cookies_.equal_range(key), cookie_its);
jww82d99c12015-11-25 18:39:531424
mkwst87734352016-03-03 17:36:231425 if (cookie_its->size() > kDomainMaxCookies) {
Oscar Johansson63e83cf2018-07-02 08:47:261426 VLOG(net::cookie_util::kVlogGarbageCollection)
1427 << "Deep Garbage Collect domain.";
[email protected]8ad5d462013-05-02 08:45:261428 size_t purge_goal =
mkwst87734352016-03-03 17:36:231429 cookie_its->size() - (kDomainMaxCookies - kDomainPurgeCookies);
[email protected]8ad5d462013-05-02 08:45:261430 DCHECK(purge_goal > kDomainPurgeCookies);
1431
mkwste079ac412016-03-11 09:04:061432 // Sort the cookies by access date, from least-recent to most-recent.
1433 std::sort(cookie_its->begin(), cookie_its->end(), LRACookieSorter);
[email protected]8ad5d462013-05-02 08:45:261434
mkwste079ac412016-03-11 09:04:061435 // Remove all but the kDomainCookiesQuotaLow most-recently accessed
1436 // cookies with low-priority. Then, if cookies still need to be removed,
1437 // bump the quota and remove low- and medium-priority. Then, if cookies
1438 // _still_ need to be removed, bump the quota and remove cookies with
1439 // any priority.
jwwc00ac712016-05-05 22:21:441440 //
1441 // 1. Low-priority non-secure cookies.
1442 // 2. Low-priority secure cookies.
1443 // 3. Medium-priority non-secure cookies.
1444 // 4. High-priority non-secure cookies.
1445 // 5. Medium-priority secure cookies.
1446 // 6. High-priority secure cookies.
1447 const static struct {
1448 CookiePriority priority;
1449 bool protect_secure_cookies;
1450 } purge_rounds[] = {
1451 // 1. Low-priority non-secure cookies.
1452 {COOKIE_PRIORITY_LOW, true},
1453 // 2. Low-priority secure cookies.
1454 {COOKIE_PRIORITY_LOW, false},
1455 // 3. Medium-priority non-secure cookies.
1456 {COOKIE_PRIORITY_MEDIUM, true},
1457 // 4. High-priority non-secure cookies.
1458 {COOKIE_PRIORITY_HIGH, true},
1459 // 5. Medium-priority secure cookies.
1460 {COOKIE_PRIORITY_MEDIUM, false},
1461 // 6. High-priority secure cookies.
1462 {COOKIE_PRIORITY_HIGH, false},
1463 };
1464
mkwste079ac412016-03-11 09:04:061465 size_t quota = 0;
jwwc00ac712016-05-05 22:21:441466 for (const auto& purge_round : purge_rounds) {
mmenke645ca6772016-06-17 18:46:431467 // Adjust quota according to the priority of cookies. Each round should
1468 // protect certain number of cookies in order to avoid starvation.
1469 // For example, when each round starts to remove cookies, the number of
1470 // cookies of that priority are counted and a decision whether they
1471 // should be deleted or not is made. If yes, some number of cookies of
1472 // that priority are deleted considering the quota.
jwwc00ac712016-05-05 22:21:441473 switch (purge_round.priority) {
1474 case COOKIE_PRIORITY_LOW:
mmenke645ca6772016-06-17 18:46:431475 quota = kDomainCookiesQuotaLow;
jwwc00ac712016-05-05 22:21:441476 break;
1477 case COOKIE_PRIORITY_MEDIUM:
mmenke645ca6772016-06-17 18:46:431478 quota = kDomainCookiesQuotaMedium;
jwwc00ac712016-05-05 22:21:441479 break;
1480 case COOKIE_PRIORITY_HIGH:
mmenke645ca6772016-06-17 18:46:431481 quota = kDomainCookiesQuotaHigh;
jwwc00ac712016-05-05 22:21:441482 break;
1483 }
jwwc00ac712016-05-05 22:21:441484 size_t just_deleted = 0u;
jwwa26e439d2017-01-27 18:17:271485 // Purge up to |purge_goal| for all cookies at the given priority. This
1486 // path will be taken only if the initial non-secure purge did not evict
1487 // enough cookies.
jwwc00ac712016-05-05 22:21:441488 if (purge_goal > 0) {
1489 just_deleted = PurgeLeastRecentMatches(
1490 cookie_its, purge_round.priority, quota, purge_goal,
1491 purge_round.protect_secure_cookies);
1492 DCHECK_LE(just_deleted, purge_goal);
1493 purge_goal -= just_deleted;
1494 num_deleted += just_deleted;
1495 }
mkwst162d2712016-02-18 18:21:291496 }
mkwste079ac412016-03-11 09:04:061497
jwwc00ac712016-05-05 22:21:441498 DCHECK_EQ(0u, purge_goal);
[email protected]8807b322010-10-01 17:10:141499 }
initial.commit586acc5fe2008-07-26 22:42:521500 }
1501
[email protected]8ad5d462013-05-02 08:45:261502 // Collect garbage for everything. With firefox style we want to preserve
1503 // cookies accessed in kSafeFromGlobalPurgeDays, otherwise evict.
mkwstbe84af312015-02-20 08:52:451504 if (cookies_.size() > kMaxCookies && earliest_access_time_ < safe_date) {
Oscar Johansson63e83cf2018-07-02 08:47:261505 VLOG(net::cookie_util::kVlogGarbageCollection)
1506 << "GarbageCollect() everything";
[email protected]8ad5d462013-05-02 08:45:261507 CookieItVector cookie_its;
jww82d99c12015-11-25 18:39:531508
[email protected]7a964a72010-09-07 19:33:261509 num_deleted += GarbageCollectExpired(
1510 current, CookieMapItPair(cookies_.begin(), cookies_.end()),
1511 &cookie_its);
jww82d99c12015-11-25 18:39:531512
[email protected]8ad5d462013-05-02 08:45:261513 if (cookie_its.size() > kMaxCookies) {
Oscar Johansson63e83cf2018-07-02 08:47:261514 VLOG(net::cookie_util::kVlogGarbageCollection)
1515 << "Deep Garbage Collect everything.";
[email protected]8ad5d462013-05-02 08:45:261516 size_t purge_goal = cookie_its.size() - (kMaxCookies - kPurgeCookies);
1517 DCHECK(purge_goal > kPurgeCookies);
jww82d99c12015-11-25 18:39:531518
jwwa26e439d2017-01-27 18:17:271519 CookieItVector secure_cookie_its;
1520 CookieItVector non_secure_cookie_its;
1521 SplitCookieVectorIntoSecureAndNonSecure(cookie_its, &secure_cookie_its,
1522 &non_secure_cookie_its);
1523 size_t non_secure_purge_goal =
mmenkef4721d992017-06-07 17:13:591524 std::min<size_t>(purge_goal, non_secure_cookie_its.size());
jww82d99c12015-11-25 18:39:531525
mmenkef4721d992017-06-07 17:13:591526 base::Time earliest_non_secure_access_time;
jwwa26e439d2017-01-27 18:17:271527 size_t just_deleted = GarbageCollectLeastRecentlyAccessed(
mmenkef4721d992017-06-07 17:13:591528 current, safe_date, non_secure_purge_goal, non_secure_cookie_its,
1529 &earliest_non_secure_access_time);
jwwa26e439d2017-01-27 18:17:271530 num_deleted += just_deleted;
jww82d99c12015-11-25 18:39:531531
mmenkef4721d992017-06-07 17:13:591532 if (secure_cookie_its.size() == 0) {
1533 // This case is unlikely, but should still update
1534 // |earliest_access_time_| if only have non-secure cookies.
1535 earliest_access_time_ = earliest_non_secure_access_time;
1536 // Garbage collection can't delete all cookies.
1537 DCHECK(!earliest_access_time_.is_null());
1538 } else if (just_deleted < purge_goal) {
1539 size_t secure_purge_goal = std::min<size_t>(purge_goal - just_deleted,
1540 secure_cookie_its.size());
1541 base::Time earliest_secure_access_time;
jww82d99c12015-11-25 18:39:531542 num_deleted += GarbageCollectLeastRecentlyAccessed(
mmenkef4721d992017-06-07 17:13:591543 current, safe_date, secure_purge_goal, secure_cookie_its,
1544 &earliest_secure_access_time);
1545
1546 if (!earliest_non_secure_access_time.is_null() &&
1547 earliest_non_secure_access_time < earliest_secure_access_time) {
1548 earliest_access_time_ = earliest_non_secure_access_time;
1549 } else {
1550 earliest_access_time_ = earliest_secure_access_time;
1551 }
1552
1553 // Garbage collection can't delete all cookies.
1554 DCHECK(!earliest_access_time_.is_null());
jww82d99c12015-11-25 18:39:531555 }
mmenkef4721d992017-06-07 17:13:591556
1557 // If there are secure cookies, but deleting non-secure cookies was enough
1558 // to meet the purge goal, secure cookies are never examined, so
1559 // |earliest_access_time_| can't be determined. Leaving it alone will mean
1560 // it's no later than the real earliest last access time, so this won't
1561 // lead to any problems.
[email protected]8807b322010-10-01 17:10:141562 }
[email protected]c890ed192008-10-30 23:45:531563 }
1564
1565 return num_deleted;
1566}
1567
mkwste079ac412016-03-11 09:04:061568size_t CookieMonster::PurgeLeastRecentMatches(CookieItVector* cookies,
1569 CookiePriority priority,
1570 size_t to_protect,
jwwc00ac712016-05-05 22:21:441571 size_t purge_goal,
1572 bool protect_secure_cookies) {
mkwste079ac412016-03-11 09:04:061573 DCHECK(thread_checker_.CalledOnValidThread());
1574
mmenke645ca6772016-06-17 18:46:431575 // 1. Count number of the cookies at |priority|
1576 size_t cookies_count_possibly_to_be_deleted = CountCookiesForPossibleDeletion(
1577 priority, cookies, false /* count all cookies */);
1578
1579 // 2. If |cookies_count_possibly_to_be_deleted| at |priority| is less than or
1580 // equal |to_protect|, skip round in order to preserve the quota. This
1581 // involves secure and non-secure cookies at |priority|.
1582 if (cookies_count_possibly_to_be_deleted <= to_protect)
1583 return 0u;
1584
1585 // 3. Calculate number of secure cookies at |priority|
1586 // and number of cookies at |priority| that can possibly be deleted.
1587 // It is guaranteed we do not delete more than |purge_goal| even if
1588 // |cookies_count_possibly_to_be_deleted| is higher.
1589 size_t secure_cookies = 0u;
jwwc00ac712016-05-05 22:21:441590 if (protect_secure_cookies) {
mmenke645ca6772016-06-17 18:46:431591 secure_cookies = CountCookiesForPossibleDeletion(
1592 priority, cookies, protect_secure_cookies /* count secure cookies */);
1593 cookies_count_possibly_to_be_deleted -=
1594 std::max(secure_cookies, to_protect - secure_cookies);
1595 } else {
1596 cookies_count_possibly_to_be_deleted -= to_protect;
jwwc00ac712016-05-05 22:21:441597 }
1598
mmenke645ca6772016-06-17 18:46:431599 size_t removed = 0u;
1600 size_t current = 0u;
1601 while ((removed < purge_goal && current < cookies->size()) &&
1602 cookies_count_possibly_to_be_deleted > 0) {
avie7cd11a2016-10-11 02:00:351603 const CanonicalCookie* current_cookie = cookies->at(current)->second.get();
mmenke645ca6772016-06-17 18:46:431604 // Only delete the current cookie if the priority is equal to
1605 // the current level.
jwwc00ac712016-05-05 22:21:441606 if (IsCookieEligibleForEviction(priority, protect_secure_cookies,
1607 current_cookie)) {
mkwstaa07ee82016-03-11 15:32:141608 InternalDeleteCookie(cookies->at(current), true,
1609 DELETE_COOKIE_EVICTED_DOMAIN);
mkwste079ac412016-03-11 09:04:061610 cookies->erase(cookies->begin() + current);
1611 removed++;
mmenke645ca6772016-06-17 18:46:431612 cookies_count_possibly_to_be_deleted--;
mkwste079ac412016-03-11 09:04:061613 } else {
1614 current++;
1615 }
1616 }
1617 return removed;
1618}
1619
jww82d99c12015-11-25 18:39:531620size_t CookieMonster::GarbageCollectExpired(const Time& current,
1621 const CookieMapItPair& itpair,
1622 CookieItVector* cookie_its) {
mmenkebe0910d2016-03-01 19:09:091623 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041624
[email protected]c890ed192008-10-30 23:45:531625 int num_deleted = 0;
1626 for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) {
1627 CookieMap::iterator curit = it;
1628 ++it;
1629
1630 if (curit->second->IsExpired(current)) {
[email protected]2f3f3592010-07-07 20:11:511631 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
[email protected]c890ed192008-10-30 23:45:531632 ++num_deleted;
1633 } else if (cookie_its) {
1634 cookie_its->push_back(curit);
1635 }
initial.commit586acc5fe2008-07-26 22:42:521636 }
1637
1638 return num_deleted;
1639}
1640
jww82d99c12015-11-25 18:39:531641size_t CookieMonster::GarbageCollectDeleteRange(
1642 const Time& current,
1643 DeletionCause cause,
1644 CookieItVector::iterator it_begin,
1645 CookieItVector::iterator it_end) {
mmenkebe0910d2016-03-01 19:09:091646 DCHECK(thread_checker_.CalledOnValidThread());
1647
[email protected]8ad5d462013-05-02 08:45:261648 for (CookieItVector::iterator it = it_begin; it != it_end; it++) {
[email protected]8ad5d462013-05-02 08:45:261649 InternalDeleteCookie((*it), true, cause);
[email protected]c10da4b02010-03-25 14:38:321650 }
[email protected]8ad5d462013-05-02 08:45:261651 return it_end - it_begin;
[email protected]c10da4b02010-03-25 14:38:321652}
1653
mmenke74bcbd52016-01-21 17:17:561654size_t CookieMonster::GarbageCollectLeastRecentlyAccessed(
1655 const base::Time& current,
1656 const base::Time& safe_date,
1657 size_t purge_goal,
mmenkef4721d992017-06-07 17:13:591658 CookieItVector cookie_its,
1659 base::Time* earliest_time) {
1660 DCHECK_LE(purge_goal, cookie_its.size());
mmenkebe0910d2016-03-01 19:09:091661 DCHECK(thread_checker_.CalledOnValidThread());
1662
mmenkef4721d992017-06-07 17:13:591663 // Sorts up to *and including* |cookie_its[purge_goal]| (if it exists), so
1664 // |earliest_time| will be properly assigned even if
mmenke74bcbd52016-01-21 17:17:561665 // |global_purge_it| == |cookie_its.begin() + purge_goal|.
mmenkef4721d992017-06-07 17:13:591666 SortLeastRecentlyAccessed(
1667 cookie_its.begin(), cookie_its.end(),
1668 cookie_its.size() < purge_goal ? purge_goal + 1 : purge_goal);
mmenke74bcbd52016-01-21 17:17:561669 // Find boundary to cookies older than safe_date.
1670 CookieItVector::iterator global_purge_it = LowerBoundAccessDate(
1671 cookie_its.begin(), cookie_its.begin() + purge_goal, safe_date);
jwwa26e439d2017-01-27 18:17:271672 // Only delete the old cookies and delete non-secure ones first.
mmenke74bcbd52016-01-21 17:17:561673 size_t num_deleted =
1674 GarbageCollectDeleteRange(current, DELETE_COOKIE_EVICTED_GLOBAL,
1675 cookie_its.begin(), global_purge_it);
mmenkef4721d992017-06-07 17:13:591676 if (global_purge_it != cookie_its.end())
1677 *earliest_time = (*global_purge_it)->second->LastAccessDate();
mmenke74bcbd52016-01-21 17:17:561678 return num_deleted;
1679}
1680
[email protected]ed32c212013-05-14 20:49:291681// A wrapper around registry_controlled_domains::GetDomainAndRegistry
Maks Orlovich323efaf2018-03-06 02:56:391682// to make clear we're creating a key for our local map or for the persistent
1683// store's use. Here and in FindCookiesForHostAndDomain() are the only two
1684// places where we need to conditionalize based on key type.
[email protected]f48b9432011-01-11 07:25:401685//
1686// Note that this key algorithm explicitly ignores the scheme. This is
1687// because when we're entering cookies into the map from the backing store,
1688// we in general won't have the scheme at that point.
1689// In practical terms, this means that file cookies will be stored
1690// in the map either by an empty string or by UNC name (and will be
1691// limited by kMaxCookiesPerHost), and extension cookies will be stored
1692// based on the single extension id, as the extension id won't have the
1693// form of a DNS host and hence GetKey() will return it unchanged.
1694//
1695// Arguably the right thing to do here is to make the key
1696// algorithm dependent on the scheme, and make sure that the scheme is
1697// available everywhere the key must be obtained (specfically at backing
1698// store load time). This would require either changing the backing store
1699// database schema to include the scheme (far more trouble than it's worth), or
1700// separating out file cookies into their own CookieMonster instance and
1701// thus restricting each scheme to a single cookie monster (which might
1702// be worth it, but is still too much trouble to solve what is currently a
1703// non-problem).
Maks Orlovich323efaf2018-03-06 02:56:391704//
1705// static
1706std::string CookieMonster::GetKey(base::StringPiece domain) {
[email protected]f48b9432011-01-11 07:25:401707 std::string effective_domain(
[email protected]ed32c212013-05-14 20:49:291708 registry_controlled_domains::GetDomainAndRegistry(
[email protected]aabe1792014-01-30 21:37:461709 domain, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES));
[email protected]f48b9432011-01-11 07:25:401710 if (effective_domain.empty())
Maks Orlovich323efaf2018-03-06 02:56:391711 domain.CopyToString(&effective_domain);
[email protected]f48b9432011-01-11 07:25:401712
1713 if (!effective_domain.empty() && effective_domain[0] == '.')
1714 return effective_domain.substr(1);
1715 return effective_domain;
1716}
1717
1718bool CookieMonster::HasCookieableScheme(const GURL& url) {
mmenkebe0910d2016-03-01 19:09:091719 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401720
1721 // Make sure the request is on a cookie-able url scheme.
1722 for (size_t i = 0; i < cookieable_schemes_.size(); ++i) {
1723 // We matched a scheme.
1724 if (url.SchemeIs(cookieable_schemes_[i].c_str())) {
1725 // We've matched a supported scheme.
initial.commit586acc5fe2008-07-26 22:42:521726 return true;
1727 }
1728 }
[email protected]f48b9432011-01-11 07:25:401729
1730 // The scheme didn't match any in our whitelist.
Oscar Johansson63e83cf2018-07-02 08:47:261731 VLOG(net::cookie_util::kVlogPerCookieMonster)
mkwstbe84af312015-02-20 08:52:451732 << "WARNING: Unsupported cookie scheme: " << url.scheme();
initial.commit586acc5fe2008-07-26 22:42:521733 return false;
1734}
1735
[email protected]c4058fb2010-06-22 17:25:261736// Test to see if stats should be recorded, and record them if so.
1737// The goal here is to get sampling for the average browser-hour of
1738// activity. We won't take samples when the web isn't being surfed,
1739// and when the web is being surfed, we'll take samples about every
1740// kRecordStatisticsIntervalSeconds.
1741// last_statistic_record_time_ is initialized to Now() rather than null
1742// in the constructor so that we won't take statistics right after
1743// startup, to avoid bias from browsers that are started but not used.
1744void CookieMonster::RecordPeriodicStats(const base::Time& current_time) {
mmenkebe0910d2016-03-01 19:09:091745 DCHECK(thread_checker_.CalledOnValidThread());
1746
[email protected]c4058fb2010-06-22 17:25:261747 const base::TimeDelta kRecordStatisticsIntervalTime(
1748 base::TimeDelta::FromSeconds(kRecordStatisticsIntervalSeconds));
1749
[email protected]7a964a72010-09-07 19:33:261750 // If we've taken statistics recently, return.
1751 if (current_time - last_statistic_record_time_ <=
[email protected]c4058fb2010-06-22 17:25:261752 kRecordStatisticsIntervalTime) {
[email protected]7a964a72010-09-07 19:33:261753 return;
[email protected]c4058fb2010-06-22 17:25:261754 }
[email protected]7a964a72010-09-07 19:33:261755
1756 // See InitializeHistograms() for details.
1757 histogram_count_->Add(cookies_.size());
1758
1759 // More detailed statistics on cookie counts at different granularities.
[email protected]7a964a72010-09-07 19:33:261760 last_statistic_record_time_ = current_time;
[email protected]c4058fb2010-06-22 17:25:261761}
1762
[email protected]f48b9432011-01-11 07:25:401763// Initialize all histogram counter variables used in this class.
1764//
1765// Normal histogram usage involves using the macros defined in
1766// histogram.h, which automatically takes care of declaring these
1767// variables (as statics), initializing them, and accumulating into
1768// them, all from a single entry point. Unfortunately, that solution
1769// doesn't work for the CookieMonster, as it's vulnerable to races between
1770// separate threads executing the same functions and hence initializing the
1771// same static variables. There isn't a race danger in the histogram
1772// accumulation calls; they are written to be resilient to simultaneous
1773// calls from multiple threads.
1774//
1775// The solution taken here is to have per-CookieMonster instance
1776// variables that are constructed during CookieMonster construction.
1777// Note that these variables refer to the same underlying histogram,
1778// so we still race (but safely) with other CookieMonster instances
1779// for accumulation.
1780//
1781// To do this we've expanded out the individual histogram macros calls,
1782// with declarations of the variables in the class decl, initialization here
1783// (done from the class constructor) and direct calls to the accumulation
1784// methods where needed. The specific histogram macro calls on which the
1785// initialization is based are included in comments below.
1786void CookieMonster::InitializeHistograms() {
mmenkebe0910d2016-03-01 19:09:091787 DCHECK(thread_checker_.CalledOnValidThread());
1788
[email protected]f48b9432011-01-11 07:25:401789 // From UMA_HISTOGRAM_CUSTOM_COUNTS
1790 histogram_expiration_duration_minutes_ = base::Histogram::FactoryGet(
mkwstbe84af312015-02-20 08:52:451791 "Cookie.ExpirationDurationMinutes", 1, kMinutesInTenYears, 50,
[email protected]f48b9432011-01-11 07:25:401792 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401793 histogram_count_ = base::Histogram::FactoryGet(
mkwstbe84af312015-02-20 08:52:451794 "Cookie.Count", 1, 4000, 50, base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401795
1796 // From UMA_HISTOGRAM_ENUMERATION
mkwstc1aa4cc2015-04-03 19:57:451797 histogram_cookie_type_ = base::LinearHistogram::FactoryGet(
mkwst87378d92015-04-10 21:22:111798 "Cookie.Type", 1, (1 << COOKIE_TYPE_LAST_ENTRY) - 1,
1799 1 << COOKIE_TYPE_LAST_ENTRY, base::Histogram::kUmaTargetedHistogramFlag);
estark7feb65c2b2015-08-21 23:38:201800 histogram_cookie_source_scheme_ = base::LinearHistogram::FactoryGet(
1801 "Cookie.CookieSourceScheme", 1, COOKIE_SOURCE_LAST_ENTRY - 1,
1802 COOKIE_SOURCE_LAST_ENTRY, base::Histogram::kUmaTargetedHistogramFlag);
jww31e32632015-12-16 23:38:341803 histogram_cookie_delete_equivalent_ = base::LinearHistogram::FactoryGet(
1804 "Cookie.CookieDeleteEquivalent", 1,
1805 COOKIE_DELETE_EQUIVALENT_LAST_ENTRY - 1,
1806 COOKIE_DELETE_EQUIVALENT_LAST_ENTRY,
1807 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401808
1809 // From UMA_HISTOGRAM_{CUSTOM_,}TIMES
[email protected]c7593fb22011-11-14 23:54:271810 histogram_time_blocked_on_load_ = base::Histogram::FactoryTimeGet(
mkwstbe84af312015-02-20 08:52:451811 "Cookie.TimeBlockedOnLoad", base::TimeDelta::FromMilliseconds(1),
1812 base::TimeDelta::FromMinutes(1), 50,
1813 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401814}
1815
[email protected]f48b9432011-01-11 07:25:401816// The system resolution is not high enough, so we can have multiple
1817// set cookies that result in the same system time. When this happens, we
1818// increment by one Time unit. Let's hope computers don't get too fast.
1819Time CookieMonster::CurrentTime() {
mkwstbe84af312015-02-20 08:52:451820 return std::max(Time::Now(), Time::FromInternalValue(
1821 last_time_seen_.ToInternalValue() + 1));
[email protected]f48b9432011-01-11 07:25:401822}
1823
rdsmithe5c701d2017-07-12 21:50:001824void CookieMonster::DoCookieCallback(base::OnceClosure callback) {
mmenkebe0910d2016-03-01 19:09:091825 DCHECK(thread_checker_.CalledOnValidThread());
1826
1827 MarkCookieStoreAsInitialized();
1828 FetchAllCookiesIfNecessary();
mmenkef49fca0e2016-03-08 12:46:241829 seen_global_task_ = true;
mmenkebe0910d2016-03-01 19:09:091830
1831 if (!finished_fetching_all_cookies_ && store_.get()) {
rdsmithe5c701d2017-07-12 21:50:001832 tasks_pending_.push_back(std::move(callback));
mmenkebe0910d2016-03-01 19:09:091833 return;
mmenke74bcbd52016-01-21 17:17:561834 }
1835
rdsmithe5c701d2017-07-12 21:50:001836 std::move(callback).Run();
mmenke74bcbd52016-01-21 17:17:561837}
1838
rdsmithe5c701d2017-07-12 21:50:001839void CookieMonster::DoCookieCallbackForURL(base::OnceClosure callback,
1840 const GURL& url) {
Maks Orlovich323efaf2018-03-06 02:56:391841 DoCookieCallbackForHostOrDomain(std::move(callback), url.host_piece());
1842}
1843
1844void CookieMonster::DoCookieCallbackForHostOrDomain(
1845 base::OnceClosure callback,
1846 base::StringPiece host_or_domain) {
mmenkebe0910d2016-03-01 19:09:091847 MarkCookieStoreAsInitialized();
erikchende4c39e2018-01-29 21:33:361848 FetchAllCookiesIfNecessary();
mmenkebe0910d2016-03-01 19:09:091849
1850 // If cookies for the requested domain key (eTLD+1) have been loaded from DB
1851 // then run the task, otherwise load from DB.
1852 if (!finished_fetching_all_cookies_ && store_.get()) {
mmenkef49fca0e2016-03-08 12:46:241853 // If a global task has been previously seen, queue the task as a global
1854 // task. Note that the CookieMonster may be in the middle of executing
1855 // the global queue, |tasks_pending_| may be empty, which is why another
1856 // bool is needed.
1857 if (seen_global_task_) {
rdsmithe5c701d2017-07-12 21:50:001858 tasks_pending_.push_back(std::move(callback));
mmenkef49fca0e2016-03-08 12:46:241859 return;
1860 }
1861
mmenkebe0910d2016-03-01 19:09:091862 // Checks if the domain key has been loaded.
Maks Orlovich323efaf2018-03-06 02:56:391863 std::string key = GetKey(host_or_domain);
mmenkebe0910d2016-03-01 19:09:091864 if (keys_loaded_.find(key) == keys_loaded_.end()) {
Brett Wilsonc6a0c822017-09-12 00:04:291865 std::map<std::string, base::circular_deque<base::OnceClosure>>::iterator
1866 it = tasks_pending_for_key_.find(key);
mmenkebe0910d2016-03-01 19:09:091867 if (it == tasks_pending_for_key_.end()) {
1868 store_->LoadCookiesForKey(
1869 key, base::Bind(&CookieMonster::OnKeyLoaded,
1870 weak_ptr_factory_.GetWeakPtr(), key));
1871 it = tasks_pending_for_key_
Brett Wilsonc6a0c822017-09-12 00:04:291872 .insert(std::make_pair(
1873 key, base::circular_deque<base::OnceClosure>()))
mmenkebe0910d2016-03-01 19:09:091874 .first;
mmenke74bcbd52016-01-21 17:17:561875 }
rdsmithe5c701d2017-07-12 21:50:001876 it->second.push_back(std::move(callback));
mmenkebe0910d2016-03-01 19:09:091877 return;
mmenke74bcbd52016-01-21 17:17:561878 }
1879 }
mmenkebe0910d2016-03-01 19:09:091880
rdsmithe5c701d2017-07-12 21:50:001881 std::move(callback).Run();
mmenke74bcbd52016-01-21 17:17:561882}
1883
[email protected]63725312012-07-19 08:24:161884} // namespace net