blob: ce09270fc6248c76e5738d5816435bfe7bfa1df1 [file] [log] [blame]
[email protected]8e1583672012-02-11 04:39:411// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit586acc5fe2008-07-26 22:42:524
5// Portions of this code based on Mozilla:
6// (netwerk/cookie/src/nsCookieService.cpp)
7/* ***** BEGIN LICENSE BLOCK *****
8 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
9 *
10 * The contents of this file are subject to the Mozilla Public License Version
11 * 1.1 (the "License"); you may not use this file except in compliance with
12 * the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
14 *
15 * Software distributed under the License is distributed on an "AS IS" basis,
16 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
17 * for the specific language governing rights and limitations under the
18 * License.
19 *
20 * The Original Code is mozilla.org code.
21 *
22 * The Initial Developer of the Original Code is
23 * Netscape Communications Corporation.
24 * Portions created by the Initial Developer are Copyright (C) 2003
25 * the Initial Developer. All Rights Reserved.
26 *
27 * Contributor(s):
28 * Daniel Witte ([email protected])
29 * Michiel van Leeuwen ([email protected])
30 *
31 * Alternatively, the contents of this file may be used under the terms of
32 * either the GNU General Public License Version 2 or later (the "GPL"), or
33 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
34 * in which case the provisions of the GPL or the LGPL are applicable instead
35 * of those above. If you wish to allow use of your version of this file only
36 * under the terms of either the GPL or the LGPL, and not to allow others to
37 * use your version of this file under the terms of the MPL, indicate your
38 * decision by deleting the provisions above and replace them with the notice
39 * and other provisions required by the GPL or the LGPL. If you do not delete
40 * the provisions above, a recipient may use your version of this file under
41 * the terms of any one of the MPL, the GPL or the LGPL.
42 *
43 * ***** END LICENSE BLOCK ***** */
44
[email protected]63ee33bd2012-03-15 09:29:5845#include "net/cookies/cookie_monster.h"
initial.commit586acc5fe2008-07-26 22:42:5246
[email protected]8ad5d462013-05-02 08:45:2647#include <functional>
[email protected]09666482011-07-12 12:50:4048#include <set>
initial.commit586acc5fe2008-07-26 22:42:5249
[email protected]218aa6a12011-09-13 17:38:3850#include "base/bind.h"
[email protected]85620342011-10-17 17:35:0451#include "base/callback.h"
skyostil4891b25b2015-06-11 11:43:4552#include "base/location.h"
initial.commit586acc5fe2008-07-26 22:42:5253#include "base/logging.h"
Avi Drissman13fc8932015-12-20 04:40:4654#include "base/macros.h"
erikchen1dd72a72015-05-06 20:45:0555#include "base/metrics/field_trial.h"
[email protected]835d7c82010-10-14 04:38:3856#include "base/metrics/histogram.h"
anujk.sharmaafc45172015-05-15 00:50:3457#include "base/single_thread_task_runner.h"
tripta.gdda72022017-06-19 05:16:2358#include "base/stl_util.h"
Maks Orlovich323efaf2018-03-06 02:56:3959#include "base/strings/string_piece.h"
[email protected]4b355212013-06-11 10:35:1960#include "base/strings/string_util.h"
61#include "base/strings/stringprintf.h"
gabf767595f2016-05-11 18:50:3562#include "base/threading/thread_task_runner_handle.h"
[email protected]be28b5f42012-07-20 11:31:2563#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
[email protected]4b355212013-06-11 10:35:1964#include "net/cookies/canonical_cookie.h"
Victor Costan14f47c12018-03-01 08:02:2465#include "net/cookies/cookie_monster_change_dispatcher.h"
[email protected]63ee33bd2012-03-15 09:29:5866#include "net/cookies/cookie_util.h"
[email protected]ebfe3172012-07-12 12:21:4167#include "net/cookies/parsed_cookie.h"
nharper2b0ad9a2017-05-22 18:33:4568#include "net/ssl/channel_id_service.h"
mkwst8241a122015-10-20 07:15:1069#include "url/origin.h"
initial.commit586acc5fe2008-07-26 22:42:5270
[email protected]e1acf6f2008-10-27 20:43:3371using base::Time;
72using base::TimeDelta;
[email protected]7a964a72010-09-07 19:33:2673using base::TimeTicks;
[email protected]e1acf6f2008-10-27 20:43:3374
[email protected]85620342011-10-17 17:35:0475// In steady state, most cookie requests can be satisfied by the in memory
erikchen1dd72a72015-05-06 20:45:0576// cookie monster store. If the cookie request cannot be satisfied by the in
77// memory store, the relevant cookies must be fetched from the persistent
78// store. The task is queued in CookieMonster::tasks_pending_ if it requires
79// all cookies to be loaded from the backend, or tasks_pending_for_key_ if it
80// only requires all cookies associated with an eTLD+1.
[email protected]85620342011-10-17 17:35:0481//
82// On the browser critical paths (e.g. for loading initial web pages in a
83// session restore) it may take too long to wait for the full load. If a cookie
rdsmithe5c701d2017-07-12 21:50:0084// request is for a specific URL, DoCookieCallbackForURL is called, which
85// triggers a priority load if the key is not loaded yet by calling
86// PersistentCookieStore::LoadCookiesForKey. The request is queued in
[email protected]0184df32013-05-14 00:53:5587// CookieMonster::tasks_pending_for_key_ and executed upon receiving
88// notification of key load completion via CookieMonster::OnKeyLoaded(). If
89// multiple requests for the same eTLD+1 are received before key load
90// completion, only the first request calls
[email protected]85620342011-10-17 17:35:0491// PersistentCookieStore::LoadCookiesForKey, all subsequent requests are queued
[email protected]0184df32013-05-14 00:53:5592// in CookieMonster::tasks_pending_for_key_ and executed upon receiving
93// notification of key load completion triggered by the first request for the
94// same eTLD+1.
[email protected]85620342011-10-17 17:35:0495
[email protected]c4058fb2010-06-22 17:25:2696static const int kMinutesInTenYears = 10 * 365 * 24 * 60;
97
erikchen1dd72a72015-05-06 20:45:0598namespace {
99
rdsmithe5c701d2017-07-12 21:50:00100void MayeRunDeleteCallback(base::WeakPtr<net::CookieMonster> cookie_monster,
101 base::OnceClosure callback) {
102 if (cookie_monster && callback)
103 std::move(callback).Run();
104}
105
106void MaybeRunCookieCallback(base::OnceClosure callback) {
107 if (callback)
108 std::move(callback).Run();
109}
110
111template <typename T>
112void MaybeRunCookieCallback(base::OnceCallback<void(const T&)> callback,
113 const T& result) {
114 if (callback)
115 std::move(callback).Run(result);
116}
117
118template <typename T>
119void MaybeRunCookieCallback(base::OnceCallback<void(T)> callback,
120 const T& result) {
121 if (callback)
122 std::move(callback).Run(result);
123}
124
erikchen1dd72a72015-05-06 20:45:05125} // namespace
126
[email protected]8ac1a752008-07-31 19:40:37127namespace net {
128
[email protected]7a964a72010-09-07 19:33:26129// See comments at declaration of these variables in cookie_monster.h
130// for details.
mkwstbe84af312015-02-20 08:52:45131const size_t CookieMonster::kDomainMaxCookies = 180;
132const size_t CookieMonster::kDomainPurgeCookies = 30;
133const size_t CookieMonster::kMaxCookies = 3300;
134const size_t CookieMonster::kPurgeCookies = 300;
[email protected]8ad5d462013-05-02 08:45:26135
mkwst87734352016-03-03 17:36:23136const size_t CookieMonster::kDomainCookiesQuotaLow = 30;
137const size_t CookieMonster::kDomainCookiesQuotaMedium = 50;
138const size_t CookieMonster::kDomainCookiesQuotaHigh =
139 kDomainMaxCookies - kDomainPurgeCookies - kDomainCookiesQuotaLow -
140 kDomainCookiesQuotaMedium;
[email protected]8ad5d462013-05-02 08:45:26141
mkwstbe84af312015-02-20 08:52:45142const int CookieMonster::kSafeFromGlobalPurgeDays = 30;
[email protected]297a4ed02010-02-12 08:12:52143
[email protected]7a964a72010-09-07 19:33:26144namespace {
[email protected]e32306c52008-11-06 16:59:05145
[email protected]6210ce52013-09-20 03:33:14146bool ContainsControlCharacter(const std::string& s) {
147 for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
148 if ((*i >= 0) && (*i <= 31))
149 return true;
150 }
151
152 return false;
153}
154
[email protected]5b9bc352012-07-18 13:13:34155typedef std::vector<CanonicalCookie*> CanonicalCookieVector;
[email protected]34a160d2011-05-12 22:12:49156
[email protected]77e0a462008-11-01 00:43:35157// Default minimum delay after updating a cookie's LastAccessDate before we
158// will update it again.
[email protected]297a4ed02010-02-12 08:12:52159const int kDefaultAccessUpdateThresholdSeconds = 60;
160
161// Comparator to sort cookies from highest creation date to lowest
162// creation date.
163struct OrderByCreationTimeDesc {
164 bool operator()(const CookieMonster::CookieMap::iterator& a,
165 const CookieMonster::CookieMap::iterator& b) const {
166 return a->second->CreationDate() > b->second->CreationDate();
167 }
168};
169
[email protected]4d3ce782010-10-29 18:31:28170// Constants for use in VLOG
171const int kVlogPerCookieMonster = 1;
[email protected]4d3ce782010-10-29 18:31:28172const int kVlogGarbageCollection = 5;
173const int kVlogSetCookies = 7;
[email protected]f48b9432011-01-11 07:25:40174// Mozilla sorts on the path length (longest first), and then it
175// sorts by creation time (oldest first).
176// The RFC says the sort order for the domain attribute is undefined.
[email protected]5b9bc352012-07-18 13:13:34177bool CookieSorter(CanonicalCookie* cc1, CanonicalCookie* cc2) {
[email protected]f48b9432011-01-11 07:25:40178 if (cc1->Path().length() == cc2->Path().length())
179 return cc1->CreationDate() < cc2->CreationDate();
180 return cc1->Path().length() > cc2->Path().length();
initial.commit586acc5fe2008-07-26 22:42:52181}
182
[email protected]8ad5d462013-05-02 08:45:26183bool LRACookieSorter(const CookieMonster::CookieMap::iterator& it1,
[email protected]f48b9432011-01-11 07:25:40184 const CookieMonster::CookieMap::iterator& it2) {
[email protected]f48b9432011-01-11 07:25:40185 if (it1->second->LastAccessDate() != it2->second->LastAccessDate())
186 return it1->second->LastAccessDate() < it2->second->LastAccessDate();
initial.commit586acc5fe2008-07-26 22:42:52187
mkwste079ac412016-03-11 09:04:06188 // Ensure stability for == last access times by falling back to creation.
[email protected]f48b9432011-01-11 07:25:40189 return it1->second->CreationDate() < it2->second->CreationDate();
[email protected]297a4ed02010-02-12 08:12:52190}
191
192// Our strategy to find duplicates is:
193// (1) Build a map from (cookiename, cookiepath) to
194// {list of cookies with this signature, sorted by creation time}.
195// (2) For each list with more than 1 entry, keep the cookie having the
196// most recent creation time, and delete the others.
[email protected]f48b9432011-01-11 07:25:40197//
[email protected]1655ba342010-07-14 18:17:42198// Two cookies are considered equivalent if they have the same domain,
199// name, and path.
200struct CookieSignature {
201 public:
[email protected]dedec0b2013-02-28 04:50:10202 CookieSignature(const std::string& name,
203 const std::string& domain,
[email protected]1655ba342010-07-14 18:17:42204 const std::string& path)
mkwstbe84af312015-02-20 08:52:45205 : name(name), domain(domain), path(path) {}
[email protected]1655ba342010-07-14 18:17:42206
207 // To be a key for a map this class needs to be assignable, copyable,
208 // and have an operator<. The default assignment operator
209 // and copy constructor are exactly what we want.
210
211 bool operator<(const CookieSignature& cs) const {
212 // Name compare dominates, then domain, then path.
213 int diff = name.compare(cs.name);
214 if (diff != 0)
215 return diff < 0;
216
217 diff = domain.compare(cs.domain);
218 if (diff != 0)
219 return diff < 0;
220
221 return path.compare(cs.path) < 0;
222 }
223
224 std::string name;
225 std::string domain;
226 std::string path;
227};
[email protected]f48b9432011-01-11 07:25:40228
[email protected]8ad5d462013-05-02 08:45:26229// For a CookieItVector iterator range [|it_begin|, |it_end|),
mmenkef4721d992017-06-07 17:13:59230// sorts the first |num_sort| elements by LastAccessDate().
mkwstbe84af312015-02-20 08:52:45231void SortLeastRecentlyAccessed(CookieMonster::CookieItVector::iterator it_begin,
232 CookieMonster::CookieItVector::iterator it_end,
233 size_t num_sort) {
mmenkef4721d992017-06-07 17:13:59234 DCHECK_LE(static_cast<int>(num_sort), it_end - it_begin);
235 std::partial_sort(it_begin, it_begin + num_sort, it_end, LRACookieSorter);
[email protected]8ad5d462013-05-02 08:45:26236}
[email protected]f48b9432011-01-11 07:25:40237
jww82d99c12015-11-25 18:39:53238// Given a single cookie vector |cookie_its|, pushs all of the secure cookies in
239// |cookie_its| into |secure_cookie_its| and all of the non-secure cookies into
240// |non_secure_cookie_its|. Both |secure_cookie_its| and |non_secure_cookie_its|
241// must be non-NULL.
242void SplitCookieVectorIntoSecureAndNonSecure(
243 const CookieMonster::CookieItVector& cookie_its,
244 CookieMonster::CookieItVector* secure_cookie_its,
245 CookieMonster::CookieItVector* non_secure_cookie_its) {
246 DCHECK(secure_cookie_its && non_secure_cookie_its);
247 for (const auto& curit : cookie_its) {
248 if (curit->second->IsSecure())
249 secure_cookie_its->push_back(curit);
250 else
251 non_secure_cookie_its->push_back(curit);
252 }
253}
254
mkwstbe84af312015-02-20 08:52:45255bool LowerBoundAccessDateComparator(const CookieMonster::CookieMap::iterator it,
256 const Time& access_date) {
[email protected]8ad5d462013-05-02 08:45:26257 return it->second->LastAccessDate() < access_date;
258}
259
260// For a CookieItVector iterator range [|it_begin|, |it_end|)
261// from a CookieItVector sorted by LastAccessDate(), returns the
262// first iterator with access date >= |access_date|, or cookie_its_end if this
263// holds for all.
264CookieMonster::CookieItVector::iterator LowerBoundAccessDate(
265 const CookieMonster::CookieItVector::iterator its_begin,
266 const CookieMonster::CookieItVector::iterator its_end,
267 const Time& access_date) {
268 return std::lower_bound(its_begin, its_end, access_date,
269 LowerBoundAccessDateComparator);
[email protected]7a964a72010-09-07 19:33:26270}
271
Victor Costan14f47c12018-03-01 08:02:24272// Mapping between DeletionCause and CookieChangeCause; the
[email protected]7c4b66b2014-01-04 12:28:13273// mapping also provides a boolean that specifies whether or not an
Victor Costan14f47c12018-03-01 08:02:24274// OnCookieChange notification ought to be generated.
[email protected]8bb846f2011-03-23 12:08:18275typedef struct ChangeCausePair_struct {
Victor Costan14f47c12018-03-01 08:02:24276 CookieChangeCause cause;
[email protected]8bb846f2011-03-23 12:08:18277 bool notify;
278} ChangeCausePair;
nharper352933e2016-09-30 18:24:57279const ChangeCausePair kChangeCauseMapping[] = {
mkwstbe84af312015-02-20 08:52:45280 // DELETE_COOKIE_EXPLICIT
Victor Costan14f47c12018-03-01 08:02:24281 {CookieChangeCause::EXPLICIT, true},
mkwstbe84af312015-02-20 08:52:45282 // DELETE_COOKIE_OVERWRITE
Victor Costan14f47c12018-03-01 08:02:24283 {CookieChangeCause::OVERWRITE, true},
mkwstbe84af312015-02-20 08:52:45284 // DELETE_COOKIE_EXPIRED
Victor Costan14f47c12018-03-01 08:02:24285 {CookieChangeCause::EXPIRED, true},
mkwstbe84af312015-02-20 08:52:45286 // DELETE_COOKIE_EVICTED
Victor Costan14f47c12018-03-01 08:02:24287 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45288 // DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE
Victor Costan14f47c12018-03-01 08:02:24289 {CookieChangeCause::EXPLICIT, false},
mkwstbe84af312015-02-20 08:52:45290 // DELETE_COOKIE_DONT_RECORD
Victor Costan14f47c12018-03-01 08:02:24291 {CookieChangeCause::EXPLICIT, false},
mkwstbe84af312015-02-20 08:52:45292 // DELETE_COOKIE_EVICTED_DOMAIN
Victor Costan14f47c12018-03-01 08:02:24293 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45294 // DELETE_COOKIE_EVICTED_GLOBAL
Victor Costan14f47c12018-03-01 08:02:24295 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45296 // DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE
Victor Costan14f47c12018-03-01 08:02:24297 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45298 // DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE
Victor Costan14f47c12018-03-01 08:02:24299 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45300 // DELETE_COOKIE_EXPIRED_OVERWRITE
Victor Costan14f47c12018-03-01 08:02:24301 {CookieChangeCause::EXPIRED_OVERWRITE, true},
mkwstbe84af312015-02-20 08:52:45302 // DELETE_COOKIE_CONTROL_CHAR
Victor Costan14f47c12018-03-01 08:02:24303 {CookieChangeCause::EVICTED, true},
jww82d99c12015-11-25 18:39:53304 // DELETE_COOKIE_NON_SECURE
Victor Costan14f47c12018-03-01 08:02:24305 {CookieChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45306 // DELETE_COOKIE_LAST_ENTRY
Victor Costan14f47c12018-03-01 08:02:24307 {CookieChangeCause::EXPLICIT, false}};
ellyjones399e35a22014-10-27 11:09:56308
jwwc00ac712016-05-05 22:21:44309bool IsCookieEligibleForEviction(CookiePriority current_priority_level,
310 bool protect_secure_cookies,
311 const CanonicalCookie* cookie) {
mmenke645ca6772016-06-17 18:46:43312 if (cookie->Priority() == current_priority_level && protect_secure_cookies)
313 return !cookie->IsSecure();
jwwc00ac712016-05-05 22:21:44314
mmenke645ca6772016-06-17 18:46:43315 return cookie->Priority() == current_priority_level;
316}
jwwc00ac712016-05-05 22:21:44317
mmenke645ca6772016-06-17 18:46:43318size_t CountCookiesForPossibleDeletion(
319 CookiePriority priority,
320 const CookieMonster::CookieItVector* cookies,
321 bool protect_secure_cookies) {
322 size_t cookies_count = 0U;
323 for (const auto& cookie : *cookies) {
324 if (cookie->second->Priority() == priority) {
325 if (!protect_secure_cookies || cookie->second->IsSecure())
326 cookies_count++;
327 }
328 }
329 return cookies_count;
jwwc00ac712016-05-05 22:21:44330}
331
[email protected]f48b9432011-01-11 07:25:40332} // namespace
333
Thomas Anderson1a03bbe2018-03-02 19:05:47334CookieMonster::CookieMonster(PersistentCookieStore* store)
shessf0bc1182016-05-19 04:35:58335 : CookieMonster(
336 store,
nharper2b0ad9a2017-05-22 18:33:45337 nullptr,
shessf0bc1182016-05-19 04:35:58338 base::TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds)) {}
[email protected]2d0f89a2010-12-06 12:02:23339
[email protected]f48b9432011-01-11 07:25:40340CookieMonster::CookieMonster(PersistentCookieStore* store,
Thomas Anderson1a03bbe2018-03-02 19:05:47341 ChannelIDService* channel_id_service)
Randy Smithb78e0922018-03-01 21:19:54342 : CookieMonster(
343 store,
344 channel_id_service,
Randy Smithb78e0922018-03-01 21:19:54345 base::TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds)) {}
346
347CookieMonster::CookieMonster(PersistentCookieStore* store,
Randy Smithb78e0922018-03-01 21:19:54348 base::TimeDelta last_access_threshold)
Thomas Anderson1a03bbe2018-03-02 19:05:47349 : CookieMonster(store, nullptr, last_access_threshold) {}
Randy Smithb78e0922018-03-01 21:19:54350
351CookieMonster::CookieMonster(PersistentCookieStore* store,
352 ChannelIDService* channel_id_service,
shessf0bc1182016-05-19 04:35:58353 base::TimeDelta last_access_threshold)
[email protected]f48b9432011-01-11 07:25:40354 : initialized_(false),
erikchen1dd72a72015-05-06 20:45:05355 started_fetching_all_cookies_(false),
356 finished_fetching_all_cookies_(false),
mmenkef49fca0e2016-03-08 12:46:24357 seen_global_task_(false),
[email protected]f48b9432011-01-11 07:25:40358 store_(store),
shessf0bc1182016-05-19 04:35:58359 last_access_threshold_(last_access_threshold),
nharper2b0ad9a2017-05-22 18:33:45360 channel_id_service_(channel_id_service),
[email protected]82388662011-03-10 21:04:06361 last_statistic_record_time_(base::Time::Now()),
mmenkebe0910d2016-03-01 19:09:09362 persist_session_cookies_(false),
mmenkebe0910d2016-03-01 19:09:09363 weak_ptr_factory_(this) {
[email protected]f48b9432011-01-11 07:25:40364 InitializeHistograms();
mmenke18dd8ba2016-02-01 18:42:10365 cookieable_schemes_.insert(
366 cookieable_schemes_.begin(), kDefaultCookieableSchemes,
367 kDefaultCookieableSchemes + kDefaultCookieableSchemesCount);
Nick Harper14e23332017-07-28 00:27:23368 if (channel_id_service_ && store_) {
369 // |store_| can outlive this CookieMonster, but there are no guarantees
370 // about the lifetime of |channel_id_service_| relative to |store_|. The
371 // only guarantee is that |channel_id_service_| will outlive this
372 // CookieMonster. To avoid the PersistentCookieStore retaining a pointer to
373 // the ChannelIDStore via this callback after this CookieMonster is
374 // destroyed, CookieMonster's d'tor sets the callback to a null callback.
375 store_->SetBeforeFlushCallback(
376 base::Bind(&ChannelIDStore::Flush,
377 base::Unretained(channel_id_service_->GetChannelIDStore())));
378 }
initial.commit586acc5fe2008-07-26 22:42:52379}
380
[email protected]218aa6a12011-09-13 17:38:38381// Asynchronous CookieMonster API
382
rdsmith7ac81712017-06-22 17:09:54383void CookieMonster::FlushStore(base::OnceClosure callback) {
mmenkebe0910d2016-03-01 19:09:09384 DCHECK(thread_checker_.CalledOnValidThread());
mmenke606c59c2016-03-07 18:20:55385
nharper2b0ad9a2017-05-22 18:33:45386 if (initialized_ && store_.get()) {
rdsmith7ac81712017-06-22 17:09:54387 store_->Flush(std::move(callback));
rdsmithe5c701d2017-07-12 21:50:00388 } else if (callback) {
rdsmith7ac81712017-06-22 17:09:54389 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
390 std::move(callback));
nharper2b0ad9a2017-05-22 18:33:45391 }
mmenke74bcbd52016-01-21 17:17:56392}
393
mmenkeded79da2016-02-06 08:28:51394void CookieMonster::SetForceKeepSessionState() {
mmenkebe0910d2016-03-01 19:09:09395 DCHECK(thread_checker_.CalledOnValidThread());
mmenke606c59c2016-03-07 18:20:55396
mmenkeded79da2016-02-06 08:28:51397 if (store_)
398 store_->SetForceKeepSessionState();
399}
400
drogerd5d1278c2015-03-17 19:21:51401void CookieMonster::SetAllCookiesAsync(const CookieList& list,
rdsmith7ac81712017-06-22 17:09:54402 SetCookiesCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00403 DoCookieCallback(base::BindOnce(
404 // base::Unretained is safe as DoCookieCallbackForURL stores
405 // the callback on |*this|, so the callback will not outlive
406 // the object.
407 &CookieMonster::SetAllCookies, base::Unretained(this), list,
408 std::move(callback)));
drogerd5d1278c2015-03-17 19:21:51409}
410
rdsmitha6ce4442017-06-21 17:11:05411void CookieMonster::SetCanonicalCookieAsync(
412 std::unique_ptr<CanonicalCookie> cookie,
413 bool secure_source,
414 bool modify_http_only,
rdsmith7ac81712017-06-22 17:09:54415 SetCookiesCallback callback) {
rdsmitha6ce4442017-06-21 17:11:05416 DCHECK(cookie->IsCanonical());
rdsmitha6ce4442017-06-21 17:11:05417
Maks Orlovich323efaf2018-03-06 02:56:39418 std::string domain = cookie->Domain();
419 DoCookieCallbackForHostOrDomain(
420 base::BindOnce(
421 // base::Unretained is safe as DoCookieCallbackForURL stores
422 // the callback on |*this|, so the callback will not outlive
423 // the object.
424 &CookieMonster::SetCanonicalCookie, base::Unretained(this),
425 std::move(cookie), secure_source, modify_http_only,
426 std::move(callback)),
427 domain);
rdsmitha6ce4442017-06-21 17:11:05428}
429
rdsmith7ac81712017-06-22 17:09:54430void CookieMonster::SetCookieWithOptionsAsync(const GURL& url,
431 const std::string& cookie_line,
432 const CookieOptions& options,
433 SetCookiesCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00434 DoCookieCallbackForURL(
435 base::BindOnce(
436 // base::Unretained is safe as DoCookieCallbackForURL stores
437 // the callback on |*this|, so the callback will not outlive
438 // the object.
439 &CookieMonster::SetCookieWithOptions, base::Unretained(this), url,
440 cookie_line, options, std::move(callback)),
441 url);
[email protected]218aa6a12011-09-13 17:38:38442}
443
mkwstc611e6d2016-02-23 15:45:55444void CookieMonster::GetCookieListWithOptionsAsync(
mmenke74bcbd52016-01-21 17:17:56445 const GURL& url,
mkwstc611e6d2016-02-23 15:45:55446 const CookieOptions& options,
rdsmith7ac81712017-06-22 17:09:54447 GetCookieListCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00448 DoCookieCallbackForURL(
449 base::BindOnce(
450 // base::Unretained is safe as DoCookieCallbackForURL stores
451 // the callback on |*this|, so the callback will not outlive
452 // the object.
453 &CookieMonster::GetCookieListWithOptions, base::Unretained(this), url,
454 options, std::move(callback)),
455 url);
mmenke74bcbd52016-01-21 17:17:56456}
457
rdsmith7ac81712017-06-22 17:09:54458void CookieMonster::GetAllCookiesAsync(GetCookieListCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00459 DoCookieCallback(base::BindOnce(
460 // base::Unretained is safe as DoCookieCallbackForURL stores
461 // the callback on |*this|, so the callback will not outlive
462 // the object.
463 &CookieMonster::GetAllCookies, base::Unretained(this),
464 std::move(callback)));
mmenke9fa44f2d2016-01-22 23:36:39465}
466
[email protected]218aa6a12011-09-13 17:38:38467void CookieMonster::DeleteCookieAsync(const GURL& url,
468 const std::string& cookie_name,
rdsmith7ac81712017-06-22 17:09:54469 base::OnceClosure callback) {
rdsmithe5c701d2017-07-12 21:50:00470 DoCookieCallbackForURL(
471 base::BindOnce(
472 // base::Unretained is safe as DoCookieCallbackForURL stores
473 // the callback on |*this|, so the callback will not outlive
474 // the object.
475 &CookieMonster::DeleteCookie, base::Unretained(this), url,
476 cookie_name, std::move(callback)),
477 url);
[email protected]218aa6a12011-09-13 17:38:38478}
479
mmenke24379d52016-02-05 23:50:17480void CookieMonster::DeleteCanonicalCookieAsync(const CanonicalCookie& cookie,
rdsmith7ac81712017-06-22 17:09:54481 DeleteCallback 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::DeleteCanonicalCookie, base::Unretained(this), cookie,
487 std::move(callback)));
mmenke24379d52016-02-05 23:50:17488}
489
rdsmith7ac81712017-06-22 17:09:54490void CookieMonster::DeleteAllCreatedBetweenAsync(const Time& delete_begin,
491 const Time& delete_end,
492 DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00493 DoCookieCallback(base::BindOnce(
494 // base::Unretained is safe as DoCookieCallbackForURL stores
495 // the callback on |*this|, so the callback will not outlive
496 // the object.
497 &CookieMonster::DeleteAllCreatedBetween, base::Unretained(this),
498 delete_begin, delete_end, std::move(callback)));
mmenke74bcbd52016-01-21 17:17:56499}
500
dmurphfaea244c2016-04-09 00:42:30501void CookieMonster::DeleteAllCreatedBetweenWithPredicateAsync(
502 const Time& delete_begin,
503 const Time& delete_end,
504 const base::Callback<bool(const CanonicalCookie&)>& predicate,
rdsmith7ac81712017-06-22 17:09:54505 DeleteCallback callback) {
dmurphfaea244c2016-04-09 00:42:30506 if (predicate.is_null()) {
rdsmithe5c701d2017-07-12 21:50:00507 MaybeRunCookieCallback(std::move(callback), 0u);
dmurphfaea244c2016-04-09 00:42:30508 return;
509 }
rdsmithe5c701d2017-07-12 21:50:00510
511 DoCookieCallback(base::BindOnce(
512 // base::Unretained is safe as DoCookieCallbackForURL stores
513 // the callback on |*this|, so the callback will not outlive
514 // the object.
515 &CookieMonster::DeleteAllCreatedBetweenWithPredicate,
516 base::Unretained(this), delete_begin, delete_end, predicate,
517 std::move(callback)));
mmenke74bcbd52016-01-21 17:17:56518}
519
[email protected]264807b2012-04-25 14:49:37520void CookieMonster::DeleteSessionCookiesAsync(
rdsmith7ac81712017-06-22 17:09:54521 CookieStore::DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00522 DoCookieCallback(base::BindOnce(
523 // base::Unretained is safe as DoCookieCallbackForURL stores
524 // the callback on |*this|, so the callback will not outlive
525 // the object.
526 &CookieMonster::DeleteSessionCookies, base::Unretained(this),
527 std::move(callback)));
[email protected]264807b2012-04-25 14:49:37528}
529
mmenke18dd8ba2016-02-01 18:42:10530void CookieMonster::SetCookieableSchemes(
531 const std::vector<std::string>& schemes) {
mmenkebe0910d2016-03-01 19:09:09532 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56533
534 // Calls to this method will have no effect if made after a WebView or
535 // CookieManager instance has been created.
mmenke18dd8ba2016-02-01 18:42:10536 if (initialized_)
mmenke74bcbd52016-01-21 17:17:56537 return;
mmenke74bcbd52016-01-21 17:17:56538
mmenke18dd8ba2016-02-01 18:42:10539 cookieable_schemes_ = schemes;
mmenke74bcbd52016-01-21 17:17:56540}
541
mmenke74bcbd52016-01-21 17:17:56542// This function must be called before the CookieMonster is used.
543void CookieMonster::SetPersistSessionCookies(bool persist_session_cookies) {
mmenkebe0910d2016-03-01 19:09:09544 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56545 DCHECK(!initialized_);
546 persist_session_cookies_ = persist_session_cookies;
547}
548
549bool CookieMonster::IsCookieableScheme(const std::string& scheme) {
mmenkebe0910d2016-03-01 19:09:09550 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56551
tripta.gdda72022017-06-19 05:16:23552 return base::ContainsValue(cookieable_schemes_, scheme);
mmenke74bcbd52016-01-21 17:17:56553}
554
mmenke18dd8ba2016-02-01 18:42:10555const char* const CookieMonster::kDefaultCookieableSchemes[] = {"http", "https",
556 "ws", "wss"};
mmenke74bcbd52016-01-21 17:17:56557const int CookieMonster::kDefaultCookieableSchemesCount =
558 arraysize(kDefaultCookieableSchemes);
559
Victor Costan14f47c12018-03-01 08:02:24560CookieChangeDispatcher& CookieMonster::GetChangeDispatcher() {
561 return change_dispatcher_;
Randy Smithd32dc8c2017-08-30 18:03:40562}
563
nharper5babb5e62016-03-09 18:58:07564bool CookieMonster::IsEphemeral() {
565 return store_.get() == nullptr;
566}
567
mmenke74bcbd52016-01-21 17:17:56568CookieMonster::~CookieMonster() {
mmenkebe0910d2016-03-01 19:09:09569 DCHECK(thread_checker_.CalledOnValidThread());
mmenke05255cf2016-02-03 15:49:31570
Nick Harper14e23332017-07-28 00:27:23571 if (channel_id_service_ && store_) {
572 store_->SetBeforeFlushCallback(base::Closure());
573 }
574
Randy Smith0a522662017-08-30 19:35:34575 // TODO(mmenke): Does it really make sense to run
mmenke606c59c2016-03-07 18:20:55576 // CookieChanged callbacks when the CookieStore is destroyed?
mmenke05255cf2016-02-03 15:49:31577 for (CookieMap::iterator cookie_it = cookies_.begin();
578 cookie_it != cookies_.end();) {
579 CookieMap::iterator current_cookie_it = cookie_it;
580 ++cookie_it;
581 InternalDeleteCookie(current_cookie_it, false /* sync_to_store */,
582 DELETE_COOKIE_DONT_RECORD);
583 }
[email protected]85620342011-10-17 17:35:04584}
585
rdsmithe5c701d2017-07-12 21:50:00586void CookieMonster::GetAllCookies(GetCookieListCallback callback) {
mmenkebe0910d2016-03-01 19:09:09587 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40588
589 // This function is being called to scrape the cookie list for management UI
590 // or similar. We shouldn't show expired cookies in this list since it will
591 // just be confusing to users, and this function is called rarely enough (and
592 // is already slow enough) that it's OK to take the time to garbage collect
593 // the expired cookies now.
594 //
595 // Note that this does not prune cookies to be below our limits (if we've
596 // exceeded them) the way that calling GarbageCollect() would.
mkwstbe84af312015-02-20 08:52:45597 GarbageCollectExpired(
598 Time::Now(), CookieMapItPair(cookies_.begin(), cookies_.end()), NULL);
[email protected]f48b9432011-01-11 07:25:40599
600 // Copy the CanonicalCookie pointers from the map so that we can use the same
601 // sorter as elsewhere, then copy the result out.
602 std::vector<CanonicalCookie*> cookie_ptrs;
603 cookie_ptrs.reserve(cookies_.size());
avie7cd11a2016-10-11 02:00:35604 for (const auto& cookie : cookies_)
605 cookie_ptrs.push_back(cookie.second.get());
[email protected]f48b9432011-01-11 07:25:40606 std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
607
608 CookieList cookie_list;
609 cookie_list.reserve(cookie_ptrs.size());
vmpstr6d9996c82017-02-23 00:43:25610 for (auto* cookie_ptr : cookie_ptrs)
avie7cd11a2016-10-11 02:00:35611 cookie_list.push_back(*cookie_ptr);
[email protected]f48b9432011-01-11 07:25:40612
rdsmithe5c701d2017-07-12 21:50:00613 MaybeRunCookieCallback(std::move(callback), cookie_list);
[email protected]f325f1e12010-04-30 22:38:55614}
615
rdsmithe5c701d2017-07-12 21:50:00616void CookieMonster::GetCookieListWithOptions(const GURL& url,
617 const CookieOptions& options,
618 GetCookieListCallback callback) {
mmenkebe0910d2016-03-01 19:09:09619 DCHECK(thread_checker_.CalledOnValidThread());
initial.commit586acc5fe2008-07-26 22:42:52620
mkwstc611e6d2016-02-23 15:45:55621 CookieList cookies;
rdsmithe5c701d2017-07-12 21:50:00622 if (HasCookieableScheme(url)) {
623 std::vector<CanonicalCookie*> cookie_ptrs;
624 FindCookiesForHostAndDomain(url, options, &cookie_ptrs);
625 std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
mkwstc611e6d2016-02-23 15:45:55626
rdsmithe5c701d2017-07-12 21:50:00627 cookies.reserve(cookie_ptrs.size());
628 for (std::vector<CanonicalCookie*>::const_iterator it = cookie_ptrs.begin();
629 it != cookie_ptrs.end(); it++)
630 cookies.push_back(**it);
631 }
632 MaybeRunCookieCallback(std::move(callback), cookies);
initial.commit586acc5fe2008-07-26 22:42:52633}
634
rdsmithe5c701d2017-07-12 21:50:00635void CookieMonster::DeleteAllCreatedBetween(const Time& delete_begin,
636 const Time& delete_end,
637 DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09638 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]d0980332010-11-16 17:08:53639
rdsmitha5beda162017-07-08 13:55:42640 uint32_t num_deleted = 0;
[email protected]f48b9432011-01-11 07:25:40641 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
642 CookieMap::iterator curit = it;
avie7cd11a2016-10-11 02:00:35643 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:40644 ++it;
[email protected]d0980332010-11-16 17:08:53645
[email protected]f48b9432011-01-11 07:25:40646 if (cc->CreationDate() >= delete_begin &&
647 (delete_end.is_null() || cc->CreationDate() < delete_end)) {
mkwstbe84af312015-02-20 08:52:45648 InternalDeleteCookie(curit, true, /*sync_to_store*/
Nick Harper7a6683a2018-01-30 20:42:52649 DELETE_COOKIE_EXPLICIT);
[email protected]f48b9432011-01-11 07:25:40650 ++num_deleted;
initial.commit586acc5fe2008-07-26 22:42:52651 }
652 }
653
rdsmithe5c701d2017-07-12 21:50:00654 FlushStore(
655 base::BindOnce(&MayeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
656 callback ? base::BindOnce(std::move(callback), num_deleted)
657 : base::OnceClosure()));
[email protected]f48b9432011-01-11 07:25:40658}
659
rdsmithe5c701d2017-07-12 21:50:00660void CookieMonster::DeleteAllCreatedBetweenWithPredicate(
dmurphfaea244c2016-04-09 00:42:30661 const base::Time& delete_begin,
662 const base::Time& delete_end,
rdsmithe5c701d2017-07-12 21:50:00663 const base::Callback<bool(const CanonicalCookie&)>& predicate,
664 DeleteCallback callback) {
rdsmitha5beda162017-07-08 13:55:42665 uint32_t num_deleted = 0;
dmurphfaea244c2016-04-09 00:42:30666 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
667 CookieMap::iterator curit = it;
avie7cd11a2016-10-11 02:00:35668 CanonicalCookie* cc = curit->second.get();
dmurphfaea244c2016-04-09 00:42:30669 ++it;
[email protected]f48b9432011-01-11 07:25:40670
dmurphfaea244c2016-04-09 00:42:30671 if (cc->CreationDate() >= delete_begin &&
[email protected]d8428d52013-08-07 06:58:25672 // The assumption that null |delete_end| is equivalent to
673 // Time::Max() is confusing.
dmurphfaea244c2016-04-09 00:42:30674 (delete_end.is_null() || cc->CreationDate() < delete_end) &&
675 predicate.Run(*cc)) {
676 InternalDeleteCookie(curit, true, /*sync_to_store*/
Nick Harper7a6683a2018-01-30 20:42:52677 DELETE_COOKIE_EXPLICIT);
dmurphfaea244c2016-04-09 00:42:30678 ++num_deleted;
[email protected]f48b9432011-01-11 07:25:40679 }
680 }
dmurphfaea244c2016-04-09 00:42:30681
rdsmithe5c701d2017-07-12 21:50:00682 FlushStore(
683 base::BindOnce(&MayeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
684 callback ? base::BindOnce(std::move(callback), num_deleted)
685 : base::OnceClosure()));
[email protected]f48b9432011-01-11 07:25:40686}
687
rdsmithe5c701d2017-07-12 21:50:00688void CookieMonster::SetCookieWithOptions(const GURL& url,
[email protected]f48b9432011-01-11 07:25:40689 const std::string& cookie_line,
rdsmithe5c701d2017-07-12 21:50:00690 const CookieOptions& options,
691 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:09692 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40693
694 if (!HasCookieableScheme(url)) {
rdsmithe5c701d2017-07-12 21:50:00695 MaybeRunCookieCallback(std::move(callback), false);
696 return;
[email protected]f48b9432011-01-11 07:25:40697 }
698
Maks Orlovicha61ed022018-03-01 18:24:24699 VLOG(kVlogSetCookies) << "SetCookie() line: " << cookie_line;
700
701 Time creation_time = CurrentTime();
702 last_time_seen_ = creation_time;
703
704 std::unique_ptr<CanonicalCookie> cc(
705 CanonicalCookie::Create(url, cookie_line, creation_time, options));
706
707 if (!cc.get()) {
708 VLOG(kVlogSetCookies) << "WARNING: Failed to allocate CanonicalCookie";
709 MaybeRunCookieCallback(std::move(callback), false);
710 return;
711 }
712 SetCanonicalCookie(std::move(cc), url.SchemeIsCryptographic(),
713 !options.exclude_httponly(), std::move(callback));
[email protected]f48b9432011-01-11 07:25:40714}
715
[email protected]f48b9432011-01-11 07:25:40716void CookieMonster::DeleteCookie(const GURL& url,
rdsmithe5c701d2017-07-12 21:50:00717 const std::string& cookie_name,
718 base::OnceClosure callback) {
mmenkebe0910d2016-03-01 19:09:09719 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40720
rdsmithe5c701d2017-07-12 21:50:00721 if (!HasCookieableScheme(url)) {
722 // TODO(rdsmith): Would be good to provide a failure indication here.
723 MaybeRunCookieCallback(std::move(callback));
[email protected]f48b9432011-01-11 07:25:40724 return;
rdsmithe5c701d2017-07-12 21:50:00725 }
[email protected]f48b9432011-01-11 07:25:40726
727 CookieOptions options;
728 options.set_include_httponly();
mkwstf71d0bd2016-03-21 14:15:24729 options.set_same_site_cookie_mode(
730 CookieOptions::SameSiteCookieMode::INCLUDE_STRICT_AND_LAX);
[email protected]f48b9432011-01-11 07:25:40731 // Get the cookies for this host and its domain(s).
732 std::vector<CanonicalCookie*> cookies;
mkwst72b65162016-02-22 19:58:54733 FindCookiesForHostAndDomain(url, options, &cookies);
[email protected]f48b9432011-01-11 07:25:40734 std::set<CanonicalCookie*> matching_cookies;
735
vmpstr6f21f242016-06-29 02:16:47736 for (auto* cookie : cookies) {
mmenke4379aeb2016-03-05 12:22:07737 if (cookie->Name() != cookie_name)
[email protected]f48b9432011-01-11 07:25:40738 continue;
mmenke4379aeb2016-03-05 12:22:07739 if (!cookie->IsOnPath(url.path()))
[email protected]f48b9432011-01-11 07:25:40740 continue;
mmenke4379aeb2016-03-05 12:22:07741 matching_cookies.insert(cookie);
[email protected]f48b9432011-01-11 07:25:40742 }
743
744 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
745 CookieMap::iterator curit = it;
746 ++it;
avie7cd11a2016-10-11 02:00:35747 if (matching_cookies.find(curit->second.get()) != matching_cookies.end()) {
Nick Harper7a6683a2018-01-30 20:42:52748 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPLICIT);
[email protected]f48b9432011-01-11 07:25:40749 }
750 }
rdsmithe5c701d2017-07-12 21:50:00751
752 FlushStore(base::BindOnce(&MayeRunDeleteCallback,
753 weak_ptr_factory_.GetWeakPtr(),
754 // No callback null check needed as BindOnce
755 // is not being called and MaybeRunDeleteCallback
756 // has its own check.
757 std::move(callback)));
[email protected]f48b9432011-01-11 07:25:40758}
759
rdsmithe5c701d2017-07-12 21:50:00760void CookieMonster::DeleteCanonicalCookie(const CanonicalCookie& cookie,
761 DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09762 DCHECK(thread_checker_.CalledOnValidThread());
mmenke24379d52016-02-05 23:50:17763
rdsmithe5c701d2017-07-12 21:50:00764 uint32_t result = 0u;
mmenke24379d52016-02-05 23:50:17765 for (CookieMapItPair its = cookies_.equal_range(GetKey(cookie.Domain()));
766 its.first != its.second; ++its.first) {
767 // The creation date acts as the unique index...
768 if (its.first->second->CreationDate() == cookie.CreationDate()) {
Nick Harper7a6683a2018-01-30 20:42:52769 InternalDeleteCookie(its.first, true, DELETE_COOKIE_EXPLICIT);
rdsmithe5c701d2017-07-12 21:50:00770 result = 1u;
771 break;
mmenke24379d52016-02-05 23:50:17772 }
773 }
rdsmithe5c701d2017-07-12 21:50:00774 FlushStore(
775 base::BindOnce(&MayeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
776 callback ? base::BindOnce(std::move(callback), result)
777 : base::OnceClosure()));
mmenke24379d52016-02-05 23:50:17778}
779
rdsmithe5c701d2017-07-12 21:50:00780void CookieMonster::DeleteSessionCookies(DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09781 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]264807b2012-04-25 14:49:37782
rdsmitha5beda162017-07-08 13:55:42783 uint32_t num_deleted = 0;
[email protected]264807b2012-04-25 14:49:37784 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
785 CookieMap::iterator curit = it;
avie7cd11a2016-10-11 02:00:35786 CanonicalCookie* cc = curit->second.get();
[email protected]264807b2012-04-25 14:49:37787 ++it;
788
789 if (!cc->IsPersistent()) {
mkwstbe84af312015-02-20 08:52:45790 InternalDeleteCookie(curit, true, /*sync_to_store*/
[email protected]264807b2012-04-25 14:49:37791 DELETE_COOKIE_EXPIRED);
792 ++num_deleted;
793 }
794 }
795
rdsmithe5c701d2017-07-12 21:50:00796 FlushStore(
797 base::BindOnce(&MayeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
798 callback ? base::BindOnce(std::move(callback), num_deleted)
799 : base::OnceClosure()));
[email protected]264807b2012-04-25 14:49:37800}
801
erikchen1dd72a72015-05-06 20:45:05802void CookieMonster::MarkCookieStoreAsInitialized() {
mmenkebe0910d2016-03-01 19:09:09803 DCHECK(thread_checker_.CalledOnValidThread());
erikchen1dd72a72015-05-06 20:45:05804 initialized_ = true;
805}
806
807void CookieMonster::FetchAllCookiesIfNecessary() {
mmenkebe0910d2016-03-01 19:09:09808 DCHECK(thread_checker_.CalledOnValidThread());
erikchen1dd72a72015-05-06 20:45:05809 if (store_.get() && !started_fetching_all_cookies_) {
810 started_fetching_all_cookies_ = true;
811 FetchAllCookies();
812 }
813}
814
mmenke74bcbd52016-01-21 17:17:56815void CookieMonster::FetchAllCookies() {
mmenkebe0910d2016-03-01 19:09:09816 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56817 DCHECK(store_.get()) << "Store must exist to initialize";
818 DCHECK(!finished_fetching_all_cookies_)
819 << "All cookies have already been fetched.";
820
821 // We bind in the current time so that we can report the wall-clock time for
822 // loading cookies.
mmenkebe0910d2016-03-01 19:09:09823 store_->Load(base::Bind(&CookieMonster::OnLoaded,
Thomas Anderson1a03bbe2018-03-02 19:05:47824 weak_ptr_factory_.GetWeakPtr(), TimeTicks::Now()));
mmenke74bcbd52016-01-21 17:17:56825}
826
avie7cd11a2016-10-11 02:00:35827void CookieMonster::OnLoaded(
828 TimeTicks beginning_time,
829 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:09830 DCHECK(thread_checker_.CalledOnValidThread());
avie7cd11a2016-10-11 02:00:35831 StoreLoadedCookies(std::move(cookies));
[email protected]c7593fb22011-11-14 23:54:27832 histogram_time_blocked_on_load_->AddTime(TimeTicks::Now() - beginning_time);
[email protected]218aa6a12011-09-13 17:38:38833
834 // Invoke the task queue of cookie request.
835 InvokeQueue();
836}
837
avie7cd11a2016-10-11 02:00:35838void CookieMonster::OnKeyLoaded(
839 const std::string& key,
840 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:09841 DCHECK(thread_checker_.CalledOnValidThread());
842
avie7cd11a2016-10-11 02:00:35843 StoreLoadedCookies(std::move(cookies));
[email protected]85620342011-10-17 17:35:04844
mmenkebe0910d2016-03-01 19:09:09845 auto tasks_pending_for_key = tasks_pending_for_key_.find(key);
[email protected]85620342011-10-17 17:35:04846
mmenkebe0910d2016-03-01 19:09:09847 // TODO(mmenke): Can this be turned into a DCHECK?
848 if (tasks_pending_for_key == tasks_pending_for_key_.end())
849 return;
[email protected]bab72ec2013-10-30 20:50:02850
mmenkebe0910d2016-03-01 19:09:09851 // Run all tasks for the key. Note that running a task can result in multiple
852 // tasks being added to the back of the deque.
853 while (!tasks_pending_for_key->second.empty()) {
rdsmithe5c701d2017-07-12 21:50:00854 base::OnceClosure task = std::move(tasks_pending_for_key->second.front());
mmenkebe0910d2016-03-01 19:09:09855 tasks_pending_for_key->second.pop_front();
rdsmithe5c701d2017-07-12 21:50:00856 std::move(task).Run();
[email protected]85620342011-10-17 17:35:04857 }
mmenkebe0910d2016-03-01 19:09:09858
859 tasks_pending_for_key_.erase(tasks_pending_for_key);
860
861 // This has to be done last, in case running a task queues a new task for the
862 // key, to ensure tasks are run in the correct order.
863 keys_loaded_.insert(key);
[email protected]85620342011-10-17 17:35:04864}
865
[email protected]218aa6a12011-09-13 17:38:38866void CookieMonster::StoreLoadedCookies(
avie7cd11a2016-10-11 02:00:35867 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:09868 DCHECK(thread_checker_.CalledOnValidThread());
869
mmenkebe0910d2016-03-01 19:09:09870 // Even if a key is expired, insert it so it can be garbage collected,
871 // removed, and sync'd.
[email protected]6210ce52013-09-20 03:33:14872 CookieItVector cookies_with_control_chars;
873
avie7cd11a2016-10-11 02:00:35874 for (auto& cookie : cookies) {
875 int64_t cookie_creation_time = cookie->CreationDate().ToInternalValue();
[email protected]f48b9432011-01-11 07:25:40876
[email protected]85620342011-10-17 17:35:04877 if (creation_times_.insert(cookie_creation_time).second) {
avie7cd11a2016-10-11 02:00:35878 CanonicalCookie* cookie_ptr = cookie.get();
879 CookieMap::iterator inserted = InternalInsertCookie(
rdsmith2709eee2017-06-20 22:43:27880 GetKey(cookie_ptr->Domain()), std::move(cookie), false);
avie7cd11a2016-10-11 02:00:35881 const Time cookie_access_time(cookie_ptr->LastAccessDate());
[email protected]85620342011-10-17 17:35:04882 if (earliest_access_time_.is_null() ||
883 cookie_access_time < earliest_access_time_)
884 earliest_access_time_ = cookie_access_time;
[email protected]6210ce52013-09-20 03:33:14885
avie7cd11a2016-10-11 02:00:35886 if (ContainsControlCharacter(cookie_ptr->Name()) ||
887 ContainsControlCharacter(cookie_ptr->Value())) {
mkwstbe84af312015-02-20 08:52:45888 cookies_with_control_chars.push_back(inserted);
[email protected]6210ce52013-09-20 03:33:14889 }
[email protected]f48b9432011-01-11 07:25:40890 } else {
mkwstbe84af312015-02-20 08:52:45891 LOG(ERROR) << base::StringPrintf(
892 "Found cookies with duplicate creation "
893 "times in backing store: "
894 "{name='%s', domain='%s', path='%s'}",
avie7cd11a2016-10-11 02:00:35895 cookie->Name().c_str(), cookie->Domain().c_str(),
896 cookie->Path().c_str());
[email protected]f48b9432011-01-11 07:25:40897 }
898 }
[email protected]f48b9432011-01-11 07:25:40899
[email protected]6210ce52013-09-20 03:33:14900 // Any cookies that contain control characters that we have loaded from the
901 // persistent store should be deleted. See http://crbug.com/238041.
902 for (CookieItVector::iterator it = cookies_with_control_chars.begin();
903 it != cookies_with_control_chars.end();) {
904 CookieItVector::iterator curit = it;
905 ++it;
906
907 InternalDeleteCookie(*curit, true, DELETE_COOKIE_CONTROL_CHAR);
908 }
909
[email protected]f48b9432011-01-11 07:25:40910 // After importing cookies from the PersistentCookieStore, verify that
911 // none of our other constraints are violated.
[email protected]f48b9432011-01-11 07:25:40912 // In particular, the backing store might have given us duplicate cookies.
[email protected]85620342011-10-17 17:35:04913
914 // This method could be called multiple times due to priority loading, thus
915 // cookies loaded in previous runs will be validated again, but this is OK
916 // since they are expected to be much fewer than total DB.
[email protected]f48b9432011-01-11 07:25:40917 EnsureCookiesMapIsValid();
[email protected]218aa6a12011-09-13 17:38:38918}
[email protected]f48b9432011-01-11 07:25:40919
[email protected]218aa6a12011-09-13 17:38:38920void CookieMonster::InvokeQueue() {
mmenkebe0910d2016-03-01 19:09:09921 DCHECK(thread_checker_.CalledOnValidThread());
922
mmenkef49fca0e2016-03-08 12:46:24923 // Move all per-key tasks into the global queue, if there are any. This is
924 // protection about a race where the store learns about all cookies loading
925 // before it learned about the cookies for a key loading.
926
927 // Needed to prevent any recursively queued tasks from going back into the
928 // per-key queues.
929 seen_global_task_ = true;
rdsmithe5c701d2017-07-12 21:50:00930 for (auto& tasks_for_key : tasks_pending_for_key_) {
931 tasks_pending_.insert(tasks_pending_.begin(),
932 std::make_move_iterator(tasks_for_key.second.begin()),
933 std::make_move_iterator(tasks_for_key.second.end()));
mmenkef49fca0e2016-03-08 12:46:24934 }
935 tasks_pending_for_key_.clear();
936
mmenkebe0910d2016-03-01 19:09:09937 while (!tasks_pending_.empty()) {
rdsmithe5c701d2017-07-12 21:50:00938 base::OnceClosure request_task = std::move(tasks_pending_.front());
mmenkef49fca0e2016-03-08 12:46:24939 tasks_pending_.pop_front();
rdsmithe5c701d2017-07-12 21:50:00940 std::move(request_task).Run();
[email protected]218aa6a12011-09-13 17:38:38941 }
mmenkebe0910d2016-03-01 19:09:09942
mmenkef49fca0e2016-03-08 12:46:24943 DCHECK(tasks_pending_for_key_.empty());
944
mmenkebe0910d2016-03-01 19:09:09945 finished_fetching_all_cookies_ = true;
946 creation_times_.clear();
947 keys_loaded_.clear();
[email protected]f48b9432011-01-11 07:25:40948}
949
950void CookieMonster::EnsureCookiesMapIsValid() {
mmenkebe0910d2016-03-01 19:09:09951 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40952
[email protected]f48b9432011-01-11 07:25:40953 // Iterate through all the of the cookies, grouped by host.
954 CookieMap::iterator prev_range_end = cookies_.begin();
955 while (prev_range_end != cookies_.end()) {
956 CookieMap::iterator cur_range_begin = prev_range_end;
957 const std::string key = cur_range_begin->first; // Keep a copy.
958 CookieMap::iterator cur_range_end = cookies_.upper_bound(key);
959 prev_range_end = cur_range_end;
960
961 // Ensure no equivalent cookies for this host.
ellyjonescabf57422015-08-21 18:44:51962 TrimDuplicateCookiesForKey(key, cur_range_begin, cur_range_end);
[email protected]f48b9432011-01-11 07:25:40963 }
[email protected]f48b9432011-01-11 07:25:40964}
965
ellyjonescabf57422015-08-21 18:44:51966void CookieMonster::TrimDuplicateCookiesForKey(const std::string& key,
967 CookieMap::iterator begin,
968 CookieMap::iterator end) {
mmenkebe0910d2016-03-01 19:09:09969 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40970
971 // Set of cookies ordered by creation time.
972 typedef std::set<CookieMap::iterator, OrderByCreationTimeDesc> CookieSet;
973
974 // Helper map we populate to find the duplicates.
975 typedef std::map<CookieSignature, CookieSet> EquivalenceMap;
976 EquivalenceMap equivalent_cookies;
977
978 // The number of duplicate cookies that have been found.
979 int num_duplicates = 0;
980
981 // Iterate through all of the cookies in our range, and insert them into
982 // the equivalence map.
983 for (CookieMap::iterator it = begin; it != end; ++it) {
984 DCHECK_EQ(key, it->first);
avie7cd11a2016-10-11 02:00:35985 CanonicalCookie* cookie = it->second.get();
[email protected]f48b9432011-01-11 07:25:40986
mkwstbe84af312015-02-20 08:52:45987 CookieSignature signature(cookie->Name(), cookie->Domain(), cookie->Path());
[email protected]f48b9432011-01-11 07:25:40988 CookieSet& set = equivalent_cookies[signature];
989
990 // We found a duplicate!
991 if (!set.empty())
992 num_duplicates++;
993
994 // We save the iterator into |cookies_| rather than the actual cookie
995 // pointer, since we may need to delete it later.
996 bool insert_success = set.insert(it).second;
mkwstbe84af312015-02-20 08:52:45997 DCHECK(insert_success)
998 << "Duplicate creation times found in duplicate cookie name scan.";
[email protected]f48b9432011-01-11 07:25:40999 }
1000
1001 // If there were no duplicates, we are done!
1002 if (num_duplicates == 0)
ellyjonescabf57422015-08-21 18:44:511003 return;
[email protected]f48b9432011-01-11 07:25:401004
1005 // Make sure we find everything below that we did above.
1006 int num_duplicates_found = 0;
1007
1008 // Otherwise, delete all the duplicate cookies, both from our in-memory store
1009 // and from the backing store.
1010 for (EquivalenceMap::iterator it = equivalent_cookies.begin();
mkwstbe84af312015-02-20 08:52:451011 it != equivalent_cookies.end(); ++it) {
[email protected]f48b9432011-01-11 07:25:401012 const CookieSignature& signature = it->first;
1013 CookieSet& dupes = it->second;
1014
1015 if (dupes.size() <= 1)
1016 continue; // This cookiename/path has no duplicates.
1017 num_duplicates_found += dupes.size() - 1;
1018
1019 // Since |dups| is sorted by creation time (descending), the first cookie
1020 // is the most recent one, so we will keep it. The rest are duplicates.
1021 dupes.erase(dupes.begin());
1022
1023 LOG(ERROR) << base::StringPrintf(
1024 "Found %d duplicate cookies for host='%s', "
1025 "with {name='%s', domain='%s', path='%s'}",
mkwstbe84af312015-02-20 08:52:451026 static_cast<int>(dupes.size()), key.c_str(), signature.name.c_str(),
1027 signature.domain.c_str(), signature.path.c_str());
[email protected]f48b9432011-01-11 07:25:401028
1029 // Remove all the cookies identified by |dupes|. It is valid to delete our
1030 // list of iterators one at a time, since |cookies_| is a multimap (they
1031 // don't invalidate existing iterators following deletion).
mkwstbe84af312015-02-20 08:52:451032 for (CookieSet::iterator dupes_it = dupes.begin(); dupes_it != dupes.end();
[email protected]f48b9432011-01-11 07:25:401033 ++dupes_it) {
[email protected]218aa6a12011-09-13 17:38:381034 InternalDeleteCookie(*dupes_it, true,
[email protected]f48b9432011-01-11 07:25:401035 DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE);
1036 }
1037 }
1038 DCHECK_EQ(num_duplicates, num_duplicates_found);
[email protected]f48b9432011-01-11 07:25:401039}
1040
[email protected]f48b9432011-01-11 07:25:401041void CookieMonster::FindCookiesForHostAndDomain(
1042 const GURL& url,
1043 const CookieOptions& options,
[email protected]f48b9432011-01-11 07:25:401044 std::vector<CanonicalCookie*>* cookies) {
mmenkebe0910d2016-03-01 19:09:091045 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401046
1047 const Time current_time(CurrentTime());
1048
1049 // Probe to save statistics relatively frequently. We do it here rather
1050 // than in the set path as many websites won't set cookies, and we
1051 // want to collect statistics whenever the browser's being used.
1052 RecordPeriodicStats(current_time);
1053
[email protected]8e1583672012-02-11 04:39:411054 // Can just dispatch to FindCookiesForKey
Maks Orlovich323efaf2018-03-06 02:56:391055 const std::string key(GetKey(url.host_piece()));
mkwst72b65162016-02-22 19:58:541056 FindCookiesForKey(key, url, options, current_time, cookies);
[email protected]f48b9432011-01-11 07:25:401057}
1058
[email protected]dedec0b2013-02-28 04:50:101059void CookieMonster::FindCookiesForKey(const std::string& key,
1060 const GURL& url,
1061 const CookieOptions& options,
1062 const Time& current,
[email protected]dedec0b2013-02-28 04:50:101063 std::vector<CanonicalCookie*>* cookies) {
mmenkebe0910d2016-03-01 19:09:091064 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401065
[email protected]f48b9432011-01-11 07:25:401066 for (CookieMapItPair its = cookies_.equal_range(key);
mkwstbe84af312015-02-20 08:52:451067 its.first != its.second;) {
[email protected]f48b9432011-01-11 07:25:401068 CookieMap::iterator curit = its.first;
avie7cd11a2016-10-11 02:00:351069 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:401070 ++its.first;
1071
1072 // If the cookie is expired, delete it.
mmenke3c79a652016-02-12 14:39:201073 if (cc->IsExpired(current)) {
[email protected]f48b9432011-01-11 07:25:401074 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
1075 continue;
1076 }
1077
[email protected]65f4e7e2012-12-12 21:56:541078 // Filter out cookies that should not be included for a request to the
1079 // given |url|. HTTP only cookies are filtered depending on the passed
1080 // cookie |options|.
1081 if (!cc->IncludeForRequestURL(url, options))
[email protected]f48b9432011-01-11 07:25:401082 continue;
1083
[email protected]65f4e7e2012-12-12 21:56:541084 // Add this cookie to the set of matching cookies. Update the access
[email protected]f48b9432011-01-11 07:25:401085 // time if we've been requested to do so.
mkwst72b65162016-02-22 19:58:541086 if (options.update_access_time()) {
[email protected]f48b9432011-01-11 07:25:401087 InternalUpdateCookieAccessTime(cc, current);
1088 }
1089 cookies->push_back(cc);
1090 }
1091}
1092
Mike Westc4a777b2017-10-06 14:04:201093bool CookieMonster::DeleteAnyEquivalentCookie(
1094 const std::string& key,
1095 const CanonicalCookie& ecc,
1096 bool source_secure,
1097 bool skip_httponly,
1098 bool already_expired,
1099 base::Time* creation_date_to_inherit) {
mmenkebe0910d2016-03-01 19:09:091100 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401101
1102 bool found_equivalent_cookie = false;
1103 bool skipped_httponly = false;
jww601411a2015-11-20 19:46:571104 bool skipped_secure_cookie = false;
jww31e32632015-12-16 23:38:341105
1106 histogram_cookie_delete_equivalent_->Add(COOKIE_DELETE_EQUIVALENT_ATTEMPT);
1107
[email protected]f48b9432011-01-11 07:25:401108 for (CookieMapItPair its = cookies_.equal_range(key);
mkwstbe84af312015-02-20 08:52:451109 its.first != its.second;) {
[email protected]f48b9432011-01-11 07:25:401110 CookieMap::iterator curit = its.first;
avie7cd11a2016-10-11 02:00:351111 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:401112 ++its.first;
1113
jwwa26e439d2017-01-27 18:17:271114 // If the cookie is being set from an insecure scheme, then if a cookie
1115 // already exists with the same name and it is Secure, then the cookie
1116 // should *not* be updated if they domain-match and ignoring the path
1117 // attribute.
jww601411a2015-11-20 19:46:571118 //
jwwa26e439d2017-01-27 18:17:271119 // See: https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone
rdsmith2709eee2017-06-20 22:43:271120 if (cc->IsSecure() && !source_secure &&
mmenke2830b0722016-07-20 16:02:501121 ecc.IsEquivalentForSecureCookieMatching(*cc)) {
jww601411a2015-11-20 19:46:571122 skipped_secure_cookie = true;
jww31e32632015-12-16 23:38:341123 histogram_cookie_delete_equivalent_->Add(
1124 COOKIE_DELETE_EQUIVALENT_SKIPPING_SECURE);
1125 // If the cookie is equivalent to the new cookie and wouldn't have been
1126 // skipped for being HTTP-only, record that it is a skipped secure cookie
1127 // that would have been deleted otherwise.
1128 if (ecc.IsEquivalent(*cc)) {
jwwa9a0d482015-12-16 18:19:411129 found_equivalent_cookie = true;
jww31e32632015-12-16 23:38:341130
1131 if (!skip_httponly || !cc->IsHttpOnly()) {
1132 histogram_cookie_delete_equivalent_->Add(
1133 COOKIE_DELETE_EQUIVALENT_WOULD_HAVE_DELETED);
1134 }
1135 }
jww601411a2015-11-20 19:46:571136 } else if (ecc.IsEquivalent(*cc)) {
[email protected]f48b9432011-01-11 07:25:401137 // We should never have more than one equivalent cookie, since they should
jww601411a2015-11-20 19:46:571138 // overwrite each other, unless secure cookies require secure scheme is
1139 // being enforced. In that case, cookies with different paths might exist
1140 // and be considered equivalent.
mkwstbe84af312015-02-20 08:52:451141 CHECK(!found_equivalent_cookie)
1142 << "Duplicate equivalent cookies found, cookie store is corrupted.";
[email protected]f48b9432011-01-11 07:25:401143 if (skip_httponly && cc->IsHttpOnly()) {
1144 skipped_httponly = true;
1145 } else {
jww31e32632015-12-16 23:38:341146 histogram_cookie_delete_equivalent_->Add(
1147 COOKIE_DELETE_EQUIVALENT_FOUND);
Mike West86149882017-07-28 10:41:491148 if (cc->Value() == ecc.Value()) {
Mike Westc4a777b2017-10-06 14:04:201149 *creation_date_to_inherit = cc->CreationDate();
Mike West86149882017-07-28 10:41:491150 histogram_cookie_delete_equivalent_->Add(
1151 COOKIE_DELETE_EQUIVALENT_FOUND_WITH_SAME_VALUE);
1152 }
mkwstbe84af312015-02-20 08:52:451153 InternalDeleteCookie(curit, true, already_expired
1154 ? DELETE_COOKIE_EXPIRED_OVERWRITE
1155 : DELETE_COOKIE_OVERWRITE);
[email protected]f48b9432011-01-11 07:25:401156 }
1157 found_equivalent_cookie = true;
1158 }
1159 }
jww601411a2015-11-20 19:46:571160 return skipped_httponly || skipped_secure_cookie;
[email protected]f48b9432011-01-11 07:25:401161}
1162
[email protected]6210ce52013-09-20 03:33:141163CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie(
1164 const std::string& key,
avie7cd11a2016-10-11 02:00:351165 std::unique_ptr<CanonicalCookie> cc,
[email protected]6210ce52013-09-20 03:33:141166 bool sync_to_store) {
mmenkebe0910d2016-03-01 19:09:091167 DCHECK(thread_checker_.CalledOnValidThread());
avie7cd11a2016-10-11 02:00:351168 CanonicalCookie* cc_ptr = cc.get();
mmenkebe0910d2016-03-01 19:09:091169
avie7cd11a2016-10-11 02:00:351170 if ((cc_ptr->IsPersistent() || persist_session_cookies_) && store_.get() &&
[email protected]90499482013-06-01 00:39:501171 sync_to_store)
avie7cd11a2016-10-11 02:00:351172 store_->AddCookie(*cc_ptr);
[email protected]6210ce52013-09-20 03:33:141173 CookieMap::iterator inserted =
avie7cd11a2016-10-11 02:00:351174 cookies_.insert(CookieMap::value_type(key, std::move(cc)));
mkwstc1aa4cc2015-04-03 19:57:451175
1176 // See InitializeHistograms() for details.
avie7cd11a2016-10-11 02:00:351177 int32_t type_sample = cc_ptr->SameSite() != CookieSameSite::NO_RESTRICTION
mkwste1a29582016-03-15 10:07:521178 ? 1 << COOKIE_TYPE_SAME_SITE
1179 : 0;
avie7cd11a2016-10-11 02:00:351180 type_sample |= cc_ptr->IsHttpOnly() ? 1 << COOKIE_TYPE_HTTPONLY : 0;
1181 type_sample |= cc_ptr->IsSecure() ? 1 << COOKIE_TYPE_SECURE : 0;
mkwst46549412016-02-01 10:05:371182 histogram_cookie_type_->Add(type_sample);
estark7feb65c2b2015-08-21 23:38:201183
Victor Costan14f47c12018-03-01 08:02:241184 change_dispatcher_.DispatchChange(*cc_ptr, CookieChangeCause::INSERTED, true);
[email protected]6210ce52013-09-20 03:33:141185
1186 return inserted;
[email protected]f48b9432011-01-11 07:25:401187}
1188
rdsmithe5c701d2017-07-12 21:50:001189void CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc,
rdsmith2709eee2017-06-20 22:43:271190 bool secure_source,
rdsmithe5c701d2017-07-12 21:50:001191 bool modify_http_only,
1192 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:091193 DCHECK(thread_checker_.CalledOnValidThread());
1194
Randy Smith10400072017-08-03 04:08:311195 if ((cc->IsSecure() && !secure_source) ||
1196 (cc->IsHttpOnly() && !modify_http_only)) {
rdsmithe5c701d2017-07-12 21:50:001197 MaybeRunCookieCallback(std::move(callback), false);
1198 return;
1199 }
rdsmith2709eee2017-06-20 22:43:271200
mmenkeea4cd402016-02-02 04:03:101201 const std::string key(GetKey(cc->Domain()));
rdsmitha6ce4442017-06-21 17:11:051202
1203 // TODO(mmenke): This class assumes each cookie to have a unique creation
1204 // time. Allowing the caller to set the creation time violates that
1205 // assumption. Worth fixing? Worth noting that time changes between browser
1206 // restarts can cause the same issue.
1207 base::Time creation_date = cc->CreationDate();
1208 if (creation_date.is_null()) {
1209 creation_date = CurrentTime();
1210 cc->SetCreationDate(creation_date);
1211 last_time_seen_ = creation_date;
1212 }
1213 bool already_expired = cc->IsExpired(creation_date);
ellyjones399e35a22014-10-27 11:09:561214
Mike Westc4a777b2017-10-06 14:04:201215 base::Time creation_date_to_inherit;
rdsmith2709eee2017-06-20 22:43:271216 if (DeleteAnyEquivalentCookie(key, *cc, secure_source, !modify_http_only,
Mike Westc4a777b2017-10-06 14:04:201217 already_expired, &creation_date_to_inherit)) {
jww601411a2015-11-20 19:46:571218 std::string error;
jwwa26e439d2017-01-27 18:17:271219 error =
1220 "SetCookie() not clobbering httponly cookie or secure cookie for "
1221 "insecure scheme";
jww601411a2015-11-20 19:46:571222
1223 VLOG(kVlogSetCookies) << error;
rdsmithe5c701d2017-07-12 21:50:001224 MaybeRunCookieCallback(std::move(callback), false);
1225 return;
[email protected]3a96c742008-11-19 19:46:271226 }
initial.commit586acc5fe2008-07-26 22:42:521227
mkwstbe84af312015-02-20 08:52:451228 VLOG(kVlogSetCookies) << "SetCookie() key: " << key
mmenkeea4cd402016-02-02 04:03:101229 << " cc: " << cc->DebugString();
initial.commit586acc5fe2008-07-26 22:42:521230
1231 // Realize that we might be setting an expired cookie, and the only point
1232 // was to delete the cookie which we've already done.
mmenke3c79a652016-02-12 14:39:201233 if (!already_expired) {
[email protected]374f58b2010-07-20 15:29:261234 // See InitializeHistograms() for details.
mmenkeea4cd402016-02-02 04:03:101235 if (cc->IsPersistent()) {
[email protected]8475bee2011-03-17 18:40:241236 histogram_expiration_duration_minutes_->Add(
rdsmitha6ce4442017-06-21 17:11:051237 (cc->ExpiryDate() - creation_date).InMinutes());
[email protected]8475bee2011-03-17 18:40:241238 }
1239
rdsmith2709eee2017-06-20 22:43:271240 // Histogram the type of scheme used on URLs that set cookies. This
1241 // intentionally includes cookies that are set or overwritten by
1242 // http:// URLs, but not cookies that are cleared by http:// URLs, to
1243 // understand if the former behavior can be deprecated for Secure
1244 // cookies.
1245 CookieSource cookie_source_sample =
1246 (secure_source
1247 ? (cc->IsSecure()
1248 ? COOKIE_SOURCE_SECURE_COOKIE_CRYPTOGRAPHIC_SCHEME
1249 : COOKIE_SOURCE_NONSECURE_COOKIE_CRYPTOGRAPHIC_SCHEME)
1250 : (cc->IsSecure()
1251 ? COOKIE_SOURCE_SECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME
1252 : COOKIE_SOURCE_NONSECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME));
1253 histogram_cookie_source_scheme_->Add(cookie_source_sample);
1254
Mike Westc4a777b2017-10-06 14:04:201255 if (!creation_date_to_inherit.is_null()) {
1256 cc->SetCreationDate(creation_date_to_inherit);
1257 // |last_time_seen_| is intentionally not updated, as moving it into the
1258 // past might cause duplicate cookie creation dates. See
1259 // `CookieMonster::CurrentTime()` for details.
1260 }
1261
rdsmith2709eee2017-06-20 22:43:271262 InternalInsertCookie(key, std::move(cc), true);
[email protected]348dd662013-03-13 20:25:071263 } else {
1264 VLOG(kVlogSetCookies) << "SetCookie() not storing already expired cookie.";
[email protected]c4058fb2010-06-22 17:25:261265 }
initial.commit586acc5fe2008-07-26 22:42:521266
1267 // We assume that hopefully setting a cookie will be less common than
1268 // querying a cookie. Since setting a cookie can put us over our limits,
1269 // make sure that we garbage collect... We can also make the assumption that
1270 // if a cookie was set, in the common case it will be used soon after,
1271 // and we will purge the expired cookies in GetCookies().
rdsmitha6ce4442017-06-21 17:11:051272 GarbageCollect(creation_date, key);
initial.commit586acc5fe2008-07-26 22:42:521273
rdsmithe5c701d2017-07-12 21:50:001274 MaybeRunCookieCallback(std::move(callback), true);
initial.commit586acc5fe2008-07-26 22:42:521275}
1276
rdsmithe5c701d2017-07-12 21:50:001277void CookieMonster::SetAllCookies(CookieList list,
1278 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:091279 DCHECK(thread_checker_.CalledOnValidThread());
rdsmithe5c701d2017-07-12 21:50:001280
rdsmith0e84cea2017-07-13 03:09:531281 // Nuke the existing store.
1282 while (!cookies_.empty()) {
1283 // TODO(rdsmith): The CANONICAL is a lie.
Nick Harper7a6683a2018-01-30 20:42:521284 InternalDeleteCookie(cookies_.begin(), true, DELETE_COOKIE_EXPLICIT);
rdsmithe5c701d2017-07-12 21:50:001285 }
1286
rdsmith0e84cea2017-07-13 03:09:531287 // Set all passed in cookies.
mmenkeea4cd402016-02-02 04:03:101288 for (const auto& cookie : list) {
rdsmith2709eee2017-06-20 22:43:271289 const std::string key(GetKey(cookie.Domain()));
1290 Time creation_time = cookie.CreationDate();
rdsmith0e84cea2017-07-13 03:09:531291 if (cookie.IsExpired(creation_time))
rdsmith2709eee2017-06-20 22:43:271292 continue;
1293
1294 if (cookie.IsPersistent()) {
1295 histogram_expiration_duration_minutes_->Add(
1296 (cookie.ExpiryDate() - creation_time).InMinutes());
mmenkeea4cd402016-02-02 04:03:101297 }
rdsmith2709eee2017-06-20 22:43:271298
Jeremy Roman0579ed62017-08-29 15:56:191299 InternalInsertCookie(key, std::make_unique<CanonicalCookie>(cookie), true);
rdsmith2709eee2017-06-20 22:43:271300 GarbageCollect(creation_time, key);
drogerd5d1278c2015-03-17 19:21:511301 }
1302
rdsmith2709eee2017-06-20 22:43:271303 // TODO(rdsmith): If this function always returns the same value, it
1304 // shouldn't have a return value. But it should also be deleted (see
1305 // https://codereview.chromium.org/2882063002/#msg64), which would
1306 // solve the return value problem.
rdsmithe5c701d2017-07-12 21:50:001307 MaybeRunCookieCallback(std::move(callback), true);
drogerd5d1278c2015-03-17 19:21:511308}
1309
[email protected]7a964a72010-09-07 19:33:261310void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc,
1311 const Time& current) {
mmenkebe0910d2016-03-01 19:09:091312 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041313
[email protected]77e0a462008-11-01 00:43:351314 // Based off the Mozilla code. When a cookie has been accessed recently,
1315 // don't bother updating its access time again. This reduces the number of
1316 // updates we do during pageload, which in turn reduces the chance our storage
1317 // backend will hit its batch thresholds and be forced to update.
[email protected]77e0a462008-11-01 00:43:351318 if ((current - cc->LastAccessDate()) < last_access_threshold_)
1319 return;
1320
1321 cc->SetLastAccessDate(current);
[email protected]90499482013-06-01 00:39:501322 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get())
[email protected]77e0a462008-11-01 00:43:351323 store_->UpdateCookieAccessTime(*cc);
1324}
1325
[email protected]6210ce52013-09-20 03:33:141326// InternalDeleteCookies must not invalidate iterators other than the one being
1327// deleted.
initial.commit586acc5fe2008-07-26 22:42:521328void CookieMonster::InternalDeleteCookie(CookieMap::iterator it,
[email protected]c4058fb2010-06-22 17:25:261329 bool sync_to_store,
1330 DeletionCause deletion_cause) {
mmenkebe0910d2016-03-01 19:09:091331 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041332
nharper352933e2016-09-30 18:24:571333 // Ideally, this would be asserted up where we define kChangeCauseMapping,
[email protected]8bb846f2011-03-23 12:08:181334 // but DeletionCause's visibility (or lack thereof) forces us to make
1335 // this check here.
nharper352933e2016-09-30 18:24:571336 static_assert(arraysize(kChangeCauseMapping) == DELETE_COOKIE_LAST_ENTRY + 1,
1337 "kChangeCauseMapping size should match DeletionCause size");
[email protected]8bb846f2011-03-23 12:08:181338
avie7cd11a2016-10-11 02:00:351339 CanonicalCookie* cc = it->second.get();
xiyuan8dbb89892015-04-13 17:04:301340 VLOG(kVlogSetCookies) << "InternalDeleteCookie()"
1341 << ", cause:" << deletion_cause
1342 << ", cc: " << cc->DebugString();
[email protected]7a964a72010-09-07 19:33:261343
[email protected]90499482013-06-01 00:39:501344 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get() &&
1345 sync_to_store)
initial.commit586acc5fe2008-07-26 22:42:521346 store_->DeleteCookie(*cc);
Thomas Anderson1a03bbe2018-03-02 19:05:471347 ChangeCausePair mapping = kChangeCauseMapping[deletion_cause];
Victor Costan14f47c12018-03-01 08:02:241348 change_dispatcher_.DispatchChange(*cc, mapping.cause, mapping.notify);
initial.commit586acc5fe2008-07-26 22:42:521349 cookies_.erase(it);
initial.commit586acc5fe2008-07-26 22:42:521350}
1351
[email protected]8807b322010-10-01 17:10:141352// Domain expiry behavior is unchanged by key/expiry scheme (the
[email protected]8ad5d462013-05-02 08:45:261353// meaning of the key is different, but that's not visible to this routine).
jww82d99c12015-11-25 18:39:531354size_t CookieMonster::GarbageCollect(const Time& current,
jwwa26e439d2017-01-27 18:17:271355 const std::string& key) {
mmenkebe0910d2016-03-01 19:09:091356 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041357
jww82d99c12015-11-25 18:39:531358 size_t num_deleted = 0;
mkwstbe84af312015-02-20 08:52:451359 Time safe_date(Time::Now() - TimeDelta::FromDays(kSafeFromGlobalPurgeDays));
initial.commit586acc5fe2008-07-26 22:42:521360
[email protected]8ad5d462013-05-02 08:45:261361 // Collect garbage for this key, minding cookie priorities.
[email protected]7a964a72010-09-07 19:33:261362 if (cookies_.count(key) > kDomainMaxCookies) {
[email protected]4d3ce782010-10-29 18:31:281363 VLOG(kVlogGarbageCollection) << "GarbageCollect() key: " << key;
[email protected]7a964a72010-09-07 19:33:261364
mkwst87734352016-03-03 17:36:231365 CookieItVector* cookie_its;
jww601411a2015-11-20 19:46:571366
mkwst87734352016-03-03 17:36:231367 CookieItVector non_expired_cookie_its;
1368 cookie_its = &non_expired_cookie_its;
jww82d99c12015-11-25 18:39:531369 num_deleted +=
mkwst87734352016-03-03 17:36:231370 GarbageCollectExpired(current, cookies_.equal_range(key), cookie_its);
jww82d99c12015-11-25 18:39:531371
mkwst87734352016-03-03 17:36:231372 if (cookie_its->size() > kDomainMaxCookies) {
[email protected]8ad5d462013-05-02 08:45:261373 VLOG(kVlogGarbageCollection) << "Deep Garbage Collect domain.";
1374 size_t purge_goal =
mkwst87734352016-03-03 17:36:231375 cookie_its->size() - (kDomainMaxCookies - kDomainPurgeCookies);
[email protected]8ad5d462013-05-02 08:45:261376 DCHECK(purge_goal > kDomainPurgeCookies);
1377
mkwste079ac412016-03-11 09:04:061378 // Sort the cookies by access date, from least-recent to most-recent.
1379 std::sort(cookie_its->begin(), cookie_its->end(), LRACookieSorter);
[email protected]8ad5d462013-05-02 08:45:261380
mkwste079ac412016-03-11 09:04:061381 // Remove all but the kDomainCookiesQuotaLow most-recently accessed
1382 // cookies with low-priority. Then, if cookies still need to be removed,
1383 // bump the quota and remove low- and medium-priority. Then, if cookies
1384 // _still_ need to be removed, bump the quota and remove cookies with
1385 // any priority.
jwwc00ac712016-05-05 22:21:441386 //
1387 // 1. Low-priority non-secure cookies.
1388 // 2. Low-priority secure cookies.
1389 // 3. Medium-priority non-secure cookies.
1390 // 4. High-priority non-secure cookies.
1391 // 5. Medium-priority secure cookies.
1392 // 6. High-priority secure cookies.
1393 const static struct {
1394 CookiePriority priority;
1395 bool protect_secure_cookies;
1396 } purge_rounds[] = {
1397 // 1. Low-priority non-secure cookies.
1398 {COOKIE_PRIORITY_LOW, true},
1399 // 2. Low-priority secure cookies.
1400 {COOKIE_PRIORITY_LOW, false},
1401 // 3. Medium-priority non-secure cookies.
1402 {COOKIE_PRIORITY_MEDIUM, true},
1403 // 4. High-priority non-secure cookies.
1404 {COOKIE_PRIORITY_HIGH, true},
1405 // 5. Medium-priority secure cookies.
1406 {COOKIE_PRIORITY_MEDIUM, false},
1407 // 6. High-priority secure cookies.
1408 {COOKIE_PRIORITY_HIGH, false},
1409 };
1410
mkwste079ac412016-03-11 09:04:061411 size_t quota = 0;
jwwc00ac712016-05-05 22:21:441412 for (const auto& purge_round : purge_rounds) {
mmenke645ca6772016-06-17 18:46:431413 // Adjust quota according to the priority of cookies. Each round should
1414 // protect certain number of cookies in order to avoid starvation.
1415 // For example, when each round starts to remove cookies, the number of
1416 // cookies of that priority are counted and a decision whether they
1417 // should be deleted or not is made. If yes, some number of cookies of
1418 // that priority are deleted considering the quota.
jwwc00ac712016-05-05 22:21:441419 switch (purge_round.priority) {
1420 case COOKIE_PRIORITY_LOW:
mmenke645ca6772016-06-17 18:46:431421 quota = kDomainCookiesQuotaLow;
jwwc00ac712016-05-05 22:21:441422 break;
1423 case COOKIE_PRIORITY_MEDIUM:
mmenke645ca6772016-06-17 18:46:431424 quota = kDomainCookiesQuotaMedium;
jwwc00ac712016-05-05 22:21:441425 break;
1426 case COOKIE_PRIORITY_HIGH:
mmenke645ca6772016-06-17 18:46:431427 quota = kDomainCookiesQuotaHigh;
jwwc00ac712016-05-05 22:21:441428 break;
1429 }
jwwc00ac712016-05-05 22:21:441430 size_t just_deleted = 0u;
jwwa26e439d2017-01-27 18:17:271431 // Purge up to |purge_goal| for all cookies at the given priority. This
1432 // path will be taken only if the initial non-secure purge did not evict
1433 // enough cookies.
jwwc00ac712016-05-05 22:21:441434 if (purge_goal > 0) {
1435 just_deleted = PurgeLeastRecentMatches(
1436 cookie_its, purge_round.priority, quota, purge_goal,
1437 purge_round.protect_secure_cookies);
1438 DCHECK_LE(just_deleted, purge_goal);
1439 purge_goal -= just_deleted;
1440 num_deleted += just_deleted;
1441 }
mkwst162d2712016-02-18 18:21:291442 }
mkwste079ac412016-03-11 09:04:061443
jwwc00ac712016-05-05 22:21:441444 DCHECK_EQ(0u, purge_goal);
[email protected]8807b322010-10-01 17:10:141445 }
initial.commit586acc5fe2008-07-26 22:42:521446 }
1447
[email protected]8ad5d462013-05-02 08:45:261448 // Collect garbage for everything. With firefox style we want to preserve
1449 // cookies accessed in kSafeFromGlobalPurgeDays, otherwise evict.
mkwstbe84af312015-02-20 08:52:451450 if (cookies_.size() > kMaxCookies && earliest_access_time_ < safe_date) {
[email protected]4d3ce782010-10-29 18:31:281451 VLOG(kVlogGarbageCollection) << "GarbageCollect() everything";
[email protected]8ad5d462013-05-02 08:45:261452 CookieItVector cookie_its;
jww82d99c12015-11-25 18:39:531453
[email protected]7a964a72010-09-07 19:33:261454 num_deleted += GarbageCollectExpired(
1455 current, CookieMapItPair(cookies_.begin(), cookies_.end()),
1456 &cookie_its);
jww82d99c12015-11-25 18:39:531457
[email protected]8ad5d462013-05-02 08:45:261458 if (cookie_its.size() > kMaxCookies) {
1459 VLOG(kVlogGarbageCollection) << "Deep Garbage Collect everything.";
1460 size_t purge_goal = cookie_its.size() - (kMaxCookies - kPurgeCookies);
1461 DCHECK(purge_goal > kPurgeCookies);
jww82d99c12015-11-25 18:39:531462
jwwa26e439d2017-01-27 18:17:271463 CookieItVector secure_cookie_its;
1464 CookieItVector non_secure_cookie_its;
1465 SplitCookieVectorIntoSecureAndNonSecure(cookie_its, &secure_cookie_its,
1466 &non_secure_cookie_its);
1467 size_t non_secure_purge_goal =
mmenkef4721d992017-06-07 17:13:591468 std::min<size_t>(purge_goal, non_secure_cookie_its.size());
jww82d99c12015-11-25 18:39:531469
mmenkef4721d992017-06-07 17:13:591470 base::Time earliest_non_secure_access_time;
jwwa26e439d2017-01-27 18:17:271471 size_t just_deleted = GarbageCollectLeastRecentlyAccessed(
mmenkef4721d992017-06-07 17:13:591472 current, safe_date, non_secure_purge_goal, non_secure_cookie_its,
1473 &earliest_non_secure_access_time);
jwwa26e439d2017-01-27 18:17:271474 num_deleted += just_deleted;
jww82d99c12015-11-25 18:39:531475
mmenkef4721d992017-06-07 17:13:591476 if (secure_cookie_its.size() == 0) {
1477 // This case is unlikely, but should still update
1478 // |earliest_access_time_| if only have non-secure cookies.
1479 earliest_access_time_ = earliest_non_secure_access_time;
1480 // Garbage collection can't delete all cookies.
1481 DCHECK(!earliest_access_time_.is_null());
1482 } else if (just_deleted < purge_goal) {
1483 size_t secure_purge_goal = std::min<size_t>(purge_goal - just_deleted,
1484 secure_cookie_its.size());
1485 base::Time earliest_secure_access_time;
jww82d99c12015-11-25 18:39:531486 num_deleted += GarbageCollectLeastRecentlyAccessed(
mmenkef4721d992017-06-07 17:13:591487 current, safe_date, secure_purge_goal, secure_cookie_its,
1488 &earliest_secure_access_time);
1489
1490 if (!earliest_non_secure_access_time.is_null() &&
1491 earliest_non_secure_access_time < earliest_secure_access_time) {
1492 earliest_access_time_ = earliest_non_secure_access_time;
1493 } else {
1494 earliest_access_time_ = earliest_secure_access_time;
1495 }
1496
1497 // Garbage collection can't delete all cookies.
1498 DCHECK(!earliest_access_time_.is_null());
jww82d99c12015-11-25 18:39:531499 }
mmenkef4721d992017-06-07 17:13:591500
1501 // If there are secure cookies, but deleting non-secure cookies was enough
1502 // to meet the purge goal, secure cookies are never examined, so
1503 // |earliest_access_time_| can't be determined. Leaving it alone will mean
1504 // it's no later than the real earliest last access time, so this won't
1505 // lead to any problems.
[email protected]8807b322010-10-01 17:10:141506 }
[email protected]c890ed192008-10-30 23:45:531507 }
1508
1509 return num_deleted;
1510}
1511
mkwste079ac412016-03-11 09:04:061512size_t CookieMonster::PurgeLeastRecentMatches(CookieItVector* cookies,
1513 CookiePriority priority,
1514 size_t to_protect,
jwwc00ac712016-05-05 22:21:441515 size_t purge_goal,
1516 bool protect_secure_cookies) {
mkwste079ac412016-03-11 09:04:061517 DCHECK(thread_checker_.CalledOnValidThread());
1518
mmenke645ca6772016-06-17 18:46:431519 // 1. Count number of the cookies at |priority|
1520 size_t cookies_count_possibly_to_be_deleted = CountCookiesForPossibleDeletion(
1521 priority, cookies, false /* count all cookies */);
1522
1523 // 2. If |cookies_count_possibly_to_be_deleted| at |priority| is less than or
1524 // equal |to_protect|, skip round in order to preserve the quota. This
1525 // involves secure and non-secure cookies at |priority|.
1526 if (cookies_count_possibly_to_be_deleted <= to_protect)
1527 return 0u;
1528
1529 // 3. Calculate number of secure cookies at |priority|
1530 // and number of cookies at |priority| that can possibly be deleted.
1531 // It is guaranteed we do not delete more than |purge_goal| even if
1532 // |cookies_count_possibly_to_be_deleted| is higher.
1533 size_t secure_cookies = 0u;
jwwc00ac712016-05-05 22:21:441534 if (protect_secure_cookies) {
mmenke645ca6772016-06-17 18:46:431535 secure_cookies = CountCookiesForPossibleDeletion(
1536 priority, cookies, protect_secure_cookies /* count secure cookies */);
1537 cookies_count_possibly_to_be_deleted -=
1538 std::max(secure_cookies, to_protect - secure_cookies);
1539 } else {
1540 cookies_count_possibly_to_be_deleted -= to_protect;
jwwc00ac712016-05-05 22:21:441541 }
1542
mmenke645ca6772016-06-17 18:46:431543 size_t removed = 0u;
1544 size_t current = 0u;
1545 while ((removed < purge_goal && current < cookies->size()) &&
1546 cookies_count_possibly_to_be_deleted > 0) {
avie7cd11a2016-10-11 02:00:351547 const CanonicalCookie* current_cookie = cookies->at(current)->second.get();
mmenke645ca6772016-06-17 18:46:431548 // Only delete the current cookie if the priority is equal to
1549 // the current level.
jwwc00ac712016-05-05 22:21:441550 if (IsCookieEligibleForEviction(priority, protect_secure_cookies,
1551 current_cookie)) {
mkwstaa07ee82016-03-11 15:32:141552 InternalDeleteCookie(cookies->at(current), true,
1553 DELETE_COOKIE_EVICTED_DOMAIN);
mkwste079ac412016-03-11 09:04:061554 cookies->erase(cookies->begin() + current);
1555 removed++;
mmenke645ca6772016-06-17 18:46:431556 cookies_count_possibly_to_be_deleted--;
mkwste079ac412016-03-11 09:04:061557 } else {
1558 current++;
1559 }
1560 }
1561 return removed;
1562}
1563
jww82d99c12015-11-25 18:39:531564size_t CookieMonster::GarbageCollectExpired(const Time& current,
1565 const CookieMapItPair& itpair,
1566 CookieItVector* cookie_its) {
mmenkebe0910d2016-03-01 19:09:091567 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041568
[email protected]c890ed192008-10-30 23:45:531569 int num_deleted = 0;
1570 for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) {
1571 CookieMap::iterator curit = it;
1572 ++it;
1573
1574 if (curit->second->IsExpired(current)) {
[email protected]2f3f3592010-07-07 20:11:511575 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
[email protected]c890ed192008-10-30 23:45:531576 ++num_deleted;
1577 } else if (cookie_its) {
1578 cookie_its->push_back(curit);
1579 }
initial.commit586acc5fe2008-07-26 22:42:521580 }
1581
1582 return num_deleted;
1583}
1584
jww82d99c12015-11-25 18:39:531585size_t CookieMonster::GarbageCollectDeleteRange(
1586 const Time& current,
1587 DeletionCause cause,
1588 CookieItVector::iterator it_begin,
1589 CookieItVector::iterator it_end) {
mmenkebe0910d2016-03-01 19:09:091590 DCHECK(thread_checker_.CalledOnValidThread());
1591
[email protected]8ad5d462013-05-02 08:45:261592 for (CookieItVector::iterator it = it_begin; it != it_end; it++) {
[email protected]8ad5d462013-05-02 08:45:261593 InternalDeleteCookie((*it), true, cause);
[email protected]c10da4b02010-03-25 14:38:321594 }
[email protected]8ad5d462013-05-02 08:45:261595 return it_end - it_begin;
[email protected]c10da4b02010-03-25 14:38:321596}
1597
mmenke74bcbd52016-01-21 17:17:561598size_t CookieMonster::GarbageCollectLeastRecentlyAccessed(
1599 const base::Time& current,
1600 const base::Time& safe_date,
1601 size_t purge_goal,
mmenkef4721d992017-06-07 17:13:591602 CookieItVector cookie_its,
1603 base::Time* earliest_time) {
1604 DCHECK_LE(purge_goal, cookie_its.size());
mmenkebe0910d2016-03-01 19:09:091605 DCHECK(thread_checker_.CalledOnValidThread());
1606
mmenkef4721d992017-06-07 17:13:591607 // Sorts up to *and including* |cookie_its[purge_goal]| (if it exists), so
1608 // |earliest_time| will be properly assigned even if
mmenke74bcbd52016-01-21 17:17:561609 // |global_purge_it| == |cookie_its.begin() + purge_goal|.
mmenkef4721d992017-06-07 17:13:591610 SortLeastRecentlyAccessed(
1611 cookie_its.begin(), cookie_its.end(),
1612 cookie_its.size() < purge_goal ? purge_goal + 1 : purge_goal);
mmenke74bcbd52016-01-21 17:17:561613 // Find boundary to cookies older than safe_date.
1614 CookieItVector::iterator global_purge_it = LowerBoundAccessDate(
1615 cookie_its.begin(), cookie_its.begin() + purge_goal, safe_date);
jwwa26e439d2017-01-27 18:17:271616 // Only delete the old cookies and delete non-secure ones first.
mmenke74bcbd52016-01-21 17:17:561617 size_t num_deleted =
1618 GarbageCollectDeleteRange(current, DELETE_COOKIE_EVICTED_GLOBAL,
1619 cookie_its.begin(), global_purge_it);
mmenkef4721d992017-06-07 17:13:591620 if (global_purge_it != cookie_its.end())
1621 *earliest_time = (*global_purge_it)->second->LastAccessDate();
mmenke74bcbd52016-01-21 17:17:561622 return num_deleted;
1623}
1624
[email protected]ed32c212013-05-14 20:49:291625// A wrapper around registry_controlled_domains::GetDomainAndRegistry
Maks Orlovich323efaf2018-03-06 02:56:391626// to make clear we're creating a key for our local map or for the persistent
1627// store's use. Here and in FindCookiesForHostAndDomain() are the only two
1628// places where we need to conditionalize based on key type.
[email protected]f48b9432011-01-11 07:25:401629//
1630// Note that this key algorithm explicitly ignores the scheme. This is
1631// because when we're entering cookies into the map from the backing store,
1632// we in general won't have the scheme at that point.
1633// In practical terms, this means that file cookies will be stored
1634// in the map either by an empty string or by UNC name (and will be
1635// limited by kMaxCookiesPerHost), and extension cookies will be stored
1636// based on the single extension id, as the extension id won't have the
1637// form of a DNS host and hence GetKey() will return it unchanged.
1638//
1639// Arguably the right thing to do here is to make the key
1640// algorithm dependent on the scheme, and make sure that the scheme is
1641// available everywhere the key must be obtained (specfically at backing
1642// store load time). This would require either changing the backing store
1643// database schema to include the scheme (far more trouble than it's worth), or
1644// separating out file cookies into their own CookieMonster instance and
1645// thus restricting each scheme to a single cookie monster (which might
1646// be worth it, but is still too much trouble to solve what is currently a
1647// non-problem).
Maks Orlovich323efaf2018-03-06 02:56:391648//
1649// static
1650std::string CookieMonster::GetKey(base::StringPiece domain) {
[email protected]f48b9432011-01-11 07:25:401651 std::string effective_domain(
[email protected]ed32c212013-05-14 20:49:291652 registry_controlled_domains::GetDomainAndRegistry(
[email protected]aabe1792014-01-30 21:37:461653 domain, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES));
[email protected]f48b9432011-01-11 07:25:401654 if (effective_domain.empty())
Maks Orlovich323efaf2018-03-06 02:56:391655 domain.CopyToString(&effective_domain);
[email protected]f48b9432011-01-11 07:25:401656
1657 if (!effective_domain.empty() && effective_domain[0] == '.')
1658 return effective_domain.substr(1);
1659 return effective_domain;
1660}
1661
1662bool CookieMonster::HasCookieableScheme(const GURL& url) {
mmenkebe0910d2016-03-01 19:09:091663 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401664
1665 // Make sure the request is on a cookie-able url scheme.
1666 for (size_t i = 0; i < cookieable_schemes_.size(); ++i) {
1667 // We matched a scheme.
1668 if (url.SchemeIs(cookieable_schemes_[i].c_str())) {
1669 // We've matched a supported scheme.
initial.commit586acc5fe2008-07-26 22:42:521670 return true;
1671 }
1672 }
[email protected]f48b9432011-01-11 07:25:401673
1674 // The scheme didn't match any in our whitelist.
mkwstbe84af312015-02-20 08:52:451675 VLOG(kVlogPerCookieMonster)
1676 << "WARNING: Unsupported cookie scheme: " << url.scheme();
initial.commit586acc5fe2008-07-26 22:42:521677 return false;
1678}
1679
[email protected]c4058fb2010-06-22 17:25:261680// Test to see if stats should be recorded, and record them if so.
1681// The goal here is to get sampling for the average browser-hour of
1682// activity. We won't take samples when the web isn't being surfed,
1683// and when the web is being surfed, we'll take samples about every
1684// kRecordStatisticsIntervalSeconds.
1685// last_statistic_record_time_ is initialized to Now() rather than null
1686// in the constructor so that we won't take statistics right after
1687// startup, to avoid bias from browsers that are started but not used.
1688void CookieMonster::RecordPeriodicStats(const base::Time& current_time) {
mmenkebe0910d2016-03-01 19:09:091689 DCHECK(thread_checker_.CalledOnValidThread());
1690
[email protected]c4058fb2010-06-22 17:25:261691 const base::TimeDelta kRecordStatisticsIntervalTime(
1692 base::TimeDelta::FromSeconds(kRecordStatisticsIntervalSeconds));
1693
[email protected]7a964a72010-09-07 19:33:261694 // If we've taken statistics recently, return.
1695 if (current_time - last_statistic_record_time_ <=
[email protected]c4058fb2010-06-22 17:25:261696 kRecordStatisticsIntervalTime) {
[email protected]7a964a72010-09-07 19:33:261697 return;
[email protected]c4058fb2010-06-22 17:25:261698 }
[email protected]7a964a72010-09-07 19:33:261699
1700 // See InitializeHistograms() for details.
1701 histogram_count_->Add(cookies_.size());
1702
1703 // More detailed statistics on cookie counts at different granularities.
[email protected]7a964a72010-09-07 19:33:261704 last_statistic_record_time_ = current_time;
[email protected]c4058fb2010-06-22 17:25:261705}
1706
[email protected]f48b9432011-01-11 07:25:401707// Initialize all histogram counter variables used in this class.
1708//
1709// Normal histogram usage involves using the macros defined in
1710// histogram.h, which automatically takes care of declaring these
1711// variables (as statics), initializing them, and accumulating into
1712// them, all from a single entry point. Unfortunately, that solution
1713// doesn't work for the CookieMonster, as it's vulnerable to races between
1714// separate threads executing the same functions and hence initializing the
1715// same static variables. There isn't a race danger in the histogram
1716// accumulation calls; they are written to be resilient to simultaneous
1717// calls from multiple threads.
1718//
1719// The solution taken here is to have per-CookieMonster instance
1720// variables that are constructed during CookieMonster construction.
1721// Note that these variables refer to the same underlying histogram,
1722// so we still race (but safely) with other CookieMonster instances
1723// for accumulation.
1724//
1725// To do this we've expanded out the individual histogram macros calls,
1726// with declarations of the variables in the class decl, initialization here
1727// (done from the class constructor) and direct calls to the accumulation
1728// methods where needed. The specific histogram macro calls on which the
1729// initialization is based are included in comments below.
1730void CookieMonster::InitializeHistograms() {
mmenkebe0910d2016-03-01 19:09:091731 DCHECK(thread_checker_.CalledOnValidThread());
1732
[email protected]f48b9432011-01-11 07:25:401733 // From UMA_HISTOGRAM_CUSTOM_COUNTS
1734 histogram_expiration_duration_minutes_ = base::Histogram::FactoryGet(
mkwstbe84af312015-02-20 08:52:451735 "Cookie.ExpirationDurationMinutes", 1, kMinutesInTenYears, 50,
[email protected]f48b9432011-01-11 07:25:401736 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401737 histogram_count_ = base::Histogram::FactoryGet(
mkwstbe84af312015-02-20 08:52:451738 "Cookie.Count", 1, 4000, 50, base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401739
1740 // From UMA_HISTOGRAM_ENUMERATION
mkwstc1aa4cc2015-04-03 19:57:451741 histogram_cookie_type_ = base::LinearHistogram::FactoryGet(
mkwst87378d92015-04-10 21:22:111742 "Cookie.Type", 1, (1 << COOKIE_TYPE_LAST_ENTRY) - 1,
1743 1 << COOKIE_TYPE_LAST_ENTRY, base::Histogram::kUmaTargetedHistogramFlag);
estark7feb65c2b2015-08-21 23:38:201744 histogram_cookie_source_scheme_ = base::LinearHistogram::FactoryGet(
1745 "Cookie.CookieSourceScheme", 1, COOKIE_SOURCE_LAST_ENTRY - 1,
1746 COOKIE_SOURCE_LAST_ENTRY, base::Histogram::kUmaTargetedHistogramFlag);
jww31e32632015-12-16 23:38:341747 histogram_cookie_delete_equivalent_ = base::LinearHistogram::FactoryGet(
1748 "Cookie.CookieDeleteEquivalent", 1,
1749 COOKIE_DELETE_EQUIVALENT_LAST_ENTRY - 1,
1750 COOKIE_DELETE_EQUIVALENT_LAST_ENTRY,
1751 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401752
1753 // From UMA_HISTOGRAM_{CUSTOM_,}TIMES
[email protected]c7593fb22011-11-14 23:54:271754 histogram_time_blocked_on_load_ = base::Histogram::FactoryTimeGet(
mkwstbe84af312015-02-20 08:52:451755 "Cookie.TimeBlockedOnLoad", base::TimeDelta::FromMilliseconds(1),
1756 base::TimeDelta::FromMinutes(1), 50,
1757 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401758}
1759
[email protected]f48b9432011-01-11 07:25:401760// The system resolution is not high enough, so we can have multiple
1761// set cookies that result in the same system time. When this happens, we
1762// increment by one Time unit. Let's hope computers don't get too fast.
1763Time CookieMonster::CurrentTime() {
mkwstbe84af312015-02-20 08:52:451764 return std::max(Time::Now(), Time::FromInternalValue(
1765 last_time_seen_.ToInternalValue() + 1));
[email protected]f48b9432011-01-11 07:25:401766}
1767
rdsmithe5c701d2017-07-12 21:50:001768void CookieMonster::DoCookieCallback(base::OnceClosure callback) {
mmenkebe0910d2016-03-01 19:09:091769 DCHECK(thread_checker_.CalledOnValidThread());
1770
1771 MarkCookieStoreAsInitialized();
1772 FetchAllCookiesIfNecessary();
mmenkef49fca0e2016-03-08 12:46:241773 seen_global_task_ = true;
mmenkebe0910d2016-03-01 19:09:091774
1775 if (!finished_fetching_all_cookies_ && store_.get()) {
rdsmithe5c701d2017-07-12 21:50:001776 tasks_pending_.push_back(std::move(callback));
mmenkebe0910d2016-03-01 19:09:091777 return;
mmenke74bcbd52016-01-21 17:17:561778 }
1779
rdsmithe5c701d2017-07-12 21:50:001780 std::move(callback).Run();
mmenke74bcbd52016-01-21 17:17:561781}
1782
rdsmithe5c701d2017-07-12 21:50:001783void CookieMonster::DoCookieCallbackForURL(base::OnceClosure callback,
1784 const GURL& url) {
Maks Orlovich323efaf2018-03-06 02:56:391785 DoCookieCallbackForHostOrDomain(std::move(callback), url.host_piece());
1786}
1787
1788void CookieMonster::DoCookieCallbackForHostOrDomain(
1789 base::OnceClosure callback,
1790 base::StringPiece host_or_domain) {
mmenkebe0910d2016-03-01 19:09:091791 MarkCookieStoreAsInitialized();
erikchende4c39e2018-01-29 21:33:361792 FetchAllCookiesIfNecessary();
mmenkebe0910d2016-03-01 19:09:091793
1794 // If cookies for the requested domain key (eTLD+1) have been loaded from DB
1795 // then run the task, otherwise load from DB.
1796 if (!finished_fetching_all_cookies_ && store_.get()) {
mmenkef49fca0e2016-03-08 12:46:241797 // If a global task has been previously seen, queue the task as a global
1798 // task. Note that the CookieMonster may be in the middle of executing
1799 // the global queue, |tasks_pending_| may be empty, which is why another
1800 // bool is needed.
1801 if (seen_global_task_) {
rdsmithe5c701d2017-07-12 21:50:001802 tasks_pending_.push_back(std::move(callback));
mmenkef49fca0e2016-03-08 12:46:241803 return;
1804 }
1805
mmenkebe0910d2016-03-01 19:09:091806 // Checks if the domain key has been loaded.
Maks Orlovich323efaf2018-03-06 02:56:391807 std::string key = GetKey(host_or_domain);
mmenkebe0910d2016-03-01 19:09:091808 if (keys_loaded_.find(key) == keys_loaded_.end()) {
Brett Wilsonc6a0c822017-09-12 00:04:291809 std::map<std::string, base::circular_deque<base::OnceClosure>>::iterator
1810 it = tasks_pending_for_key_.find(key);
mmenkebe0910d2016-03-01 19:09:091811 if (it == tasks_pending_for_key_.end()) {
1812 store_->LoadCookiesForKey(
1813 key, base::Bind(&CookieMonster::OnKeyLoaded,
1814 weak_ptr_factory_.GetWeakPtr(), key));
1815 it = tasks_pending_for_key_
Brett Wilsonc6a0c822017-09-12 00:04:291816 .insert(std::make_pair(
1817 key, base::circular_deque<base::OnceClosure>()))
mmenkebe0910d2016-03-01 19:09:091818 .first;
mmenke74bcbd52016-01-21 17:17:561819 }
rdsmithe5c701d2017-07-12 21:50:001820 it->second.push_back(std::move(callback));
mmenkebe0910d2016-03-01 19:09:091821 return;
mmenke74bcbd52016-01-21 17:17:561822 }
1823 }
mmenkebe0910d2016-03-01 19:09:091824
rdsmithe5c701d2017-07-12 21:50:001825 std::move(callback).Run();
mmenke74bcbd52016-01-21 17:17:561826}
1827
[email protected]63725312012-07-19 08:24:161828} // namespace net