blob: 9ccdbaa0f2d9f9363b50942099e5fa85fdb2ec59 [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>
danakja9850e12016-04-18 22:28:0848#include <memory>
[email protected]09666482011-07-12 12:50:4049#include <set>
initial.commit586acc5fe2008-07-26 22:42:5250
[email protected]218aa6a12011-09-13 17:38:3851#include "base/bind.h"
[email protected]8562034e2011-10-17 17:35:0452#include "base/callback.h"
skyostil4891b25b2015-06-11 11:43:4553#include "base/location.h"
initial.commit586acc5fe2008-07-26 22:42:5254#include "base/logging.h"
Avi Drissman13fc8932015-12-20 04:40:4655#include "base/macros.h"
danakja9850e12016-04-18 22:28:0856#include "base/memory/ptr_util.h"
erikchen1dd72a72015-05-06 20:45:0557#include "base/metrics/field_trial.h"
[email protected]835d7c82010-10-14 04:38:3858#include "base/metrics/histogram.h"
anujk.sharmaafc45172015-05-15 00:50:3459#include "base/single_thread_task_runner.h"
tripta.gdda72022017-06-19 05:16:2360#include "base/stl_util.h"
[email protected]4b355212013-06-11 10:35:1961#include "base/strings/string_util.h"
62#include "base/strings/stringprintf.h"
gabf767595f2016-05-11 18:50:3563#include "base/threading/thread_task_runner_handle.h"
[email protected]be28b5f42012-07-20 11:31:2564#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
[email protected]4b355212013-06-11 10:35:1965#include "net/cookies/canonical_cookie.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]8562034e2011-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]8562034e2011-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]8562034e2011-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]8562034e2011-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
100const char kFetchWhenNecessaryName[] = "FetchWhenNecessary";
101const char kAlwaysFetchName[] = "AlwaysFetch";
102const char kCookieMonsterFetchStrategyName[] = "CookieMonsterFetchStrategy";
103
rdsmithe5c701d2017-07-12 21:50:00104void MayeRunDeleteCallback(base::WeakPtr<net::CookieMonster> cookie_monster,
105 base::OnceClosure callback) {
106 if (cookie_monster && callback)
107 std::move(callback).Run();
108}
109
110void MaybeRunCookieCallback(base::OnceClosure callback) {
111 if (callback)
112 std::move(callback).Run();
113}
114
115template <typename T>
116void MaybeRunCookieCallback(base::OnceCallback<void(const T&)> callback,
117 const T& result) {
118 if (callback)
119 std::move(callback).Run(result);
120}
121
122template <typename T>
123void MaybeRunCookieCallback(base::OnceCallback<void(T)> callback,
124 const T& result) {
125 if (callback)
126 std::move(callback).Run(result);
127}
128
erikchen1dd72a72015-05-06 20:45:05129} // namespace
130
[email protected]8ac1a752008-07-31 19:40:37131namespace net {
132
[email protected]7a964a72010-09-07 19:33:26133// See comments at declaration of these variables in cookie_monster.h
134// for details.
mkwstbe84af312015-02-20 08:52:45135const size_t CookieMonster::kDomainMaxCookies = 180;
136const size_t CookieMonster::kDomainPurgeCookies = 30;
137const size_t CookieMonster::kMaxCookies = 3300;
138const size_t CookieMonster::kPurgeCookies = 300;
[email protected]8ad5d462013-05-02 08:45:26139
mkwst87734352016-03-03 17:36:23140const size_t CookieMonster::kDomainCookiesQuotaLow = 30;
141const size_t CookieMonster::kDomainCookiesQuotaMedium = 50;
142const size_t CookieMonster::kDomainCookiesQuotaHigh =
143 kDomainMaxCookies - kDomainPurgeCookies - kDomainCookiesQuotaLow -
144 kDomainCookiesQuotaMedium;
[email protected]8ad5d462013-05-02 08:45:26145
mkwstbe84af312015-02-20 08:52:45146const int CookieMonster::kSafeFromGlobalPurgeDays = 30;
[email protected]297a4ed02010-02-12 08:12:52147
[email protected]7a964a72010-09-07 19:33:26148namespace {
[email protected]e32306c52008-11-06 16:59:05149
Randy Smith4780ccc2017-09-29 17:39:41150// This class owns the CookieStore::CookieChangedCallbackList::Subscription,
151// thus guaranteeing destruction when it is destroyed. In addition, it
152// wraps the callback for a particular subscription, guaranteeing that it
153// won't be run even if a PostTask completes after the subscription has
154// been destroyed.
155class CookieMonsterCookieChangedSubscription
156 : public CookieStore::CookieChangedSubscription {
157 public:
158 CookieMonsterCookieChangedSubscription(
159 const CookieStore::CookieChangedCallback& callback)
160 : callback_(callback), weak_ptr_factory_(this) {}
161 ~CookieMonsterCookieChangedSubscription() override {}
162
163 void SetCallbackSubscription(
164 std::unique_ptr<CookieStore::CookieChangedCallbackList::Subscription>
165 subscription) {
166 subscription_ = std::move(subscription);
167 }
168
169 // The returned callback runs the callback passed to the constructor
170 // directly as long as this object hasn't been destroyed.
171 CookieStore::CookieChangedCallback WeakCallback() {
172 return base::Bind(&CookieMonsterCookieChangedSubscription::RunCallback,
173 weak_ptr_factory_.GetWeakPtr());
174 }
175
176 private:
177 void RunCallback(const CanonicalCookie& cookie,
178 CookieStore::ChangeCause cause) {
179 callback_.Run(cookie, cause);
180 }
181
182 const CookieStore::CookieChangedCallback callback_;
183 std::unique_ptr<CookieStore::CookieChangedCallbackList::Subscription>
184 subscription_;
185 base::WeakPtrFactory<CookieMonsterCookieChangedSubscription>
186 weak_ptr_factory_;
187
188 DISALLOW_COPY_AND_ASSIGN(CookieMonsterCookieChangedSubscription);
189};
190
[email protected]6210ce52013-09-20 03:33:14191bool ContainsControlCharacter(const std::string& s) {
192 for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
193 if ((*i >= 0) && (*i <= 31))
194 return true;
195 }
196
197 return false;
198}
199
[email protected]5b9bc352012-07-18 13:13:34200typedef std::vector<CanonicalCookie*> CanonicalCookieVector;
[email protected]34a160d2011-05-12 22:12:49201
[email protected]77e0a462008-11-01 00:43:35202// Default minimum delay after updating a cookie's LastAccessDate before we
203// will update it again.
[email protected]297a4ed02010-02-12 08:12:52204const int kDefaultAccessUpdateThresholdSeconds = 60;
205
206// Comparator to sort cookies from highest creation date to lowest
207// creation date.
208struct OrderByCreationTimeDesc {
209 bool operator()(const CookieMonster::CookieMap::iterator& a,
210 const CookieMonster::CookieMap::iterator& b) const {
211 return a->second->CreationDate() > b->second->CreationDate();
212 }
213};
214
[email protected]4d3ce782010-10-29 18:31:28215// Constants for use in VLOG
216const int kVlogPerCookieMonster = 1;
[email protected]4d3ce782010-10-29 18:31:28217const int kVlogGarbageCollection = 5;
218const int kVlogSetCookies = 7;
219const int kVlogGetCookies = 9;
220
[email protected]f48b9432011-01-11 07:25:40221// Mozilla sorts on the path length (longest first), and then it
222// sorts by creation time (oldest first).
223// The RFC says the sort order for the domain attribute is undefined.
[email protected]5b9bc352012-07-18 13:13:34224bool CookieSorter(CanonicalCookie* cc1, CanonicalCookie* cc2) {
[email protected]f48b9432011-01-11 07:25:40225 if (cc1->Path().length() == cc2->Path().length())
226 return cc1->CreationDate() < cc2->CreationDate();
227 return cc1->Path().length() > cc2->Path().length();
initial.commit586acc5fe2008-07-26 22:42:52228}
229
[email protected]8ad5d462013-05-02 08:45:26230bool LRACookieSorter(const CookieMonster::CookieMap::iterator& it1,
[email protected]f48b9432011-01-11 07:25:40231 const CookieMonster::CookieMap::iterator& it2) {
[email protected]f48b9432011-01-11 07:25:40232 if (it1->second->LastAccessDate() != it2->second->LastAccessDate())
233 return it1->second->LastAccessDate() < it2->second->LastAccessDate();
initial.commit586acc5fe2008-07-26 22:42:52234
mkwste079ac412016-03-11 09:04:06235 // Ensure stability for == last access times by falling back to creation.
[email protected]f48b9432011-01-11 07:25:40236 return it1->second->CreationDate() < it2->second->CreationDate();
[email protected]297a4ed02010-02-12 08:12:52237}
238
239// Our strategy to find duplicates is:
240// (1) Build a map from (cookiename, cookiepath) to
241// {list of cookies with this signature, sorted by creation time}.
242// (2) For each list with more than 1 entry, keep the cookie having the
243// most recent creation time, and delete the others.
[email protected]f48b9432011-01-11 07:25:40244//
[email protected]1655ba342010-07-14 18:17:42245// Two cookies are considered equivalent if they have the same domain,
246// name, and path.
247struct CookieSignature {
248 public:
[email protected]dedec0b2013-02-28 04:50:10249 CookieSignature(const std::string& name,
250 const std::string& domain,
[email protected]1655ba342010-07-14 18:17:42251 const std::string& path)
mkwstbe84af312015-02-20 08:52:45252 : name(name), domain(domain), path(path) {}
[email protected]1655ba342010-07-14 18:17:42253
254 // To be a key for a map this class needs to be assignable, copyable,
255 // and have an operator<. The default assignment operator
256 // and copy constructor are exactly what we want.
257
258 bool operator<(const CookieSignature& cs) const {
259 // Name compare dominates, then domain, then path.
260 int diff = name.compare(cs.name);
261 if (diff != 0)
262 return diff < 0;
263
264 diff = domain.compare(cs.domain);
265 if (diff != 0)
266 return diff < 0;
267
268 return path.compare(cs.path) < 0;
269 }
270
271 std::string name;
272 std::string domain;
273 std::string path;
274};
[email protected]f48b9432011-01-11 07:25:40275
[email protected]8ad5d462013-05-02 08:45:26276// For a CookieItVector iterator range [|it_begin|, |it_end|),
mmenkef4721d992017-06-07 17:13:59277// sorts the first |num_sort| elements by LastAccessDate().
mkwstbe84af312015-02-20 08:52:45278void SortLeastRecentlyAccessed(CookieMonster::CookieItVector::iterator it_begin,
279 CookieMonster::CookieItVector::iterator it_end,
280 size_t num_sort) {
mmenkef4721d992017-06-07 17:13:59281 DCHECK_LE(static_cast<int>(num_sort), it_end - it_begin);
282 std::partial_sort(it_begin, it_begin + num_sort, it_end, LRACookieSorter);
[email protected]8ad5d462013-05-02 08:45:26283}
[email protected]f48b9432011-01-11 07:25:40284
jww82d99c12015-11-25 18:39:53285// Given a single cookie vector |cookie_its|, pushs all of the secure cookies in
286// |cookie_its| into |secure_cookie_its| and all of the non-secure cookies into
287// |non_secure_cookie_its|. Both |secure_cookie_its| and |non_secure_cookie_its|
288// must be non-NULL.
289void SplitCookieVectorIntoSecureAndNonSecure(
290 const CookieMonster::CookieItVector& cookie_its,
291 CookieMonster::CookieItVector* secure_cookie_its,
292 CookieMonster::CookieItVector* non_secure_cookie_its) {
293 DCHECK(secure_cookie_its && non_secure_cookie_its);
294 for (const auto& curit : cookie_its) {
295 if (curit->second->IsSecure())
296 secure_cookie_its->push_back(curit);
297 else
298 non_secure_cookie_its->push_back(curit);
299 }
300}
301
mkwstbe84af312015-02-20 08:52:45302bool LowerBoundAccessDateComparator(const CookieMonster::CookieMap::iterator it,
303 const Time& access_date) {
[email protected]8ad5d462013-05-02 08:45:26304 return it->second->LastAccessDate() < access_date;
305}
306
307// For a CookieItVector iterator range [|it_begin|, |it_end|)
308// from a CookieItVector sorted by LastAccessDate(), returns the
309// first iterator with access date >= |access_date|, or cookie_its_end if this
310// holds for all.
311CookieMonster::CookieItVector::iterator LowerBoundAccessDate(
312 const CookieMonster::CookieItVector::iterator its_begin,
313 const CookieMonster::CookieItVector::iterator its_end,
314 const Time& access_date) {
315 return std::lower_bound(its_begin, its_end, access_date,
316 LowerBoundAccessDateComparator);
[email protected]7a964a72010-09-07 19:33:26317}
318
nharper352933e2016-09-30 18:24:57319// Mapping between DeletionCause and CookieStore::ChangeCause; the
[email protected]7c4b66b2014-01-04 12:28:13320// mapping also provides a boolean that specifies whether or not an
321// OnCookieChanged notification ought to be generated.
[email protected]8bb846f2011-03-23 12:08:18322typedef struct ChangeCausePair_struct {
nharper352933e2016-09-30 18:24:57323 CookieStore::ChangeCause cause;
[email protected]8bb846f2011-03-23 12:08:18324 bool notify;
325} ChangeCausePair;
nharper352933e2016-09-30 18:24:57326const ChangeCausePair kChangeCauseMapping[] = {
mkwstbe84af312015-02-20 08:52:45327 // DELETE_COOKIE_EXPLICIT
nharper68903362017-01-20 04:07:14328 {CookieStore::ChangeCause::EXPLICIT, true},
mkwstbe84af312015-02-20 08:52:45329 // DELETE_COOKIE_OVERWRITE
nharper352933e2016-09-30 18:24:57330 {CookieStore::ChangeCause::OVERWRITE, true},
mkwstbe84af312015-02-20 08:52:45331 // DELETE_COOKIE_EXPIRED
nharper352933e2016-09-30 18:24:57332 {CookieStore::ChangeCause::EXPIRED, true},
mkwstbe84af312015-02-20 08:52:45333 // DELETE_COOKIE_EVICTED
nharper352933e2016-09-30 18:24:57334 {CookieStore::ChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45335 // DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE
nharper68903362017-01-20 04:07:14336 {CookieStore::ChangeCause::EXPLICIT, false},
mkwstbe84af312015-02-20 08:52:45337 // DELETE_COOKIE_DONT_RECORD
nharper68903362017-01-20 04:07:14338 {CookieStore::ChangeCause::EXPLICIT, false},
mkwstbe84af312015-02-20 08:52:45339 // DELETE_COOKIE_EVICTED_DOMAIN
nharper352933e2016-09-30 18:24:57340 {CookieStore::ChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45341 // DELETE_COOKIE_EVICTED_GLOBAL
nharper352933e2016-09-30 18:24:57342 {CookieStore::ChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45343 // DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE
nharper352933e2016-09-30 18:24:57344 {CookieStore::ChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45345 // DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE
nharper352933e2016-09-30 18:24:57346 {CookieStore::ChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45347 // DELETE_COOKIE_EXPIRED_OVERWRITE
nharper352933e2016-09-30 18:24:57348 {CookieStore::ChangeCause::EXPIRED_OVERWRITE, true},
mkwstbe84af312015-02-20 08:52:45349 // DELETE_COOKIE_CONTROL_CHAR
nharper352933e2016-09-30 18:24:57350 {CookieStore::ChangeCause::EVICTED, true},
jww82d99c12015-11-25 18:39:53351 // DELETE_COOKIE_NON_SECURE
nharper352933e2016-09-30 18:24:57352 {CookieStore::ChangeCause::EVICTED, true},
nharper68903362017-01-20 04:07:14353 // DELETE_COOKIE_CREATED_BETWEEN
354 {CookieStore::ChangeCause::EXPLICIT_DELETE_BETWEEN, true},
355 // DELETE_COOKIE_CREATED_BETWEEN_WITH_PREDICATE
356 {CookieStore::ChangeCause::EXPLICIT_DELETE_PREDICATE, true},
357 // DELETE_COOKIE_SINGLE
358 {CookieStore::ChangeCause::EXPLICIT_DELETE_SINGLE, true},
359 // DELETE_COOKIE_CANONICAL
360 {CookieStore::ChangeCause::EXPLICIT_DELETE_CANONICAL, true},
mkwstbe84af312015-02-20 08:52:45361 // DELETE_COOKIE_LAST_ENTRY
nharper68903362017-01-20 04:07:14362 {CookieStore::ChangeCause::EXPLICIT, false}};
[email protected]8bb846f2011-03-23 12:08:18363
ellyjones399e35a22014-10-27 11:09:56364void RunAsync(scoped_refptr<base::TaskRunner> proxy,
msarda0aad8f02014-10-30 09:22:39365 const CookieStore::CookieChangedCallback& callback,
366 const CanonicalCookie& cookie,
nharper352933e2016-09-30 18:24:57367 CookieStore::ChangeCause cause) {
368 proxy->PostTask(FROM_HERE, base::Bind(callback, cookie, cause));
ellyjones399e35a22014-10-27 11:09:56369}
370
jwwc00ac712016-05-05 22:21:44371bool IsCookieEligibleForEviction(CookiePriority current_priority_level,
372 bool protect_secure_cookies,
373 const CanonicalCookie* cookie) {
mmenke645ca6772016-06-17 18:46:43374 if (cookie->Priority() == current_priority_level && protect_secure_cookies)
375 return !cookie->IsSecure();
jwwc00ac712016-05-05 22:21:44376
mmenke645ca6772016-06-17 18:46:43377 return cookie->Priority() == current_priority_level;
378}
jwwc00ac712016-05-05 22:21:44379
mmenke645ca6772016-06-17 18:46:43380size_t CountCookiesForPossibleDeletion(
381 CookiePriority priority,
382 const CookieMonster::CookieItVector* cookies,
383 bool protect_secure_cookies) {
384 size_t cookies_count = 0U;
385 for (const auto& cookie : *cookies) {
386 if (cookie->second->Priority() == priority) {
387 if (!protect_secure_cookies || cookie->second->IsSecure())
388 cookies_count++;
389 }
390 }
391 return cookies_count;
jwwc00ac712016-05-05 22:21:44392}
393
[email protected]f48b9432011-01-11 07:25:40394} // namespace
395
Randy Smith0a522662017-08-30 19:35:34396CookieMonster::CookieMonster(PersistentCookieStore* store)
shessf0bc1182016-05-19 04:35:58397 : CookieMonster(
398 store,
nharper2b0ad9a2017-05-22 18:33:45399 nullptr,
shessf0bc1182016-05-19 04:35:58400 base::TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds)) {}
[email protected]2d0f89a2010-12-06 12:02:23401
[email protected]f48b9432011-01-11 07:25:40402CookieMonster::CookieMonster(PersistentCookieStore* store,
nharper2b0ad9a2017-05-22 18:33:45403 ChannelIDService* channel_id_service)
404 : CookieMonster(
405 store,
nharper2b0ad9a2017-05-22 18:33:45406 channel_id_service,
407 base::TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds)) {}
408
409CookieMonster::CookieMonster(PersistentCookieStore* store,
nharper2b0ad9a2017-05-22 18:33:45410 base::TimeDelta last_access_threshold)
Randy Smith0a522662017-08-30 19:35:34411 : CookieMonster(store, nullptr, last_access_threshold) {}
nharper2b0ad9a2017-05-22 18:33:45412
413CookieMonster::CookieMonster(PersistentCookieStore* store,
nharper2b0ad9a2017-05-22 18:33:45414 ChannelIDService* channel_id_service,
shessf0bc1182016-05-19 04:35:58415 base::TimeDelta last_access_threshold)
[email protected]f48b9432011-01-11 07:25:40416 : initialized_(false),
erikchen1dd72a72015-05-06 20:45:05417 started_fetching_all_cookies_(false),
418 finished_fetching_all_cookies_(false),
419 fetch_strategy_(kUnknownFetch),
mmenkef49fca0e2016-03-08 12:46:24420 seen_global_task_(false),
[email protected]f48b9432011-01-11 07:25:40421 store_(store),
shessf0bc1182016-05-19 04:35:58422 last_access_threshold_(last_access_threshold),
nharper2b0ad9a2017-05-22 18:33:45423 channel_id_service_(channel_id_service),
[email protected]82388662011-03-10 21:04:06424 last_statistic_record_time_(base::Time::Now()),
mmenkebe0910d2016-03-01 19:09:09425 persist_session_cookies_(false),
Randy Smith4780ccc2017-09-29 17:39:41426 global_hook_map_(std::make_unique<CookieChangedCallbackList>()),
mmenkebe0910d2016-03-01 19:09:09427 weak_ptr_factory_(this) {
[email protected]f48b9432011-01-11 07:25:40428 InitializeHistograms();
mmenke18dd8ba2016-02-01 18:42:10429 cookieable_schemes_.insert(
430 cookieable_schemes_.begin(), kDefaultCookieableSchemes,
431 kDefaultCookieableSchemes + kDefaultCookieableSchemesCount);
Nick Harper14e23332017-07-28 00:27:23432 if (channel_id_service_ && store_) {
433 // |store_| can outlive this CookieMonster, but there are no guarantees
434 // about the lifetime of |channel_id_service_| relative to |store_|. The
435 // only guarantee is that |channel_id_service_| will outlive this
436 // CookieMonster. To avoid the PersistentCookieStore retaining a pointer to
437 // the ChannelIDStore via this callback after this CookieMonster is
438 // destroyed, CookieMonster's d'tor sets the callback to a null callback.
439 store_->SetBeforeFlushCallback(
440 base::Bind(&ChannelIDStore::Flush,
441 base::Unretained(channel_id_service_->GetChannelIDStore())));
442 }
initial.commit586acc5fe2008-07-26 22:42:52443}
444
[email protected]218aa6a12011-09-13 17:38:38445// Asynchronous CookieMonster API
446
rdsmith7ac81712017-06-22 17:09:54447void CookieMonster::SetCookieWithDetailsAsync(const GURL& url,
448 const std::string& name,
449 const std::string& value,
450 const std::string& domain,
451 const std::string& path,
452 Time creation_time,
453 Time expiration_time,
454 Time last_access_time,
455 bool secure,
456 bool http_only,
457 CookieSameSite same_site,
458 CookiePriority priority,
459 SetCookiesCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00460 DoCookieCallbackForURL(
461 base::BindOnce(
462 // base::Unretained is safe as DoCookieCallbackForURL stores
463 // the callback on |*this|, so the callback will not outlive
464 // the object.
465 &CookieMonster::SetCookieWithDetails, base::Unretained(this), url,
466 name, value, domain, path, creation_time, expiration_time,
467 last_access_time, secure, http_only, same_site, priority,
468 std::move(callback)),
469 url);
[email protected]218aa6a12011-09-13 17:38:38470}
471
rdsmith7ac81712017-06-22 17:09:54472void CookieMonster::FlushStore(base::OnceClosure callback) {
mmenkebe0910d2016-03-01 19:09:09473 DCHECK(thread_checker_.CalledOnValidThread());
mmenke606c59c2016-03-07 18:20:55474
nharper2b0ad9a2017-05-22 18:33:45475 if (initialized_ && store_.get()) {
rdsmith7ac81712017-06-22 17:09:54476 store_->Flush(std::move(callback));
rdsmithe5c701d2017-07-12 21:50:00477 } else if (callback) {
rdsmith7ac81712017-06-22 17:09:54478 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
479 std::move(callback));
nharper2b0ad9a2017-05-22 18:33:45480 }
mmenke74bcbd52016-01-21 17:17:56481}
482
mmenkeded79da2016-02-06 08:28:51483void CookieMonster::SetForceKeepSessionState() {
mmenkebe0910d2016-03-01 19:09:09484 DCHECK(thread_checker_.CalledOnValidThread());
mmenke606c59c2016-03-07 18:20:55485
mmenkeded79da2016-02-06 08:28:51486 if (store_)
487 store_->SetForceKeepSessionState();
488}
489
drogerd5d1278c2015-03-17 19:21:51490void CookieMonster::SetAllCookiesAsync(const CookieList& list,
rdsmith7ac81712017-06-22 17:09:54491 SetCookiesCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00492 DoCookieCallback(base::BindOnce(
493 // base::Unretained is safe as DoCookieCallbackForURL stores
494 // the callback on |*this|, so the callback will not outlive
495 // the object.
496 &CookieMonster::SetAllCookies, base::Unretained(this), list,
497 std::move(callback)));
drogerd5d1278c2015-03-17 19:21:51498}
499
rdsmitha6ce4442017-06-21 17:11:05500void CookieMonster::SetCanonicalCookieAsync(
501 std::unique_ptr<CanonicalCookie> cookie,
502 bool secure_source,
503 bool modify_http_only,
rdsmith7ac81712017-06-22 17:09:54504 SetCookiesCallback callback) {
rdsmitha6ce4442017-06-21 17:11:05505 DCHECK(cookie->IsCanonical());
rdsmitha6ce4442017-06-21 17:11:05506
rdsmithe5c701d2017-07-12 21:50:00507 // TODO(rdsmith): Switch to DoCookieCallbackForURL (or the equivalent).
rdsmitha6ce4442017-06-21 17:11:05508 // This is tricky because we don't have the scheme in this routine
rdsmithe5c701d2017-07-12 21:50:00509 // and DoCookieCallbackForURL uses
510 // cookie_util::GetEffectiveDomain(scheme, host)
rdsmitha6ce4442017-06-21 17:11:05511 // to generate the database key to block behind.
rdsmithe5c701d2017-07-12 21:50:00512 DoCookieCallback(base::BindOnce(
513 // base::Unretained is safe as DoCookieCallbackForURL stores
514 // the callback on |*this|, so the callback will not outlive
515 // the object.
516 &CookieMonster::SetCanonicalCookie, base::Unretained(this),
517 std::move(cookie), secure_source, modify_http_only, std::move(callback)));
rdsmitha6ce4442017-06-21 17:11:05518}
519
rdsmith7ac81712017-06-22 17:09:54520void CookieMonster::SetCookieWithOptionsAsync(const GURL& url,
521 const std::string& cookie_line,
522 const CookieOptions& options,
523 SetCookiesCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00524 DoCookieCallbackForURL(
525 base::BindOnce(
526 // base::Unretained is safe as DoCookieCallbackForURL stores
527 // the callback on |*this|, so the callback will not outlive
528 // the object.
529 &CookieMonster::SetCookieWithOptions, base::Unretained(this), url,
530 cookie_line, options, std::move(callback)),
531 url);
[email protected]218aa6a12011-09-13 17:38:38532}
533
rdsmith7ac81712017-06-22 17:09:54534void CookieMonster::GetCookiesWithOptionsAsync(const GURL& url,
535 const CookieOptions& options,
536 GetCookiesCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00537 DoCookieCallbackForURL(
538 base::BindOnce(
539 // base::Unretained is safe as DoCookieCallbackForURL stores
540 // the callback on |*this|, so the callback will not outlive
541 // the object.
542 &CookieMonster::GetCookiesWithOptions, base::Unretained(this), url,
543 options, std::move(callback)),
544 url);
[email protected]218aa6a12011-09-13 17:38:38545}
546
mkwstc611e6d2016-02-23 15:45:55547void CookieMonster::GetCookieListWithOptionsAsync(
mmenke74bcbd52016-01-21 17:17:56548 const GURL& url,
mkwstc611e6d2016-02-23 15:45:55549 const CookieOptions& options,
rdsmith7ac81712017-06-22 17:09:54550 GetCookieListCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00551 DoCookieCallbackForURL(
552 base::BindOnce(
553 // base::Unretained is safe as DoCookieCallbackForURL stores
554 // the callback on |*this|, so the callback will not outlive
555 // the object.
556 &CookieMonster::GetCookieListWithOptions, base::Unretained(this), url,
557 options, std::move(callback)),
558 url);
mmenke74bcbd52016-01-21 17:17:56559}
560
rdsmith7ac81712017-06-22 17:09:54561void CookieMonster::GetAllCookiesAsync(GetCookieListCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00562 DoCookieCallback(base::BindOnce(
563 // base::Unretained is safe as DoCookieCallbackForURL stores
564 // the callback on |*this|, so the callback will not outlive
565 // the object.
566 &CookieMonster::GetAllCookies, base::Unretained(this),
567 std::move(callback)));
mmenke9fa44f2d2016-01-22 23:36:39568}
569
[email protected]218aa6a12011-09-13 17:38:38570void CookieMonster::DeleteCookieAsync(const GURL& url,
571 const std::string& cookie_name,
rdsmith7ac81712017-06-22 17:09:54572 base::OnceClosure callback) {
rdsmithe5c701d2017-07-12 21:50:00573 DoCookieCallbackForURL(
574 base::BindOnce(
575 // base::Unretained is safe as DoCookieCallbackForURL stores
576 // the callback on |*this|, so the callback will not outlive
577 // the object.
578 &CookieMonster::DeleteCookie, base::Unretained(this), url,
579 cookie_name, std::move(callback)),
580 url);
[email protected]218aa6a12011-09-13 17:38:38581}
582
mmenke24379d52016-02-05 23:50:17583void CookieMonster::DeleteCanonicalCookieAsync(const CanonicalCookie& cookie,
rdsmith7ac81712017-06-22 17:09:54584 DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00585 DoCookieCallback(base::BindOnce(
586 // base::Unretained is safe as DoCookieCallbackForURL stores
587 // the callback on |*this|, so the callback will not outlive
588 // the object.
589 &CookieMonster::DeleteCanonicalCookie, base::Unretained(this), cookie,
590 std::move(callback)));
mmenke24379d52016-02-05 23:50:17591}
592
rdsmith7ac81712017-06-22 17:09:54593void CookieMonster::DeleteAllCreatedBetweenAsync(const Time& delete_begin,
594 const Time& delete_end,
595 DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00596 DoCookieCallback(base::BindOnce(
597 // base::Unretained is safe as DoCookieCallbackForURL stores
598 // the callback on |*this|, so the callback will not outlive
599 // the object.
600 &CookieMonster::DeleteAllCreatedBetween, base::Unretained(this),
601 delete_begin, delete_end, std::move(callback)));
mmenke74bcbd52016-01-21 17:17:56602}
603
dmurphfaea244c2016-04-09 00:42:30604void CookieMonster::DeleteAllCreatedBetweenWithPredicateAsync(
605 const Time& delete_begin,
606 const Time& delete_end,
607 const base::Callback<bool(const CanonicalCookie&)>& predicate,
rdsmith7ac81712017-06-22 17:09:54608 DeleteCallback callback) {
dmurphfaea244c2016-04-09 00:42:30609 if (predicate.is_null()) {
rdsmithe5c701d2017-07-12 21:50:00610 MaybeRunCookieCallback(std::move(callback), 0u);
dmurphfaea244c2016-04-09 00:42:30611 return;
612 }
rdsmithe5c701d2017-07-12 21:50:00613
614 DoCookieCallback(base::BindOnce(
615 // base::Unretained is safe as DoCookieCallbackForURL stores
616 // the callback on |*this|, so the callback will not outlive
617 // the object.
618 &CookieMonster::DeleteAllCreatedBetweenWithPredicate,
619 base::Unretained(this), delete_begin, delete_end, predicate,
620 std::move(callback)));
mmenke74bcbd52016-01-21 17:17:56621}
622
[email protected]264807b2012-04-25 14:49:37623void CookieMonster::DeleteSessionCookiesAsync(
rdsmith7ac81712017-06-22 17:09:54624 CookieStore::DeleteCallback callback) {
rdsmithe5c701d2017-07-12 21:50:00625 DoCookieCallback(base::BindOnce(
626 // base::Unretained is safe as DoCookieCallbackForURL stores
627 // the callback on |*this|, so the callback will not outlive
628 // the object.
629 &CookieMonster::DeleteSessionCookies, base::Unretained(this),
630 std::move(callback)));
[email protected]264807b2012-04-25 14:49:37631}
632
mmenke18dd8ba2016-02-01 18:42:10633void CookieMonster::SetCookieableSchemes(
634 const std::vector<std::string>& schemes) {
mmenkebe0910d2016-03-01 19:09:09635 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56636
637 // Calls to this method will have no effect if made after a WebView or
638 // CookieManager instance has been created.
mmenke18dd8ba2016-02-01 18:42:10639 if (initialized_)
mmenke74bcbd52016-01-21 17:17:56640 return;
mmenke74bcbd52016-01-21 17:17:56641
mmenke18dd8ba2016-02-01 18:42:10642 cookieable_schemes_ = schemes;
mmenke74bcbd52016-01-21 17:17:56643}
644
mmenke74bcbd52016-01-21 17:17:56645// This function must be called before the CookieMonster is used.
646void CookieMonster::SetPersistSessionCookies(bool persist_session_cookies) {
mmenkebe0910d2016-03-01 19:09:09647 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56648 DCHECK(!initialized_);
649 persist_session_cookies_ = persist_session_cookies;
650}
651
652bool CookieMonster::IsCookieableScheme(const std::string& scheme) {
mmenkebe0910d2016-03-01 19:09:09653 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56654
tripta.gdda72022017-06-19 05:16:23655 return base::ContainsValue(cookieable_schemes_, scheme);
mmenke74bcbd52016-01-21 17:17:56656}
657
mmenke18dd8ba2016-02-01 18:42:10658const char* const CookieMonster::kDefaultCookieableSchemes[] = {"http", "https",
659 "ws", "wss"};
mmenke74bcbd52016-01-21 17:17:56660const int CookieMonster::kDefaultCookieableSchemesCount =
661 arraysize(kDefaultCookieableSchemes);
662
danakja9850e12016-04-18 22:28:08663std::unique_ptr<CookieStore::CookieChangedSubscription>
mmenke74bcbd52016-01-21 17:17:56664CookieMonster::AddCallbackForCookie(const GURL& gurl,
665 const std::string& name,
666 const CookieChangedCallback& callback) {
mmenkebe0910d2016-03-01 19:09:09667 DCHECK(thread_checker_.CalledOnValidThread());
mmenke606c59c2016-03-07 18:20:55668
mmenke74bcbd52016-01-21 17:17:56669 std::pair<GURL, std::string> key(gurl, name);
670 if (hook_map_.count(key) == 0)
Jeremy Roman0579ed62017-08-29 15:56:19671 hook_map_[key] = std::make_unique<CookieChangedCallbackList>();
Randy Smith4780ccc2017-09-29 17:39:41672
673 std::unique_ptr<CookieMonsterCookieChangedSubscription> sub(
674 std::make_unique<CookieMonsterCookieChangedSubscription>(callback));
675 sub->SetCallbackSubscription(hook_map_[key]->Add(base::Bind(
676 &RunAsync, base::ThreadTaskRunnerHandle::Get(), sub->WeakCallback())));
677
678 return std::move(sub);
mmenke74bcbd52016-01-21 17:17:56679}
680
Randy Smithd32dc8c2017-08-30 18:03:40681std::unique_ptr<CookieStore::CookieChangedSubscription>
682CookieMonster::AddCallbackForAllChanges(const CookieChangedCallback& callback) {
683 DCHECK(thread_checker_.CalledOnValidThread());
684
Randy Smith4780ccc2017-09-29 17:39:41685 std::unique_ptr<CookieMonsterCookieChangedSubscription> sub(
686 std::make_unique<CookieMonsterCookieChangedSubscription>(callback));
687 sub->SetCallbackSubscription(global_hook_map_->Add(base::Bind(
688 &RunAsync, base::ThreadTaskRunnerHandle::Get(), sub->WeakCallback())));
689 return std::move(sub);
Randy Smithd32dc8c2017-08-30 18:03:40690}
691
nharper5babb5e62016-03-09 18:58:07692bool CookieMonster::IsEphemeral() {
693 return store_.get() == nullptr;
694}
695
mmenke74bcbd52016-01-21 17:17:56696CookieMonster::~CookieMonster() {
mmenkebe0910d2016-03-01 19:09:09697 DCHECK(thread_checker_.CalledOnValidThread());
mmenke05255cf2016-02-03 15:49:31698
Nick Harper14e23332017-07-28 00:27:23699 if (channel_id_service_ && store_) {
700 store_->SetBeforeFlushCallback(base::Closure());
701 }
702
Randy Smith0a522662017-08-30 19:35:34703 // TODO(mmenke): Does it really make sense to run
mmenke606c59c2016-03-07 18:20:55704 // CookieChanged callbacks when the CookieStore is destroyed?
mmenke05255cf2016-02-03 15:49:31705 for (CookieMap::iterator cookie_it = cookies_.begin();
706 cookie_it != cookies_.end();) {
707 CookieMap::iterator current_cookie_it = cookie_it;
708 ++cookie_it;
709 InternalDeleteCookie(current_cookie_it, false /* sync_to_store */,
710 DELETE_COOKIE_DONT_RECORD);
711 }
[email protected]8562034e2011-10-17 17:35:04712}
713
rdsmithe5c701d2017-07-12 21:50:00714void CookieMonster::SetCookieWithDetails(const GURL& url,
[email protected]dedec0b2013-02-28 04:50:10715 const std::string& name,
716 const std::string& value,
717 const std::string& domain,
718 const std::string& path,
mmenkefdd4fc72016-02-05 20:53:24719 base::Time creation_time,
720 base::Time expiration_time,
721 base::Time last_access_time,
[email protected]dedec0b2013-02-28 04:50:10722 bool secure,
[email protected]ab2d75c82013-04-19 18:39:04723 bool http_only,
mkwste1a29582016-03-15 10:07:52724 CookieSameSite same_site,
rdsmithe5c701d2017-07-12 21:50:00725 CookiePriority priority,
726 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:09727 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]69bb5872010-01-12 20:33:52728
rdsmithe5c701d2017-07-12 21:50:00729 if (!HasCookieableScheme(url)) {
730 MaybeRunCookieCallback(std::move(callback), false);
731 return;
732 }
initial.commit586acc5fe2008-07-26 22:42:52733
rdsmithb4ecb4c2017-05-12 18:39:03734 // Validate consistency of passed arguments.
735 if (ParsedCookie::ParseTokenString(name) != name ||
736 ParsedCookie::ParseValueString(value) != value ||
737 ParsedCookie::ParseValueString(domain) != domain ||
738 ParsedCookie::ParseValueString(path) != path) {
rdsmithe5c701d2017-07-12 21:50:00739 MaybeRunCookieCallback(std::move(callback), false);
740 return;
rdsmithb4ecb4c2017-05-12 18:39:03741 }
742
rdsmithb4ecb4c2017-05-12 18:39:03743 std::string cookie_domain;
rdsmithe5c701d2017-07-12 21:50:00744 if (!cookie_util::GetCookieDomainWithString(url, domain, &cookie_domain)) {
745 MaybeRunCookieCallback(std::move(callback), false);
746 return;
747 }
rdsmithb4ecb4c2017-05-12 18:39:03748
749 std::string cookie_path = CanonicalCookie::CanonPathWithString(url, path);
rdsmithe5c701d2017-07-12 21:50:00750 if (!path.empty() && cookie_path != path) {
751 MaybeRunCookieCallback(std::move(callback), false);
752 return;
753 }
rdsmithb4ecb4c2017-05-12 18:39:03754
755 // Canonicalize path again to make sure it escapes characters as needed.
756 url::Component path_component(0, cookie_path.length());
757 url::RawCanonOutputT<char> canon_path;
758 url::Component canon_path_component;
759 url::CanonicalizePath(cookie_path.data(), path_component, &canon_path,
760 &canon_path_component);
761 cookie_path = std::string(canon_path.data() + canon_path_component.begin,
762 canon_path_component.len);
763
Jeremy Roman0579ed62017-08-29 15:56:19764 std::unique_ptr<CanonicalCookie> cc(std::make_unique<CanonicalCookie>(
rdsmitha6ce4442017-06-21 17:11:05765 name, value, cookie_domain, cookie_path, creation_time, expiration_time,
766 last_access_time, secure, http_only, same_site, priority));
[email protected]f48b9432011-01-11 07:25:40767
rdsmithe5c701d2017-07-12 21:50:00768 SetCanonicalCookie(std::move(cc), url.SchemeIsCryptographic(), true,
769 std::move(callback));
initial.commit586acc5fe2008-07-26 22:42:52770}
771
rdsmithe5c701d2017-07-12 21:50:00772void CookieMonster::GetAllCookies(GetCookieListCallback callback) {
mmenkebe0910d2016-03-01 19:09:09773 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40774
775 // This function is being called to scrape the cookie list for management UI
776 // or similar. We shouldn't show expired cookies in this list since it will
777 // just be confusing to users, and this function is called rarely enough (and
778 // is already slow enough) that it's OK to take the time to garbage collect
779 // the expired cookies now.
780 //
781 // Note that this does not prune cookies to be below our limits (if we've
782 // exceeded them) the way that calling GarbageCollect() would.
mkwstbe84af312015-02-20 08:52:45783 GarbageCollectExpired(
784 Time::Now(), CookieMapItPair(cookies_.begin(), cookies_.end()), NULL);
[email protected]f48b9432011-01-11 07:25:40785
786 // Copy the CanonicalCookie pointers from the map so that we can use the same
787 // sorter as elsewhere, then copy the result out.
788 std::vector<CanonicalCookie*> cookie_ptrs;
789 cookie_ptrs.reserve(cookies_.size());
avie7cd11a2016-10-11 02:00:35790 for (const auto& cookie : cookies_)
791 cookie_ptrs.push_back(cookie.second.get());
[email protected]f48b9432011-01-11 07:25:40792 std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
793
794 CookieList cookie_list;
795 cookie_list.reserve(cookie_ptrs.size());
vmpstr6d9996c82017-02-23 00:43:25796 for (auto* cookie_ptr : cookie_ptrs)
avie7cd11a2016-10-11 02:00:35797 cookie_list.push_back(*cookie_ptr);
[email protected]f48b9432011-01-11 07:25:40798
rdsmithe5c701d2017-07-12 21:50:00799 MaybeRunCookieCallback(std::move(callback), cookie_list);
[email protected]f325f1e12010-04-30 22:38:55800}
801
rdsmithe5c701d2017-07-12 21:50:00802void CookieMonster::GetCookieListWithOptions(const GURL& url,
803 const CookieOptions& options,
804 GetCookieListCallback callback) {
mmenkebe0910d2016-03-01 19:09:09805 DCHECK(thread_checker_.CalledOnValidThread());
initial.commit586acc5fe2008-07-26 22:42:52806
mkwstc611e6d2016-02-23 15:45:55807 CookieList cookies;
rdsmithe5c701d2017-07-12 21:50:00808 if (HasCookieableScheme(url)) {
809 std::vector<CanonicalCookie*> cookie_ptrs;
810 FindCookiesForHostAndDomain(url, options, &cookie_ptrs);
811 std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
mkwstc611e6d2016-02-23 15:45:55812
rdsmithe5c701d2017-07-12 21:50:00813 cookies.reserve(cookie_ptrs.size());
814 for (std::vector<CanonicalCookie*>::const_iterator it = cookie_ptrs.begin();
815 it != cookie_ptrs.end(); it++)
816 cookies.push_back(**it);
817 }
818 MaybeRunCookieCallback(std::move(callback), cookies);
initial.commit586acc5fe2008-07-26 22:42:52819}
820
rdsmithe5c701d2017-07-12 21:50:00821void CookieMonster::DeleteAllCreatedBetween(const Time& delete_begin,
822 const Time& delete_end,
823 DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09824 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]d0980332010-11-16 17:08:53825
rdsmitha5beda162017-07-08 13:55:42826 uint32_t num_deleted = 0;
[email protected]f48b9432011-01-11 07:25:40827 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
828 CookieMap::iterator curit = it;
avie7cd11a2016-10-11 02:00:35829 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:40830 ++it;
[email protected]d0980332010-11-16 17:08:53831
[email protected]f48b9432011-01-11 07:25:40832 if (cc->CreationDate() >= delete_begin &&
833 (delete_end.is_null() || cc->CreationDate() < delete_end)) {
mkwstbe84af312015-02-20 08:52:45834 InternalDeleteCookie(curit, true, /*sync_to_store*/
nharper68903362017-01-20 04:07:14835 DELETE_COOKIE_CREATED_BETWEEN);
[email protected]f48b9432011-01-11 07:25:40836 ++num_deleted;
initial.commit586acc5fe2008-07-26 22:42:52837 }
838 }
839
rdsmithe5c701d2017-07-12 21:50:00840 FlushStore(
841 base::BindOnce(&MayeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
842 callback ? base::BindOnce(std::move(callback), num_deleted)
843 : base::OnceClosure()));
[email protected]f48b9432011-01-11 07:25:40844}
845
rdsmithe5c701d2017-07-12 21:50:00846void CookieMonster::DeleteAllCreatedBetweenWithPredicate(
dmurphfaea244c2016-04-09 00:42:30847 const base::Time& delete_begin,
848 const base::Time& delete_end,
rdsmithe5c701d2017-07-12 21:50:00849 const base::Callback<bool(const CanonicalCookie&)>& predicate,
850 DeleteCallback callback) {
rdsmitha5beda162017-07-08 13:55:42851 uint32_t num_deleted = 0;
dmurphfaea244c2016-04-09 00:42:30852 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
853 CookieMap::iterator curit = it;
avie7cd11a2016-10-11 02:00:35854 CanonicalCookie* cc = curit->second.get();
dmurphfaea244c2016-04-09 00:42:30855 ++it;
[email protected]f48b9432011-01-11 07:25:40856
dmurphfaea244c2016-04-09 00:42:30857 if (cc->CreationDate() >= delete_begin &&
[email protected]d8428d52013-08-07 06:58:25858 // The assumption that null |delete_end| is equivalent to
859 // Time::Max() is confusing.
dmurphfaea244c2016-04-09 00:42:30860 (delete_end.is_null() || cc->CreationDate() < delete_end) &&
861 predicate.Run(*cc)) {
862 InternalDeleteCookie(curit, true, /*sync_to_store*/
nharper68903362017-01-20 04:07:14863 DELETE_COOKIE_CREATED_BETWEEN_WITH_PREDICATE);
dmurphfaea244c2016-04-09 00:42:30864 ++num_deleted;
[email protected]f48b9432011-01-11 07:25:40865 }
866 }
dmurphfaea244c2016-04-09 00:42:30867
rdsmithe5c701d2017-07-12 21:50:00868 FlushStore(
869 base::BindOnce(&MayeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
870 callback ? base::BindOnce(std::move(callback), num_deleted)
871 : base::OnceClosure()));
[email protected]f48b9432011-01-11 07:25:40872}
873
rdsmithe5c701d2017-07-12 21:50:00874void CookieMonster::SetCookieWithOptions(const GURL& url,
[email protected]f48b9432011-01-11 07:25:40875 const std::string& cookie_line,
rdsmithe5c701d2017-07-12 21:50:00876 const CookieOptions& options,
877 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:09878 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40879
880 if (!HasCookieableScheme(url)) {
rdsmithe5c701d2017-07-12 21:50:00881 MaybeRunCookieCallback(std::move(callback), false);
882 return;
[email protected]f48b9432011-01-11 07:25:40883 }
884
rdsmithe5c701d2017-07-12 21:50:00885 SetCookieWithCreationTimeAndOptions(url, cookie_line, Time(), options,
886 std::move(callback));
[email protected]f48b9432011-01-11 07:25:40887}
888
rdsmithe5c701d2017-07-12 21:50:00889void CookieMonster::GetCookiesWithOptions(const GURL& url,
890 const CookieOptions& options,
891 GetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:09892 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40893
rdsmithe5c701d2017-07-12 21:50:00894 std::string cookie_line;
895 if (HasCookieableScheme(url)) {
896 std::vector<CanonicalCookie*> cookies;
897 FindCookiesForHostAndDomain(url, options, &cookies);
898 std::sort(cookies.begin(), cookies.end(), CookieSorter);
[email protected]f48b9432011-01-11 07:25:40899
rdsmithe5c701d2017-07-12 21:50:00900 cookie_line = BuildCookieLine(cookies);
[email protected]f48b9432011-01-11 07:25:40901
rdsmithe5c701d2017-07-12 21:50:00902 VLOG(kVlogGetCookies) << "GetCookies() result: " << cookie_line;
903 }
904 MaybeRunCookieCallback(std::move(callback), cookie_line);
[email protected]f48b9432011-01-11 07:25:40905}
906
907void CookieMonster::DeleteCookie(const GURL& url,
rdsmithe5c701d2017-07-12 21:50:00908 const std::string& cookie_name,
909 base::OnceClosure callback) {
mmenkebe0910d2016-03-01 19:09:09910 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:40911
rdsmithe5c701d2017-07-12 21:50:00912 if (!HasCookieableScheme(url)) {
913 // TODO(rdsmith): Would be good to provide a failure indication here.
914 MaybeRunCookieCallback(std::move(callback));
[email protected]f48b9432011-01-11 07:25:40915 return;
rdsmithe5c701d2017-07-12 21:50:00916 }
[email protected]f48b9432011-01-11 07:25:40917
918 CookieOptions options;
919 options.set_include_httponly();
mkwstf71d0bd2016-03-21 14:15:24920 options.set_same_site_cookie_mode(
921 CookieOptions::SameSiteCookieMode::INCLUDE_STRICT_AND_LAX);
[email protected]f48b9432011-01-11 07:25:40922 // Get the cookies for this host and its domain(s).
923 std::vector<CanonicalCookie*> cookies;
mkwst72b65162016-02-22 19:58:54924 FindCookiesForHostAndDomain(url, options, &cookies);
[email protected]f48b9432011-01-11 07:25:40925 std::set<CanonicalCookie*> matching_cookies;
926
vmpstr6f21f242016-06-29 02:16:47927 for (auto* cookie : cookies) {
mmenke4379aeb2016-03-05 12:22:07928 if (cookie->Name() != cookie_name)
[email protected]f48b9432011-01-11 07:25:40929 continue;
mmenke4379aeb2016-03-05 12:22:07930 if (!cookie->IsOnPath(url.path()))
[email protected]f48b9432011-01-11 07:25:40931 continue;
mmenke4379aeb2016-03-05 12:22:07932 matching_cookies.insert(cookie);
[email protected]f48b9432011-01-11 07:25:40933 }
934
935 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
936 CookieMap::iterator curit = it;
937 ++it;
avie7cd11a2016-10-11 02:00:35938 if (matching_cookies.find(curit->second.get()) != matching_cookies.end()) {
nharper68903362017-01-20 04:07:14939 InternalDeleteCookie(curit, true, DELETE_COOKIE_SINGLE);
[email protected]f48b9432011-01-11 07:25:40940 }
941 }
rdsmithe5c701d2017-07-12 21:50:00942
943 FlushStore(base::BindOnce(&MayeRunDeleteCallback,
944 weak_ptr_factory_.GetWeakPtr(),
945 // No callback null check needed as BindOnce
946 // is not being called and MaybeRunDeleteCallback
947 // has its own check.
948 std::move(callback)));
[email protected]f48b9432011-01-11 07:25:40949}
950
rdsmithe5c701d2017-07-12 21:50:00951void CookieMonster::DeleteCanonicalCookie(const CanonicalCookie& cookie,
952 DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09953 DCHECK(thread_checker_.CalledOnValidThread());
mmenke24379d52016-02-05 23:50:17954
rdsmithe5c701d2017-07-12 21:50:00955 uint32_t result = 0u;
mmenke24379d52016-02-05 23:50:17956 for (CookieMapItPair its = cookies_.equal_range(GetKey(cookie.Domain()));
957 its.first != its.second; ++its.first) {
958 // The creation date acts as the unique index...
959 if (its.first->second->CreationDate() == cookie.CreationDate()) {
nharper68903362017-01-20 04:07:14960 InternalDeleteCookie(its.first, true, DELETE_COOKIE_CANONICAL);
rdsmithe5c701d2017-07-12 21:50:00961 result = 1u;
962 break;
mmenke24379d52016-02-05 23:50:17963 }
964 }
rdsmithe5c701d2017-07-12 21:50:00965 FlushStore(
966 base::BindOnce(&MayeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
967 callback ? base::BindOnce(std::move(callback), result)
968 : base::OnceClosure()));
mmenke24379d52016-02-05 23:50:17969}
970
rdsmithe5c701d2017-07-12 21:50:00971void CookieMonster::SetCookieWithCreationTimeForTesting(
972 const GURL& url,
973 const std::string& cookie_line,
974 const base::Time& creation_time,
975 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:09976 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56977 DCHECK(!store_.get()) << "This method is only to be used by unit-tests.";
mmenke74bcbd52016-01-21 17:17:56978
979 if (!HasCookieableScheme(url)) {
rdsmithe5c701d2017-07-12 21:50:00980 MaybeRunCookieCallback(std::move(callback), false);
981 return;
mmenke74bcbd52016-01-21 17:17:56982 }
983
984 MarkCookieStoreAsInitialized();
985 if (ShouldFetchAllCookiesWhenFetchingAnyCookie())
986 FetchAllCookiesIfNecessary();
987
rdsmithe5c701d2017-07-12 21:50:00988 return SetCookieWithCreationTimeAndOptions(
989 url, cookie_line, creation_time, CookieOptions(), std::move(callback));
mmenke74bcbd52016-01-21 17:17:56990}
991
rdsmithe5c701d2017-07-12 21:50:00992void CookieMonster::DeleteSessionCookies(DeleteCallback callback) {
mmenkebe0910d2016-03-01 19:09:09993 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]264807b2012-04-25 14:49:37994
rdsmitha5beda162017-07-08 13:55:42995 uint32_t num_deleted = 0;
[email protected]264807b2012-04-25 14:49:37996 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
997 CookieMap::iterator curit = it;
avie7cd11a2016-10-11 02:00:35998 CanonicalCookie* cc = curit->second.get();
[email protected]264807b2012-04-25 14:49:37999 ++it;
1000
1001 if (!cc->IsPersistent()) {
mkwstbe84af312015-02-20 08:52:451002 InternalDeleteCookie(curit, true, /*sync_to_store*/
[email protected]264807b2012-04-25 14:49:371003 DELETE_COOKIE_EXPIRED);
1004 ++num_deleted;
1005 }
1006 }
1007
rdsmithe5c701d2017-07-12 21:50:001008 FlushStore(
1009 base::BindOnce(&MayeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
1010 callback ? base::BindOnce(std::move(callback), num_deleted)
1011 : base::OnceClosure()));
[email protected]264807b2012-04-25 14:49:371012}
1013
erikchen1dd72a72015-05-06 20:45:051014void CookieMonster::MarkCookieStoreAsInitialized() {
mmenkebe0910d2016-03-01 19:09:091015 DCHECK(thread_checker_.CalledOnValidThread());
erikchen1dd72a72015-05-06 20:45:051016 initialized_ = true;
1017}
1018
1019void CookieMonster::FetchAllCookiesIfNecessary() {
mmenkebe0910d2016-03-01 19:09:091020 DCHECK(thread_checker_.CalledOnValidThread());
erikchen1dd72a72015-05-06 20:45:051021 if (store_.get() && !started_fetching_all_cookies_) {
1022 started_fetching_all_cookies_ = true;
1023 FetchAllCookies();
1024 }
1025}
1026
mmenke74bcbd52016-01-21 17:17:561027void CookieMonster::FetchAllCookies() {
mmenkebe0910d2016-03-01 19:09:091028 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:561029 DCHECK(store_.get()) << "Store must exist to initialize";
1030 DCHECK(!finished_fetching_all_cookies_)
1031 << "All cookies have already been fetched.";
1032
1033 // We bind in the current time so that we can report the wall-clock time for
1034 // loading cookies.
mmenkebe0910d2016-03-01 19:09:091035 store_->Load(base::Bind(&CookieMonster::OnLoaded,
1036 weak_ptr_factory_.GetWeakPtr(), TimeTicks::Now()));
mmenke74bcbd52016-01-21 17:17:561037}
1038
erikchen1dd72a72015-05-06 20:45:051039bool CookieMonster::ShouldFetchAllCookiesWhenFetchingAnyCookie() {
mmenkebe0910d2016-03-01 19:09:091040 DCHECK(thread_checker_.CalledOnValidThread());
1041
erikchen1dd72a72015-05-06 20:45:051042 if (fetch_strategy_ == kUnknownFetch) {
1043 const std::string group_name =
1044 base::FieldTrialList::FindFullName(kCookieMonsterFetchStrategyName);
1045 if (group_name == kFetchWhenNecessaryName) {
1046 fetch_strategy_ = kFetchWhenNecessary;
1047 } else if (group_name == kAlwaysFetchName) {
1048 fetch_strategy_ = kAlwaysFetch;
1049 } else {
1050 // The logic in the conditional is redundant, but it makes trials of
1051 // the Finch experiment more explicit.
1052 fetch_strategy_ = kAlwaysFetch;
1053 }
1054 }
1055
1056 return fetch_strategy_ == kAlwaysFetch;
1057}
1058
avie7cd11a2016-10-11 02:00:351059void CookieMonster::OnLoaded(
1060 TimeTicks beginning_time,
1061 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:091062 DCHECK(thread_checker_.CalledOnValidThread());
avie7cd11a2016-10-11 02:00:351063 StoreLoadedCookies(std::move(cookies));
[email protected]c7593fb22011-11-14 23:54:271064 histogram_time_blocked_on_load_->AddTime(TimeTicks::Now() - beginning_time);
[email protected]218aa6a12011-09-13 17:38:381065
1066 // Invoke the task queue of cookie request.
1067 InvokeQueue();
1068}
1069
avie7cd11a2016-10-11 02:00:351070void CookieMonster::OnKeyLoaded(
1071 const std::string& key,
1072 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:091073 DCHECK(thread_checker_.CalledOnValidThread());
1074
avie7cd11a2016-10-11 02:00:351075 StoreLoadedCookies(std::move(cookies));
[email protected]8562034e2011-10-17 17:35:041076
mmenkebe0910d2016-03-01 19:09:091077 auto tasks_pending_for_key = tasks_pending_for_key_.find(key);
[email protected]8562034e2011-10-17 17:35:041078
mmenkebe0910d2016-03-01 19:09:091079 // TODO(mmenke): Can this be turned into a DCHECK?
1080 if (tasks_pending_for_key == tasks_pending_for_key_.end())
1081 return;
[email protected]bab72ec2013-10-30 20:50:021082
mmenkebe0910d2016-03-01 19:09:091083 // Run all tasks for the key. Note that running a task can result in multiple
1084 // tasks being added to the back of the deque.
1085 while (!tasks_pending_for_key->second.empty()) {
rdsmithe5c701d2017-07-12 21:50:001086 base::OnceClosure task = std::move(tasks_pending_for_key->second.front());
mmenkebe0910d2016-03-01 19:09:091087 tasks_pending_for_key->second.pop_front();
rdsmithe5c701d2017-07-12 21:50:001088 std::move(task).Run();
[email protected]8562034e2011-10-17 17:35:041089 }
mmenkebe0910d2016-03-01 19:09:091090
1091 tasks_pending_for_key_.erase(tasks_pending_for_key);
1092
1093 // This has to be done last, in case running a task queues a new task for the
1094 // key, to ensure tasks are run in the correct order.
1095 keys_loaded_.insert(key);
[email protected]8562034e2011-10-17 17:35:041096}
1097
[email protected]218aa6a12011-09-13 17:38:381098void CookieMonster::StoreLoadedCookies(
avie7cd11a2016-10-11 02:00:351099 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:091100 DCHECK(thread_checker_.CalledOnValidThread());
1101
mmenkebe0910d2016-03-01 19:09:091102 // Even if a key is expired, insert it so it can be garbage collected,
1103 // removed, and sync'd.
[email protected]6210ce52013-09-20 03:33:141104 CookieItVector cookies_with_control_chars;
1105
avie7cd11a2016-10-11 02:00:351106 for (auto& cookie : cookies) {
1107 int64_t cookie_creation_time = cookie->CreationDate().ToInternalValue();
[email protected]f48b9432011-01-11 07:25:401108
[email protected]8562034e2011-10-17 17:35:041109 if (creation_times_.insert(cookie_creation_time).second) {
avie7cd11a2016-10-11 02:00:351110 CanonicalCookie* cookie_ptr = cookie.get();
1111 CookieMap::iterator inserted = InternalInsertCookie(
rdsmith2709eee2017-06-20 22:43:271112 GetKey(cookie_ptr->Domain()), std::move(cookie), false);
avie7cd11a2016-10-11 02:00:351113 const Time cookie_access_time(cookie_ptr->LastAccessDate());
[email protected]8562034e2011-10-17 17:35:041114 if (earliest_access_time_.is_null() ||
1115 cookie_access_time < earliest_access_time_)
1116 earliest_access_time_ = cookie_access_time;
[email protected]6210ce52013-09-20 03:33:141117
avie7cd11a2016-10-11 02:00:351118 if (ContainsControlCharacter(cookie_ptr->Name()) ||
1119 ContainsControlCharacter(cookie_ptr->Value())) {
mkwstbe84af312015-02-20 08:52:451120 cookies_with_control_chars.push_back(inserted);
[email protected]6210ce52013-09-20 03:33:141121 }
[email protected]f48b9432011-01-11 07:25:401122 } else {
mkwstbe84af312015-02-20 08:52:451123 LOG(ERROR) << base::StringPrintf(
1124 "Found cookies with duplicate creation "
1125 "times in backing store: "
1126 "{name='%s', domain='%s', path='%s'}",
avie7cd11a2016-10-11 02:00:351127 cookie->Name().c_str(), cookie->Domain().c_str(),
1128 cookie->Path().c_str());
[email protected]f48b9432011-01-11 07:25:401129 }
1130 }
[email protected]f48b9432011-01-11 07:25:401131
[email protected]6210ce52013-09-20 03:33:141132 // Any cookies that contain control characters that we have loaded from the
1133 // persistent store should be deleted. See http://crbug.com/238041.
1134 for (CookieItVector::iterator it = cookies_with_control_chars.begin();
1135 it != cookies_with_control_chars.end();) {
1136 CookieItVector::iterator curit = it;
1137 ++it;
1138
1139 InternalDeleteCookie(*curit, true, DELETE_COOKIE_CONTROL_CHAR);
1140 }
1141
[email protected]f48b9432011-01-11 07:25:401142 // After importing cookies from the PersistentCookieStore, verify that
1143 // none of our other constraints are violated.
[email protected]f48b9432011-01-11 07:25:401144 // In particular, the backing store might have given us duplicate cookies.
[email protected]8562034e2011-10-17 17:35:041145
1146 // This method could be called multiple times due to priority loading, thus
1147 // cookies loaded in previous runs will be validated again, but this is OK
1148 // since they are expected to be much fewer than total DB.
[email protected]f48b9432011-01-11 07:25:401149 EnsureCookiesMapIsValid();
[email protected]218aa6a12011-09-13 17:38:381150}
[email protected]f48b9432011-01-11 07:25:401151
[email protected]218aa6a12011-09-13 17:38:381152void CookieMonster::InvokeQueue() {
mmenkebe0910d2016-03-01 19:09:091153 DCHECK(thread_checker_.CalledOnValidThread());
1154
mmenkef49fca0e2016-03-08 12:46:241155 // Move all per-key tasks into the global queue, if there are any. This is
1156 // protection about a race where the store learns about all cookies loading
1157 // before it learned about the cookies for a key loading.
1158
1159 // Needed to prevent any recursively queued tasks from going back into the
1160 // per-key queues.
1161 seen_global_task_ = true;
rdsmithe5c701d2017-07-12 21:50:001162 for (auto& tasks_for_key : tasks_pending_for_key_) {
1163 tasks_pending_.insert(tasks_pending_.begin(),
1164 std::make_move_iterator(tasks_for_key.second.begin()),
1165 std::make_move_iterator(tasks_for_key.second.end()));
mmenkef49fca0e2016-03-08 12:46:241166 }
1167 tasks_pending_for_key_.clear();
1168
mmenkebe0910d2016-03-01 19:09:091169 while (!tasks_pending_.empty()) {
rdsmithe5c701d2017-07-12 21:50:001170 base::OnceClosure request_task = std::move(tasks_pending_.front());
mmenkef49fca0e2016-03-08 12:46:241171 tasks_pending_.pop_front();
rdsmithe5c701d2017-07-12 21:50:001172 std::move(request_task).Run();
[email protected]218aa6a12011-09-13 17:38:381173 }
mmenkebe0910d2016-03-01 19:09:091174
mmenkef49fca0e2016-03-08 12:46:241175 DCHECK(tasks_pending_for_key_.empty());
1176
mmenkebe0910d2016-03-01 19:09:091177 finished_fetching_all_cookies_ = true;
1178 creation_times_.clear();
1179 keys_loaded_.clear();
[email protected]f48b9432011-01-11 07:25:401180}
1181
1182void CookieMonster::EnsureCookiesMapIsValid() {
mmenkebe0910d2016-03-01 19:09:091183 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401184
[email protected]f48b9432011-01-11 07:25:401185 // Iterate through all the of the cookies, grouped by host.
1186 CookieMap::iterator prev_range_end = cookies_.begin();
1187 while (prev_range_end != cookies_.end()) {
1188 CookieMap::iterator cur_range_begin = prev_range_end;
1189 const std::string key = cur_range_begin->first; // Keep a copy.
1190 CookieMap::iterator cur_range_end = cookies_.upper_bound(key);
1191 prev_range_end = cur_range_end;
1192
1193 // Ensure no equivalent cookies for this host.
ellyjonescabf57422015-08-21 18:44:511194 TrimDuplicateCookiesForKey(key, cur_range_begin, cur_range_end);
[email protected]f48b9432011-01-11 07:25:401195 }
[email protected]f48b9432011-01-11 07:25:401196}
1197
ellyjonescabf57422015-08-21 18:44:511198void CookieMonster::TrimDuplicateCookiesForKey(const std::string& key,
1199 CookieMap::iterator begin,
1200 CookieMap::iterator end) {
mmenkebe0910d2016-03-01 19:09:091201 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401202
1203 // Set of cookies ordered by creation time.
1204 typedef std::set<CookieMap::iterator, OrderByCreationTimeDesc> CookieSet;
1205
1206 // Helper map we populate to find the duplicates.
1207 typedef std::map<CookieSignature, CookieSet> EquivalenceMap;
1208 EquivalenceMap equivalent_cookies;
1209
1210 // The number of duplicate cookies that have been found.
1211 int num_duplicates = 0;
1212
1213 // Iterate through all of the cookies in our range, and insert them into
1214 // the equivalence map.
1215 for (CookieMap::iterator it = begin; it != end; ++it) {
1216 DCHECK_EQ(key, it->first);
avie7cd11a2016-10-11 02:00:351217 CanonicalCookie* cookie = it->second.get();
[email protected]f48b9432011-01-11 07:25:401218
mkwstbe84af312015-02-20 08:52:451219 CookieSignature signature(cookie->Name(), cookie->Domain(), cookie->Path());
[email protected]f48b9432011-01-11 07:25:401220 CookieSet& set = equivalent_cookies[signature];
1221
1222 // We found a duplicate!
1223 if (!set.empty())
1224 num_duplicates++;
1225
1226 // We save the iterator into |cookies_| rather than the actual cookie
1227 // pointer, since we may need to delete it later.
1228 bool insert_success = set.insert(it).second;
mkwstbe84af312015-02-20 08:52:451229 DCHECK(insert_success)
1230 << "Duplicate creation times found in duplicate cookie name scan.";
[email protected]f48b9432011-01-11 07:25:401231 }
1232
1233 // If there were no duplicates, we are done!
1234 if (num_duplicates == 0)
ellyjonescabf57422015-08-21 18:44:511235 return;
[email protected]f48b9432011-01-11 07:25:401236
1237 // Make sure we find everything below that we did above.
1238 int num_duplicates_found = 0;
1239
1240 // Otherwise, delete all the duplicate cookies, both from our in-memory store
1241 // and from the backing store.
1242 for (EquivalenceMap::iterator it = equivalent_cookies.begin();
mkwstbe84af312015-02-20 08:52:451243 it != equivalent_cookies.end(); ++it) {
[email protected]f48b9432011-01-11 07:25:401244 const CookieSignature& signature = it->first;
1245 CookieSet& dupes = it->second;
1246
1247 if (dupes.size() <= 1)
1248 continue; // This cookiename/path has no duplicates.
1249 num_duplicates_found += dupes.size() - 1;
1250
1251 // Since |dups| is sorted by creation time (descending), the first cookie
1252 // is the most recent one, so we will keep it. The rest are duplicates.
1253 dupes.erase(dupes.begin());
1254
1255 LOG(ERROR) << base::StringPrintf(
1256 "Found %d duplicate cookies for host='%s', "
1257 "with {name='%s', domain='%s', path='%s'}",
mkwstbe84af312015-02-20 08:52:451258 static_cast<int>(dupes.size()), key.c_str(), signature.name.c_str(),
1259 signature.domain.c_str(), signature.path.c_str());
[email protected]f48b9432011-01-11 07:25:401260
1261 // Remove all the cookies identified by |dupes|. It is valid to delete our
1262 // list of iterators one at a time, since |cookies_| is a multimap (they
1263 // don't invalidate existing iterators following deletion).
mkwstbe84af312015-02-20 08:52:451264 for (CookieSet::iterator dupes_it = dupes.begin(); dupes_it != dupes.end();
[email protected]f48b9432011-01-11 07:25:401265 ++dupes_it) {
[email protected]218aa6a12011-09-13 17:38:381266 InternalDeleteCookie(*dupes_it, true,
[email protected]f48b9432011-01-11 07:25:401267 DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE);
1268 }
1269 }
1270 DCHECK_EQ(num_duplicates, num_duplicates_found);
[email protected]f48b9432011-01-11 07:25:401271}
1272
[email protected]f48b9432011-01-11 07:25:401273void CookieMonster::FindCookiesForHostAndDomain(
1274 const GURL& url,
1275 const CookieOptions& options,
[email protected]f48b9432011-01-11 07:25:401276 std::vector<CanonicalCookie*>* cookies) {
mmenkebe0910d2016-03-01 19:09:091277 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401278
1279 const Time current_time(CurrentTime());
1280
1281 // Probe to save statistics relatively frequently. We do it here rather
1282 // than in the set path as many websites won't set cookies, and we
1283 // want to collect statistics whenever the browser's being used.
1284 RecordPeriodicStats(current_time);
1285
[email protected]8e1583672012-02-11 04:39:411286 // Can just dispatch to FindCookiesForKey
1287 const std::string key(GetKey(url.host()));
mkwst72b65162016-02-22 19:58:541288 FindCookiesForKey(key, url, options, current_time, cookies);
[email protected]f48b9432011-01-11 07:25:401289}
1290
[email protected]dedec0b2013-02-28 04:50:101291void CookieMonster::FindCookiesForKey(const std::string& key,
1292 const GURL& url,
1293 const CookieOptions& options,
1294 const Time& current,
[email protected]dedec0b2013-02-28 04:50:101295 std::vector<CanonicalCookie*>* cookies) {
mmenkebe0910d2016-03-01 19:09:091296 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401297
[email protected]f48b9432011-01-11 07:25:401298 for (CookieMapItPair its = cookies_.equal_range(key);
mkwstbe84af312015-02-20 08:52:451299 its.first != its.second;) {
[email protected]f48b9432011-01-11 07:25:401300 CookieMap::iterator curit = its.first;
avie7cd11a2016-10-11 02:00:351301 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:401302 ++its.first;
1303
1304 // If the cookie is expired, delete it.
mmenke3c79a652016-02-12 14:39:201305 if (cc->IsExpired(current)) {
[email protected]f48b9432011-01-11 07:25:401306 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
1307 continue;
1308 }
1309
[email protected]65f4e7e2012-12-12 21:56:541310 // Filter out cookies that should not be included for a request to the
1311 // given |url|. HTTP only cookies are filtered depending on the passed
1312 // cookie |options|.
1313 if (!cc->IncludeForRequestURL(url, options))
[email protected]f48b9432011-01-11 07:25:401314 continue;
1315
[email protected]65f4e7e2012-12-12 21:56:541316 // Add this cookie to the set of matching cookies. Update the access
[email protected]f48b9432011-01-11 07:25:401317 // time if we've been requested to do so.
mkwst72b65162016-02-22 19:58:541318 if (options.update_access_time()) {
[email protected]f48b9432011-01-11 07:25:401319 InternalUpdateCookieAccessTime(cc, current);
1320 }
1321 cookies->push_back(cc);
1322 }
1323}
1324
Mike Westc4a777b2017-10-06 14:04:201325bool CookieMonster::DeleteAnyEquivalentCookie(
1326 const std::string& key,
1327 const CanonicalCookie& ecc,
1328 bool source_secure,
1329 bool skip_httponly,
1330 bool already_expired,
1331 base::Time* creation_date_to_inherit) {
mmenkebe0910d2016-03-01 19:09:091332 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401333
1334 bool found_equivalent_cookie = false;
1335 bool skipped_httponly = false;
jww601411a2015-11-20 19:46:571336 bool skipped_secure_cookie = false;
jww31e32632015-12-16 23:38:341337
1338 histogram_cookie_delete_equivalent_->Add(COOKIE_DELETE_EQUIVALENT_ATTEMPT);
1339
[email protected]f48b9432011-01-11 07:25:401340 for (CookieMapItPair its = cookies_.equal_range(key);
mkwstbe84af312015-02-20 08:52:451341 its.first != its.second;) {
[email protected]f48b9432011-01-11 07:25:401342 CookieMap::iterator curit = its.first;
avie7cd11a2016-10-11 02:00:351343 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:401344 ++its.first;
1345
jwwa26e439d2017-01-27 18:17:271346 // If the cookie is being set from an insecure scheme, then if a cookie
1347 // already exists with the same name and it is Secure, then the cookie
1348 // should *not* be updated if they domain-match and ignoring the path
1349 // attribute.
jww601411a2015-11-20 19:46:571350 //
jwwa26e439d2017-01-27 18:17:271351 // See: https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone
rdsmith2709eee2017-06-20 22:43:271352 if (cc->IsSecure() && !source_secure &&
mmenke2830b0722016-07-20 16:02:501353 ecc.IsEquivalentForSecureCookieMatching(*cc)) {
jww601411a2015-11-20 19:46:571354 skipped_secure_cookie = true;
jww31e32632015-12-16 23:38:341355 histogram_cookie_delete_equivalent_->Add(
1356 COOKIE_DELETE_EQUIVALENT_SKIPPING_SECURE);
1357 // If the cookie is equivalent to the new cookie and wouldn't have been
1358 // skipped for being HTTP-only, record that it is a skipped secure cookie
1359 // that would have been deleted otherwise.
1360 if (ecc.IsEquivalent(*cc)) {
jwwa9a0d482015-12-16 18:19:411361 found_equivalent_cookie = true;
jww31e32632015-12-16 23:38:341362
1363 if (!skip_httponly || !cc->IsHttpOnly()) {
1364 histogram_cookie_delete_equivalent_->Add(
1365 COOKIE_DELETE_EQUIVALENT_WOULD_HAVE_DELETED);
1366 }
1367 }
jww601411a2015-11-20 19:46:571368 } else if (ecc.IsEquivalent(*cc)) {
[email protected]f48b9432011-01-11 07:25:401369 // We should never have more than one equivalent cookie, since they should
jww601411a2015-11-20 19:46:571370 // overwrite each other, unless secure cookies require secure scheme is
1371 // being enforced. In that case, cookies with different paths might exist
1372 // and be considered equivalent.
mkwstbe84af312015-02-20 08:52:451373 CHECK(!found_equivalent_cookie)
1374 << "Duplicate equivalent cookies found, cookie store is corrupted.";
[email protected]f48b9432011-01-11 07:25:401375 if (skip_httponly && cc->IsHttpOnly()) {
1376 skipped_httponly = true;
1377 } else {
jww31e32632015-12-16 23:38:341378 histogram_cookie_delete_equivalent_->Add(
1379 COOKIE_DELETE_EQUIVALENT_FOUND);
Mike West86149882017-07-28 10:41:491380 if (cc->Value() == ecc.Value()) {
Mike Westc4a777b2017-10-06 14:04:201381 *creation_date_to_inherit = cc->CreationDate();
Mike West86149882017-07-28 10:41:491382 histogram_cookie_delete_equivalent_->Add(
1383 COOKIE_DELETE_EQUIVALENT_FOUND_WITH_SAME_VALUE);
1384 }
mkwstbe84af312015-02-20 08:52:451385 InternalDeleteCookie(curit, true, already_expired
1386 ? DELETE_COOKIE_EXPIRED_OVERWRITE
1387 : DELETE_COOKIE_OVERWRITE);
[email protected]f48b9432011-01-11 07:25:401388 }
1389 found_equivalent_cookie = true;
1390 }
1391 }
jww601411a2015-11-20 19:46:571392 return skipped_httponly || skipped_secure_cookie;
[email protected]f48b9432011-01-11 07:25:401393}
1394
[email protected]6210ce52013-09-20 03:33:141395CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie(
1396 const std::string& key,
avie7cd11a2016-10-11 02:00:351397 std::unique_ptr<CanonicalCookie> cc,
[email protected]6210ce52013-09-20 03:33:141398 bool sync_to_store) {
mmenkebe0910d2016-03-01 19:09:091399 DCHECK(thread_checker_.CalledOnValidThread());
avie7cd11a2016-10-11 02:00:351400 CanonicalCookie* cc_ptr = cc.get();
mmenkebe0910d2016-03-01 19:09:091401
avie7cd11a2016-10-11 02:00:351402 if ((cc_ptr->IsPersistent() || persist_session_cookies_) && store_.get() &&
[email protected]90499482013-06-01 00:39:501403 sync_to_store)
avie7cd11a2016-10-11 02:00:351404 store_->AddCookie(*cc_ptr);
[email protected]6210ce52013-09-20 03:33:141405 CookieMap::iterator inserted =
avie7cd11a2016-10-11 02:00:351406 cookies_.insert(CookieMap::value_type(key, std::move(cc)));
mkwstc1aa4cc2015-04-03 19:57:451407
1408 // See InitializeHistograms() for details.
avie7cd11a2016-10-11 02:00:351409 int32_t type_sample = cc_ptr->SameSite() != CookieSameSite::NO_RESTRICTION
mkwste1a29582016-03-15 10:07:521410 ? 1 << COOKIE_TYPE_SAME_SITE
1411 : 0;
avie7cd11a2016-10-11 02:00:351412 type_sample |= cc_ptr->IsHttpOnly() ? 1 << COOKIE_TYPE_HTTPONLY : 0;
1413 type_sample |= cc_ptr->IsSecure() ? 1 << COOKIE_TYPE_SECURE : 0;
mkwst46549412016-02-01 10:05:371414 histogram_cookie_type_->Add(type_sample);
estark7feb65c2b2015-08-21 23:38:201415
Randy Smithd32dc8c2017-08-30 18:03:401416 RunCookieChangedCallbacks(*cc_ptr, true, CookieStore::ChangeCause::INSERTED);
[email protected]6210ce52013-09-20 03:33:141417
1418 return inserted;
[email protected]f48b9432011-01-11 07:25:401419}
1420
rdsmithe5c701d2017-07-12 21:50:001421void CookieMonster::SetCookieWithCreationTimeAndOptions(
[email protected]34602282010-02-03 22:14:151422 const GURL& url,
1423 const std::string& cookie_line,
1424 const Time& creation_time_or_null,
rdsmithe5c701d2017-07-12 21:50:001425 const CookieOptions& options,
1426 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:091427 DCHECK(thread_checker_.CalledOnValidThread());
initial.commit586acc5fe2008-07-26 22:42:521428
[email protected]4d3ce782010-10-29 18:31:281429 VLOG(kVlogSetCookies) << "SetCookie() line: " << cookie_line;
initial.commit586acc5fe2008-07-26 22:42:521430
[email protected]34602282010-02-03 22:14:151431 Time creation_time = creation_time_or_null;
1432 if (creation_time.is_null()) {
1433 creation_time = CurrentTime();
1434 last_time_seen_ = creation_time;
1435 }
1436
danakja9850e12016-04-18 22:28:081437 std::unique_ptr<CanonicalCookie> cc(
[email protected]abbd13b2012-11-15 17:54:201438 CanonicalCookie::Create(url, cookie_line, creation_time, options));
initial.commit586acc5fe2008-07-26 22:42:521439
1440 if (!cc.get()) {
[email protected]4d3ce782010-10-29 18:31:281441 VLOG(kVlogSetCookies) << "WARNING: Failed to allocate CanonicalCookie";
rdsmithe5c701d2017-07-12 21:50:001442 MaybeRunCookieCallback(std::move(callback), false);
1443 return;
initial.commit586acc5fe2008-07-26 22:42:521444 }
rdsmithe5c701d2017-07-12 21:50:001445 SetCanonicalCookie(std::move(cc), url.SchemeIsCryptographic(),
1446 !options.exclude_httponly(), std::move(callback));
[email protected]f325f1e12010-04-30 22:38:551447}
initial.commit586acc5fe2008-07-26 22:42:521448
rdsmithe5c701d2017-07-12 21:50:001449void CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc,
rdsmith2709eee2017-06-20 22:43:271450 bool secure_source,
rdsmithe5c701d2017-07-12 21:50:001451 bool modify_http_only,
1452 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:091453 DCHECK(thread_checker_.CalledOnValidThread());
1454
Randy Smith10400072017-08-03 04:08:311455 if ((cc->IsSecure() && !secure_source) ||
1456 (cc->IsHttpOnly() && !modify_http_only)) {
rdsmithe5c701d2017-07-12 21:50:001457 MaybeRunCookieCallback(std::move(callback), false);
1458 return;
1459 }
rdsmith2709eee2017-06-20 22:43:271460
mmenkeea4cd402016-02-02 04:03:101461 const std::string key(GetKey(cc->Domain()));
rdsmitha6ce4442017-06-21 17:11:051462
1463 // TODO(mmenke): This class assumes each cookie to have a unique creation
1464 // time. Allowing the caller to set the creation time violates that
1465 // assumption. Worth fixing? Worth noting that time changes between browser
1466 // restarts can cause the same issue.
1467 base::Time creation_date = cc->CreationDate();
1468 if (creation_date.is_null()) {
1469 creation_date = CurrentTime();
1470 cc->SetCreationDate(creation_date);
1471 last_time_seen_ = creation_date;
1472 }
1473 bool already_expired = cc->IsExpired(creation_date);
ellyjones399e35a22014-10-27 11:09:561474
Mike Westc4a777b2017-10-06 14:04:201475 base::Time creation_date_to_inherit;
rdsmith2709eee2017-06-20 22:43:271476 if (DeleteAnyEquivalentCookie(key, *cc, secure_source, !modify_http_only,
Mike Westc4a777b2017-10-06 14:04:201477 already_expired, &creation_date_to_inherit)) {
jww601411a2015-11-20 19:46:571478 std::string error;
jwwa26e439d2017-01-27 18:17:271479 error =
1480 "SetCookie() not clobbering httponly cookie or secure cookie for "
1481 "insecure scheme";
jww601411a2015-11-20 19:46:571482
1483 VLOG(kVlogSetCookies) << error;
rdsmithe5c701d2017-07-12 21:50:001484 MaybeRunCookieCallback(std::move(callback), false);
1485 return;
[email protected]3a96c742008-11-19 19:46:271486 }
initial.commit586acc5fe2008-07-26 22:42:521487
mkwstbe84af312015-02-20 08:52:451488 VLOG(kVlogSetCookies) << "SetCookie() key: " << key
mmenkeea4cd402016-02-02 04:03:101489 << " cc: " << cc->DebugString();
initial.commit586acc5fe2008-07-26 22:42:521490
1491 // Realize that we might be setting an expired cookie, and the only point
1492 // was to delete the cookie which we've already done.
mmenke3c79a652016-02-12 14:39:201493 if (!already_expired) {
[email protected]374f58b2010-07-20 15:29:261494 // See InitializeHistograms() for details.
mmenkeea4cd402016-02-02 04:03:101495 if (cc->IsPersistent()) {
[email protected]8475bee2011-03-17 18:40:241496 histogram_expiration_duration_minutes_->Add(
rdsmitha6ce4442017-06-21 17:11:051497 (cc->ExpiryDate() - creation_date).InMinutes());
[email protected]8475bee2011-03-17 18:40:241498 }
1499
rdsmith2709eee2017-06-20 22:43:271500 // Histogram the type of scheme used on URLs that set cookies. This
1501 // intentionally includes cookies that are set or overwritten by
1502 // http:// URLs, but not cookies that are cleared by http:// URLs, to
1503 // understand if the former behavior can be deprecated for Secure
1504 // cookies.
1505 CookieSource cookie_source_sample =
1506 (secure_source
1507 ? (cc->IsSecure()
1508 ? COOKIE_SOURCE_SECURE_COOKIE_CRYPTOGRAPHIC_SCHEME
1509 : COOKIE_SOURCE_NONSECURE_COOKIE_CRYPTOGRAPHIC_SCHEME)
1510 : (cc->IsSecure()
1511 ? COOKIE_SOURCE_SECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME
1512 : COOKIE_SOURCE_NONSECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME));
1513 histogram_cookie_source_scheme_->Add(cookie_source_sample);
1514
Mike Westc4a777b2017-10-06 14:04:201515 if (!creation_date_to_inherit.is_null()) {
1516 cc->SetCreationDate(creation_date_to_inherit);
1517 // |last_time_seen_| is intentionally not updated, as moving it into the
1518 // past might cause duplicate cookie creation dates. See
1519 // `CookieMonster::CurrentTime()` for details.
1520 }
1521
rdsmith2709eee2017-06-20 22:43:271522 InternalInsertCookie(key, std::move(cc), true);
[email protected]348dd662013-03-13 20:25:071523 } else {
1524 VLOG(kVlogSetCookies) << "SetCookie() not storing already expired cookie.";
[email protected]c4058fb2010-06-22 17:25:261525 }
initial.commit586acc5fe2008-07-26 22:42:521526
1527 // We assume that hopefully setting a cookie will be less common than
1528 // querying a cookie. Since setting a cookie can put us over our limits,
1529 // make sure that we garbage collect... We can also make the assumption that
1530 // if a cookie was set, in the common case it will be used soon after,
1531 // and we will purge the expired cookies in GetCookies().
rdsmitha6ce4442017-06-21 17:11:051532 GarbageCollect(creation_date, key);
initial.commit586acc5fe2008-07-26 22:42:521533
rdsmithe5c701d2017-07-12 21:50:001534 MaybeRunCookieCallback(std::move(callback), true);
initial.commit586acc5fe2008-07-26 22:42:521535}
1536
rdsmithe5c701d2017-07-12 21:50:001537void CookieMonster::SetAllCookies(CookieList list,
1538 SetCookiesCallback callback) {
mmenkebe0910d2016-03-01 19:09:091539 DCHECK(thread_checker_.CalledOnValidThread());
rdsmithe5c701d2017-07-12 21:50:001540
rdsmith0e84cea2017-07-13 03:09:531541 // Nuke the existing store.
1542 while (!cookies_.empty()) {
1543 // TODO(rdsmith): The CANONICAL is a lie.
1544 InternalDeleteCookie(cookies_.begin(), true, DELETE_COOKIE_CANONICAL);
rdsmithe5c701d2017-07-12 21:50:001545 }
1546
rdsmith0e84cea2017-07-13 03:09:531547 // Set all passed in cookies.
mmenkeea4cd402016-02-02 04:03:101548 for (const auto& cookie : list) {
rdsmith2709eee2017-06-20 22:43:271549 const std::string key(GetKey(cookie.Domain()));
1550 Time creation_time = cookie.CreationDate();
rdsmith0e84cea2017-07-13 03:09:531551 if (cookie.IsExpired(creation_time))
rdsmith2709eee2017-06-20 22:43:271552 continue;
1553
1554 if (cookie.IsPersistent()) {
1555 histogram_expiration_duration_minutes_->Add(
1556 (cookie.ExpiryDate() - creation_time).InMinutes());
mmenkeea4cd402016-02-02 04:03:101557 }
rdsmith2709eee2017-06-20 22:43:271558
Jeremy Roman0579ed62017-08-29 15:56:191559 InternalInsertCookie(key, std::make_unique<CanonicalCookie>(cookie), true);
rdsmith2709eee2017-06-20 22:43:271560 GarbageCollect(creation_time, key);
drogerd5d1278c2015-03-17 19:21:511561 }
1562
rdsmith2709eee2017-06-20 22:43:271563 // TODO(rdsmith): If this function always returns the same value, it
1564 // shouldn't have a return value. But it should also be deleted (see
1565 // https://codereview.chromium.org/2882063002/#msg64), which would
1566 // solve the return value problem.
rdsmithe5c701d2017-07-12 21:50:001567 MaybeRunCookieCallback(std::move(callback), true);
drogerd5d1278c2015-03-17 19:21:511568}
1569
[email protected]7a964a72010-09-07 19:33:261570void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc,
1571 const Time& current) {
mmenkebe0910d2016-03-01 19:09:091572 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041573
[email protected]77e0a462008-11-01 00:43:351574 // Based off the Mozilla code. When a cookie has been accessed recently,
1575 // don't bother updating its access time again. This reduces the number of
1576 // updates we do during pageload, which in turn reduces the chance our storage
1577 // backend will hit its batch thresholds and be forced to update.
[email protected]77e0a462008-11-01 00:43:351578 if ((current - cc->LastAccessDate()) < last_access_threshold_)
1579 return;
1580
1581 cc->SetLastAccessDate(current);
[email protected]90499482013-06-01 00:39:501582 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get())
[email protected]77e0a462008-11-01 00:43:351583 store_->UpdateCookieAccessTime(*cc);
1584}
1585
[email protected]6210ce52013-09-20 03:33:141586// InternalDeleteCookies must not invalidate iterators other than the one being
1587// deleted.
initial.commit586acc5fe2008-07-26 22:42:521588void CookieMonster::InternalDeleteCookie(CookieMap::iterator it,
[email protected]c4058fb2010-06-22 17:25:261589 bool sync_to_store,
1590 DeletionCause deletion_cause) {
mmenkebe0910d2016-03-01 19:09:091591 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041592
nharper352933e2016-09-30 18:24:571593 // Ideally, this would be asserted up where we define kChangeCauseMapping,
[email protected]8bb846f2011-03-23 12:08:181594 // but DeletionCause's visibility (or lack thereof) forces us to make
1595 // this check here.
nharper352933e2016-09-30 18:24:571596 static_assert(arraysize(kChangeCauseMapping) == DELETE_COOKIE_LAST_ENTRY + 1,
1597 "kChangeCauseMapping size should match DeletionCause size");
[email protected]8bb846f2011-03-23 12:08:181598
avie7cd11a2016-10-11 02:00:351599 CanonicalCookie* cc = it->second.get();
xiyuan8dbb89892015-04-13 17:04:301600 VLOG(kVlogSetCookies) << "InternalDeleteCookie()"
1601 << ", cause:" << deletion_cause
1602 << ", cc: " << cc->DebugString();
[email protected]7a964a72010-09-07 19:33:261603
[email protected]90499482013-06-01 00:39:501604 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get() &&
1605 sync_to_store)
initial.commit586acc5fe2008-07-26 22:42:521606 store_->DeleteCookie(*cc);
nharper352933e2016-09-30 18:24:571607 ChangeCausePair mapping = kChangeCauseMapping[deletion_cause];
Randy Smithd32dc8c2017-08-30 18:03:401608 RunCookieChangedCallbacks(*cc, mapping.notify, mapping.cause);
initial.commit586acc5fe2008-07-26 22:42:521609 cookies_.erase(it);
initial.commit586acc5fe2008-07-26 22:42:521610}
1611
[email protected]8807b322010-10-01 17:10:141612// Domain expiry behavior is unchanged by key/expiry scheme (the
[email protected]8ad5d462013-05-02 08:45:261613// meaning of the key is different, but that's not visible to this routine).
jww82d99c12015-11-25 18:39:531614size_t CookieMonster::GarbageCollect(const Time& current,
jwwa26e439d2017-01-27 18:17:271615 const std::string& key) {
mmenkebe0910d2016-03-01 19:09:091616 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041617
jww82d99c12015-11-25 18:39:531618 size_t num_deleted = 0;
mkwstbe84af312015-02-20 08:52:451619 Time safe_date(Time::Now() - TimeDelta::FromDays(kSafeFromGlobalPurgeDays));
initial.commit586acc5fe2008-07-26 22:42:521620
[email protected]8ad5d462013-05-02 08:45:261621 // Collect garbage for this key, minding cookie priorities.
[email protected]7a964a72010-09-07 19:33:261622 if (cookies_.count(key) > kDomainMaxCookies) {
[email protected]4d3ce782010-10-29 18:31:281623 VLOG(kVlogGarbageCollection) << "GarbageCollect() key: " << key;
[email protected]7a964a72010-09-07 19:33:261624
mkwst87734352016-03-03 17:36:231625 CookieItVector* cookie_its;
jww601411a2015-11-20 19:46:571626
mkwst87734352016-03-03 17:36:231627 CookieItVector non_expired_cookie_its;
1628 cookie_its = &non_expired_cookie_its;
jww82d99c12015-11-25 18:39:531629 num_deleted +=
mkwst87734352016-03-03 17:36:231630 GarbageCollectExpired(current, cookies_.equal_range(key), cookie_its);
jww82d99c12015-11-25 18:39:531631
mkwst87734352016-03-03 17:36:231632 if (cookie_its->size() > kDomainMaxCookies) {
[email protected]8ad5d462013-05-02 08:45:261633 VLOG(kVlogGarbageCollection) << "Deep Garbage Collect domain.";
1634 size_t purge_goal =
mkwst87734352016-03-03 17:36:231635 cookie_its->size() - (kDomainMaxCookies - kDomainPurgeCookies);
[email protected]8ad5d462013-05-02 08:45:261636 DCHECK(purge_goal > kDomainPurgeCookies);
1637
mkwste079ac412016-03-11 09:04:061638 // Sort the cookies by access date, from least-recent to most-recent.
1639 std::sort(cookie_its->begin(), cookie_its->end(), LRACookieSorter);
[email protected]8ad5d462013-05-02 08:45:261640
mkwste079ac412016-03-11 09:04:061641 // Remove all but the kDomainCookiesQuotaLow most-recently accessed
1642 // cookies with low-priority. Then, if cookies still need to be removed,
1643 // bump the quota and remove low- and medium-priority. Then, if cookies
1644 // _still_ need to be removed, bump the quota and remove cookies with
1645 // any priority.
jwwc00ac712016-05-05 22:21:441646 //
1647 // 1. Low-priority non-secure cookies.
1648 // 2. Low-priority secure cookies.
1649 // 3. Medium-priority non-secure cookies.
1650 // 4. High-priority non-secure cookies.
1651 // 5. Medium-priority secure cookies.
1652 // 6. High-priority secure cookies.
1653 const static struct {
1654 CookiePriority priority;
1655 bool protect_secure_cookies;
1656 } purge_rounds[] = {
1657 // 1. Low-priority non-secure cookies.
1658 {COOKIE_PRIORITY_LOW, true},
1659 // 2. Low-priority secure cookies.
1660 {COOKIE_PRIORITY_LOW, false},
1661 // 3. Medium-priority non-secure cookies.
1662 {COOKIE_PRIORITY_MEDIUM, true},
1663 // 4. High-priority non-secure cookies.
1664 {COOKIE_PRIORITY_HIGH, true},
1665 // 5. Medium-priority secure cookies.
1666 {COOKIE_PRIORITY_MEDIUM, false},
1667 // 6. High-priority secure cookies.
1668 {COOKIE_PRIORITY_HIGH, false},
1669 };
1670
mkwste079ac412016-03-11 09:04:061671 size_t quota = 0;
jwwc00ac712016-05-05 22:21:441672 for (const auto& purge_round : purge_rounds) {
mmenke645ca6772016-06-17 18:46:431673 // Adjust quota according to the priority of cookies. Each round should
1674 // protect certain number of cookies in order to avoid starvation.
1675 // For example, when each round starts to remove cookies, the number of
1676 // cookies of that priority are counted and a decision whether they
1677 // should be deleted or not is made. If yes, some number of cookies of
1678 // that priority are deleted considering the quota.
jwwc00ac712016-05-05 22:21:441679 switch (purge_round.priority) {
1680 case COOKIE_PRIORITY_LOW:
mmenke645ca6772016-06-17 18:46:431681 quota = kDomainCookiesQuotaLow;
jwwc00ac712016-05-05 22:21:441682 break;
1683 case COOKIE_PRIORITY_MEDIUM:
mmenke645ca6772016-06-17 18:46:431684 quota = kDomainCookiesQuotaMedium;
jwwc00ac712016-05-05 22:21:441685 break;
1686 case COOKIE_PRIORITY_HIGH:
mmenke645ca6772016-06-17 18:46:431687 quota = kDomainCookiesQuotaHigh;
jwwc00ac712016-05-05 22:21:441688 break;
1689 }
jwwc00ac712016-05-05 22:21:441690 size_t just_deleted = 0u;
jwwa26e439d2017-01-27 18:17:271691 // Purge up to |purge_goal| for all cookies at the given priority. This
1692 // path will be taken only if the initial non-secure purge did not evict
1693 // enough cookies.
jwwc00ac712016-05-05 22:21:441694 if (purge_goal > 0) {
1695 just_deleted = PurgeLeastRecentMatches(
1696 cookie_its, purge_round.priority, quota, purge_goal,
1697 purge_round.protect_secure_cookies);
1698 DCHECK_LE(just_deleted, purge_goal);
1699 purge_goal -= just_deleted;
1700 num_deleted += just_deleted;
1701 }
mkwst162d2712016-02-18 18:21:291702 }
mkwste079ac412016-03-11 09:04:061703
jwwc00ac712016-05-05 22:21:441704 DCHECK_EQ(0u, purge_goal);
[email protected]8807b322010-10-01 17:10:141705 }
initial.commit586acc5fe2008-07-26 22:42:521706 }
1707
[email protected]8ad5d462013-05-02 08:45:261708 // Collect garbage for everything. With firefox style we want to preserve
1709 // cookies accessed in kSafeFromGlobalPurgeDays, otherwise evict.
mkwstbe84af312015-02-20 08:52:451710 if (cookies_.size() > kMaxCookies && earliest_access_time_ < safe_date) {
[email protected]4d3ce782010-10-29 18:31:281711 VLOG(kVlogGarbageCollection) << "GarbageCollect() everything";
[email protected]8ad5d462013-05-02 08:45:261712 CookieItVector cookie_its;
jww82d99c12015-11-25 18:39:531713
[email protected]7a964a72010-09-07 19:33:261714 num_deleted += GarbageCollectExpired(
1715 current, CookieMapItPair(cookies_.begin(), cookies_.end()),
1716 &cookie_its);
jww82d99c12015-11-25 18:39:531717
[email protected]8ad5d462013-05-02 08:45:261718 if (cookie_its.size() > kMaxCookies) {
1719 VLOG(kVlogGarbageCollection) << "Deep Garbage Collect everything.";
1720 size_t purge_goal = cookie_its.size() - (kMaxCookies - kPurgeCookies);
1721 DCHECK(purge_goal > kPurgeCookies);
jww82d99c12015-11-25 18:39:531722
jwwa26e439d2017-01-27 18:17:271723 CookieItVector secure_cookie_its;
1724 CookieItVector non_secure_cookie_its;
1725 SplitCookieVectorIntoSecureAndNonSecure(cookie_its, &secure_cookie_its,
1726 &non_secure_cookie_its);
1727 size_t non_secure_purge_goal =
mmenkef4721d992017-06-07 17:13:591728 std::min<size_t>(purge_goal, non_secure_cookie_its.size());
jww82d99c12015-11-25 18:39:531729
mmenkef4721d992017-06-07 17:13:591730 base::Time earliest_non_secure_access_time;
jwwa26e439d2017-01-27 18:17:271731 size_t just_deleted = GarbageCollectLeastRecentlyAccessed(
mmenkef4721d992017-06-07 17:13:591732 current, safe_date, non_secure_purge_goal, non_secure_cookie_its,
1733 &earliest_non_secure_access_time);
jwwa26e439d2017-01-27 18:17:271734 num_deleted += just_deleted;
jww82d99c12015-11-25 18:39:531735
mmenkef4721d992017-06-07 17:13:591736 if (secure_cookie_its.size() == 0) {
1737 // This case is unlikely, but should still update
1738 // |earliest_access_time_| if only have non-secure cookies.
1739 earliest_access_time_ = earliest_non_secure_access_time;
1740 // Garbage collection can't delete all cookies.
1741 DCHECK(!earliest_access_time_.is_null());
1742 } else if (just_deleted < purge_goal) {
1743 size_t secure_purge_goal = std::min<size_t>(purge_goal - just_deleted,
1744 secure_cookie_its.size());
1745 base::Time earliest_secure_access_time;
jww82d99c12015-11-25 18:39:531746 num_deleted += GarbageCollectLeastRecentlyAccessed(
mmenkef4721d992017-06-07 17:13:591747 current, safe_date, secure_purge_goal, secure_cookie_its,
1748 &earliest_secure_access_time);
1749
1750 if (!earliest_non_secure_access_time.is_null() &&
1751 earliest_non_secure_access_time < earliest_secure_access_time) {
1752 earliest_access_time_ = earliest_non_secure_access_time;
1753 } else {
1754 earliest_access_time_ = earliest_secure_access_time;
1755 }
1756
1757 // Garbage collection can't delete all cookies.
1758 DCHECK(!earliest_access_time_.is_null());
jww82d99c12015-11-25 18:39:531759 }
mmenkef4721d992017-06-07 17:13:591760
1761 // If there are secure cookies, but deleting non-secure cookies was enough
1762 // to meet the purge goal, secure cookies are never examined, so
1763 // |earliest_access_time_| can't be determined. Leaving it alone will mean
1764 // it's no later than the real earliest last access time, so this won't
1765 // lead to any problems.
[email protected]8807b322010-10-01 17:10:141766 }
[email protected]c890ed192008-10-30 23:45:531767 }
1768
1769 return num_deleted;
1770}
1771
mkwste079ac412016-03-11 09:04:061772size_t CookieMonster::PurgeLeastRecentMatches(CookieItVector* cookies,
1773 CookiePriority priority,
1774 size_t to_protect,
jwwc00ac712016-05-05 22:21:441775 size_t purge_goal,
1776 bool protect_secure_cookies) {
mkwste079ac412016-03-11 09:04:061777 DCHECK(thread_checker_.CalledOnValidThread());
1778
mmenke645ca6772016-06-17 18:46:431779 // 1. Count number of the cookies at |priority|
1780 size_t cookies_count_possibly_to_be_deleted = CountCookiesForPossibleDeletion(
1781 priority, cookies, false /* count all cookies */);
1782
1783 // 2. If |cookies_count_possibly_to_be_deleted| at |priority| is less than or
1784 // equal |to_protect|, skip round in order to preserve the quota. This
1785 // involves secure and non-secure cookies at |priority|.
1786 if (cookies_count_possibly_to_be_deleted <= to_protect)
1787 return 0u;
1788
1789 // 3. Calculate number of secure cookies at |priority|
1790 // and number of cookies at |priority| that can possibly be deleted.
1791 // It is guaranteed we do not delete more than |purge_goal| even if
1792 // |cookies_count_possibly_to_be_deleted| is higher.
1793 size_t secure_cookies = 0u;
jwwc00ac712016-05-05 22:21:441794 if (protect_secure_cookies) {
mmenke645ca6772016-06-17 18:46:431795 secure_cookies = CountCookiesForPossibleDeletion(
1796 priority, cookies, protect_secure_cookies /* count secure cookies */);
1797 cookies_count_possibly_to_be_deleted -=
1798 std::max(secure_cookies, to_protect - secure_cookies);
1799 } else {
1800 cookies_count_possibly_to_be_deleted -= to_protect;
jwwc00ac712016-05-05 22:21:441801 }
1802
mmenke645ca6772016-06-17 18:46:431803 size_t removed = 0u;
1804 size_t current = 0u;
1805 while ((removed < purge_goal && current < cookies->size()) &&
1806 cookies_count_possibly_to_be_deleted > 0) {
avie7cd11a2016-10-11 02:00:351807 const CanonicalCookie* current_cookie = cookies->at(current)->second.get();
mmenke645ca6772016-06-17 18:46:431808 // Only delete the current cookie if the priority is equal to
1809 // the current level.
jwwc00ac712016-05-05 22:21:441810 if (IsCookieEligibleForEviction(priority, protect_secure_cookies,
1811 current_cookie)) {
mkwstaa07ee82016-03-11 15:32:141812 InternalDeleteCookie(cookies->at(current), true,
1813 DELETE_COOKIE_EVICTED_DOMAIN);
mkwste079ac412016-03-11 09:04:061814 cookies->erase(cookies->begin() + current);
1815 removed++;
mmenke645ca6772016-06-17 18:46:431816 cookies_count_possibly_to_be_deleted--;
mkwste079ac412016-03-11 09:04:061817 } else {
1818 current++;
1819 }
1820 }
1821 return removed;
1822}
1823
jww82d99c12015-11-25 18:39:531824size_t CookieMonster::GarbageCollectExpired(const Time& current,
1825 const CookieMapItPair& itpair,
1826 CookieItVector* cookie_its) {
mmenkebe0910d2016-03-01 19:09:091827 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041828
[email protected]c890ed192008-10-30 23:45:531829 int num_deleted = 0;
1830 for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) {
1831 CookieMap::iterator curit = it;
1832 ++it;
1833
1834 if (curit->second->IsExpired(current)) {
[email protected]2f3f3592010-07-07 20:11:511835 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
[email protected]c890ed192008-10-30 23:45:531836 ++num_deleted;
1837 } else if (cookie_its) {
1838 cookie_its->push_back(curit);
1839 }
initial.commit586acc5fe2008-07-26 22:42:521840 }
1841
1842 return num_deleted;
1843}
1844
jww82d99c12015-11-25 18:39:531845size_t CookieMonster::GarbageCollectDeleteRange(
1846 const Time& current,
1847 DeletionCause cause,
1848 CookieItVector::iterator it_begin,
1849 CookieItVector::iterator it_end) {
mmenkebe0910d2016-03-01 19:09:091850 DCHECK(thread_checker_.CalledOnValidThread());
1851
[email protected]8ad5d462013-05-02 08:45:261852 for (CookieItVector::iterator it = it_begin; it != it_end; it++) {
[email protected]8ad5d462013-05-02 08:45:261853 InternalDeleteCookie((*it), true, cause);
[email protected]c10da4b02010-03-25 14:38:321854 }
[email protected]8ad5d462013-05-02 08:45:261855 return it_end - it_begin;
[email protected]c10da4b02010-03-25 14:38:321856}
1857
mmenke74bcbd52016-01-21 17:17:561858size_t CookieMonster::GarbageCollectLeastRecentlyAccessed(
1859 const base::Time& current,
1860 const base::Time& safe_date,
1861 size_t purge_goal,
mmenkef4721d992017-06-07 17:13:591862 CookieItVector cookie_its,
1863 base::Time* earliest_time) {
1864 DCHECK_LE(purge_goal, cookie_its.size());
mmenkebe0910d2016-03-01 19:09:091865 DCHECK(thread_checker_.CalledOnValidThread());
1866
mmenkef4721d992017-06-07 17:13:591867 // Sorts up to *and including* |cookie_its[purge_goal]| (if it exists), so
1868 // |earliest_time| will be properly assigned even if
mmenke74bcbd52016-01-21 17:17:561869 // |global_purge_it| == |cookie_its.begin() + purge_goal|.
mmenkef4721d992017-06-07 17:13:591870 SortLeastRecentlyAccessed(
1871 cookie_its.begin(), cookie_its.end(),
1872 cookie_its.size() < purge_goal ? purge_goal + 1 : purge_goal);
mmenke74bcbd52016-01-21 17:17:561873 // Find boundary to cookies older than safe_date.
1874 CookieItVector::iterator global_purge_it = LowerBoundAccessDate(
1875 cookie_its.begin(), cookie_its.begin() + purge_goal, safe_date);
jwwa26e439d2017-01-27 18:17:271876 // Only delete the old cookies and delete non-secure ones first.
mmenke74bcbd52016-01-21 17:17:561877 size_t num_deleted =
1878 GarbageCollectDeleteRange(current, DELETE_COOKIE_EVICTED_GLOBAL,
1879 cookie_its.begin(), global_purge_it);
mmenkef4721d992017-06-07 17:13:591880 if (global_purge_it != cookie_its.end())
1881 *earliest_time = (*global_purge_it)->second->LastAccessDate();
mmenke74bcbd52016-01-21 17:17:561882 return num_deleted;
1883}
1884
[email protected]ed32c212013-05-14 20:49:291885// A wrapper around registry_controlled_domains::GetDomainAndRegistry
[email protected]f48b9432011-01-11 07:25:401886// to make clear we're creating a key for our local map. Here and
1887// in FindCookiesForHostAndDomain() are the only two places where
1888// we need to conditionalize based on key type.
1889//
1890// Note that this key algorithm explicitly ignores the scheme. This is
1891// because when we're entering cookies into the map from the backing store,
1892// we in general won't have the scheme at that point.
1893// In practical terms, this means that file cookies will be stored
1894// in the map either by an empty string or by UNC name (and will be
1895// limited by kMaxCookiesPerHost), and extension cookies will be stored
1896// based on the single extension id, as the extension id won't have the
1897// form of a DNS host and hence GetKey() will return it unchanged.
1898//
1899// Arguably the right thing to do here is to make the key
1900// algorithm dependent on the scheme, and make sure that the scheme is
1901// available everywhere the key must be obtained (specfically at backing
1902// store load time). This would require either changing the backing store
1903// database schema to include the scheme (far more trouble than it's worth), or
1904// separating out file cookies into their own CookieMonster instance and
1905// thus restricting each scheme to a single cookie monster (which might
1906// be worth it, but is still too much trouble to solve what is currently a
1907// non-problem).
1908std::string CookieMonster::GetKey(const std::string& domain) const {
mmenkebe0910d2016-03-01 19:09:091909 DCHECK(thread_checker_.CalledOnValidThread());
1910
[email protected]f48b9432011-01-11 07:25:401911 std::string effective_domain(
[email protected]ed32c212013-05-14 20:49:291912 registry_controlled_domains::GetDomainAndRegistry(
[email protected]aabe1792014-01-30 21:37:461913 domain, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES));
[email protected]f48b9432011-01-11 07:25:401914 if (effective_domain.empty())
1915 effective_domain = domain;
1916
1917 if (!effective_domain.empty() && effective_domain[0] == '.')
1918 return effective_domain.substr(1);
1919 return effective_domain;
1920}
1921
1922bool CookieMonster::HasCookieableScheme(const GURL& url) {
mmenkebe0910d2016-03-01 19:09:091923 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401924
1925 // Make sure the request is on a cookie-able url scheme.
1926 for (size_t i = 0; i < cookieable_schemes_.size(); ++i) {
1927 // We matched a scheme.
1928 if (url.SchemeIs(cookieable_schemes_[i].c_str())) {
1929 // We've matched a supported scheme.
initial.commit586acc5fe2008-07-26 22:42:521930 return true;
1931 }
1932 }
[email protected]f48b9432011-01-11 07:25:401933
1934 // The scheme didn't match any in our whitelist.
mkwstbe84af312015-02-20 08:52:451935 VLOG(kVlogPerCookieMonster)
1936 << "WARNING: Unsupported cookie scheme: " << url.scheme();
initial.commit586acc5fe2008-07-26 22:42:521937 return false;
1938}
1939
[email protected]c4058fb2010-06-22 17:25:261940// Test to see if stats should be recorded, and record them if so.
1941// The goal here is to get sampling for the average browser-hour of
1942// activity. We won't take samples when the web isn't being surfed,
1943// and when the web is being surfed, we'll take samples about every
1944// kRecordStatisticsIntervalSeconds.
1945// last_statistic_record_time_ is initialized to Now() rather than null
1946// in the constructor so that we won't take statistics right after
1947// startup, to avoid bias from browsers that are started but not used.
1948void CookieMonster::RecordPeriodicStats(const base::Time& current_time) {
mmenkebe0910d2016-03-01 19:09:091949 DCHECK(thread_checker_.CalledOnValidThread());
1950
[email protected]c4058fb2010-06-22 17:25:261951 const base::TimeDelta kRecordStatisticsIntervalTime(
1952 base::TimeDelta::FromSeconds(kRecordStatisticsIntervalSeconds));
1953
[email protected]7a964a72010-09-07 19:33:261954 // If we've taken statistics recently, return.
1955 if (current_time - last_statistic_record_time_ <=
[email protected]c4058fb2010-06-22 17:25:261956 kRecordStatisticsIntervalTime) {
[email protected]7a964a72010-09-07 19:33:261957 return;
[email protected]c4058fb2010-06-22 17:25:261958 }
[email protected]7a964a72010-09-07 19:33:261959
1960 // See InitializeHistograms() for details.
1961 histogram_count_->Add(cookies_.size());
1962
1963 // More detailed statistics on cookie counts at different granularities.
[email protected]7a964a72010-09-07 19:33:261964 last_statistic_record_time_ = current_time;
[email protected]c4058fb2010-06-22 17:25:261965}
1966
[email protected]f48b9432011-01-11 07:25:401967// Initialize all histogram counter variables used in this class.
1968//
1969// Normal histogram usage involves using the macros defined in
1970// histogram.h, which automatically takes care of declaring these
1971// variables (as statics), initializing them, and accumulating into
1972// them, all from a single entry point. Unfortunately, that solution
1973// doesn't work for the CookieMonster, as it's vulnerable to races between
1974// separate threads executing the same functions and hence initializing the
1975// same static variables. There isn't a race danger in the histogram
1976// accumulation calls; they are written to be resilient to simultaneous
1977// calls from multiple threads.
1978//
1979// The solution taken here is to have per-CookieMonster instance
1980// variables that are constructed during CookieMonster construction.
1981// Note that these variables refer to the same underlying histogram,
1982// so we still race (but safely) with other CookieMonster instances
1983// for accumulation.
1984//
1985// To do this we've expanded out the individual histogram macros calls,
1986// with declarations of the variables in the class decl, initialization here
1987// (done from the class constructor) and direct calls to the accumulation
1988// methods where needed. The specific histogram macro calls on which the
1989// initialization is based are included in comments below.
1990void CookieMonster::InitializeHistograms() {
mmenkebe0910d2016-03-01 19:09:091991 DCHECK(thread_checker_.CalledOnValidThread());
1992
[email protected]f48b9432011-01-11 07:25:401993 // From UMA_HISTOGRAM_CUSTOM_COUNTS
1994 histogram_expiration_duration_minutes_ = base::Histogram::FactoryGet(
mkwstbe84af312015-02-20 08:52:451995 "Cookie.ExpirationDurationMinutes", 1, kMinutesInTenYears, 50,
[email protected]f48b9432011-01-11 07:25:401996 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401997 histogram_count_ = base::Histogram::FactoryGet(
mkwstbe84af312015-02-20 08:52:451998 "Cookie.Count", 1, 4000, 50, base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:401999
2000 // From UMA_HISTOGRAM_ENUMERATION
mkwstc1aa4cc2015-04-03 19:57:452001 histogram_cookie_type_ = base::LinearHistogram::FactoryGet(
mkwst87378d92015-04-10 21:22:112002 "Cookie.Type", 1, (1 << COOKIE_TYPE_LAST_ENTRY) - 1,
2003 1 << COOKIE_TYPE_LAST_ENTRY, base::Histogram::kUmaTargetedHistogramFlag);
estark7feb65c2b2015-08-21 23:38:202004 histogram_cookie_source_scheme_ = base::LinearHistogram::FactoryGet(
2005 "Cookie.CookieSourceScheme", 1, COOKIE_SOURCE_LAST_ENTRY - 1,
2006 COOKIE_SOURCE_LAST_ENTRY, base::Histogram::kUmaTargetedHistogramFlag);
jww31e32632015-12-16 23:38:342007 histogram_cookie_delete_equivalent_ = base::LinearHistogram::FactoryGet(
2008 "Cookie.CookieDeleteEquivalent", 1,
2009 COOKIE_DELETE_EQUIVALENT_LAST_ENTRY - 1,
2010 COOKIE_DELETE_EQUIVALENT_LAST_ENTRY,
2011 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:402012
2013 // From UMA_HISTOGRAM_{CUSTOM_,}TIMES
[email protected]c7593fb22011-11-14 23:54:272014 histogram_time_blocked_on_load_ = base::Histogram::FactoryTimeGet(
mkwstbe84af312015-02-20 08:52:452015 "Cookie.TimeBlockedOnLoad", base::TimeDelta::FromMilliseconds(1),
2016 base::TimeDelta::FromMinutes(1), 50,
2017 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:402018}
2019
[email protected]f48b9432011-01-11 07:25:402020// The system resolution is not high enough, so we can have multiple
2021// set cookies that result in the same system time. When this happens, we
2022// increment by one Time unit. Let's hope computers don't get too fast.
2023Time CookieMonster::CurrentTime() {
mkwstbe84af312015-02-20 08:52:452024 return std::max(Time::Now(), Time::FromInternalValue(
2025 last_time_seen_.ToInternalValue() + 1));
[email protected]f48b9432011-01-11 07:25:402026}
2027
rdsmithe5c701d2017-07-12 21:50:002028void CookieMonster::DoCookieCallback(base::OnceClosure callback) {
mmenkebe0910d2016-03-01 19:09:092029 DCHECK(thread_checker_.CalledOnValidThread());
2030
2031 MarkCookieStoreAsInitialized();
2032 FetchAllCookiesIfNecessary();
mmenkef49fca0e2016-03-08 12:46:242033 seen_global_task_ = true;
mmenkebe0910d2016-03-01 19:09:092034
2035 if (!finished_fetching_all_cookies_ && store_.get()) {
rdsmithe5c701d2017-07-12 21:50:002036 tasks_pending_.push_back(std::move(callback));
mmenkebe0910d2016-03-01 19:09:092037 return;
mmenke74bcbd52016-01-21 17:17:562038 }
2039
rdsmithe5c701d2017-07-12 21:50:002040 std::move(callback).Run();
mmenke74bcbd52016-01-21 17:17:562041}
2042
rdsmithe5c701d2017-07-12 21:50:002043void CookieMonster::DoCookieCallbackForURL(base::OnceClosure callback,
2044 const GURL& url) {
mmenkebe0910d2016-03-01 19:09:092045 MarkCookieStoreAsInitialized();
2046 if (ShouldFetchAllCookiesWhenFetchingAnyCookie())
2047 FetchAllCookiesIfNecessary();
2048
2049 // If cookies for the requested domain key (eTLD+1) have been loaded from DB
2050 // then run the task, otherwise load from DB.
2051 if (!finished_fetching_all_cookies_ && store_.get()) {
mmenkef49fca0e2016-03-08 12:46:242052 // If a global task has been previously seen, queue the task as a global
2053 // task. Note that the CookieMonster may be in the middle of executing
2054 // the global queue, |tasks_pending_| may be empty, which is why another
2055 // bool is needed.
2056 if (seen_global_task_) {
rdsmithe5c701d2017-07-12 21:50:002057 tasks_pending_.push_back(std::move(callback));
mmenkef49fca0e2016-03-08 12:46:242058 return;
2059 }
2060
mmenkebe0910d2016-03-01 19:09:092061 // Checks if the domain key has been loaded.
2062 std::string key(cookie_util::GetEffectiveDomain(url.scheme(), url.host()));
2063 if (keys_loaded_.find(key) == keys_loaded_.end()) {
Brett Wilsonc6a0c822017-09-12 00:04:292064 std::map<std::string, base::circular_deque<base::OnceClosure>>::iterator
2065 it = tasks_pending_for_key_.find(key);
mmenkebe0910d2016-03-01 19:09:092066 if (it == tasks_pending_for_key_.end()) {
2067 store_->LoadCookiesForKey(
2068 key, base::Bind(&CookieMonster::OnKeyLoaded,
2069 weak_ptr_factory_.GetWeakPtr(), key));
2070 it = tasks_pending_for_key_
Brett Wilsonc6a0c822017-09-12 00:04:292071 .insert(std::make_pair(
2072 key, base::circular_deque<base::OnceClosure>()))
mmenkebe0910d2016-03-01 19:09:092073 .first;
mmenke74bcbd52016-01-21 17:17:562074 }
rdsmithe5c701d2017-07-12 21:50:002075 it->second.push_back(std::move(callback));
mmenkebe0910d2016-03-01 19:09:092076 return;
mmenke74bcbd52016-01-21 17:17:562077 }
2078 }
mmenkebe0910d2016-03-01 19:09:092079
rdsmithe5c701d2017-07-12 21:50:002080 std::move(callback).Run();
mmenke74bcbd52016-01-21 17:17:562081}
2082
mmenkebe0910d2016-03-01 19:09:092083void CookieMonster::RunCookieChangedCallbacks(const CanonicalCookie& cookie,
Randy Smithd32dc8c2017-08-30 18:03:402084 bool notify_global_hooks,
nharper352933e2016-09-30 18:24:572085 ChangeCause cause) {
mmenkebe0910d2016-03-01 19:09:092086 DCHECK(thread_checker_.CalledOnValidThread());
2087
ellyjones399e35a22014-10-27 11:09:562088 CookieOptions opts;
2089 opts.set_include_httponly();
mkwstf71d0bd2016-03-21 14:15:242090 opts.set_same_site_cookie_mode(
2091 CookieOptions::SameSiteCookieMode::INCLUDE_STRICT_AND_LAX);
mmenkebe0910d2016-03-01 19:09:092092 // Note that the callbacks in hook_map_ are wrapped with RunAsync(), so they
ellyjones399e35a22014-10-27 11:09:562093 // are guaranteed to not take long - they just post a RunAsync task back to
mmenkebe0910d2016-03-01 19:09:092094 // the appropriate thread's message loop and return.
2095 // TODO(mmenke): Consider running these synchronously?
ellyjones399e35a22014-10-27 11:09:562096 for (CookieChangedHookMap::iterator it = hook_map_.begin();
2097 it != hook_map_.end(); ++it) {
2098 std::pair<GURL, std::string> key = it->first;
2099 if (cookie.IncludeForRequestURL(key.first, opts) &&
2100 cookie.Name() == key.second) {
nharper352933e2016-09-30 18:24:572101 it->second->Notify(cookie, cause);
ellyjones399e35a22014-10-27 11:09:562102 }
2103 }
Randy Smithd32dc8c2017-08-30 18:03:402104
2105 if (notify_global_hooks)
2106 global_hook_map_->Notify(cookie, cause);
ellyjones399e35a22014-10-27 11:09:562107}
2108
[email protected]63725312012-07-19 08:24:162109} // namespace net