blob: 2272d7b08ab49ca58e9ce4024cd2ebb369efdc07 [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
47#include <algorithm>
[email protected]8ad5d462013-05-02 08:45:2648#include <functional>
danakja9850e12016-04-18 22:28:0849#include <memory>
[email protected]09666482011-07-12 12:50:4050#include <set>
initial.commit586acc5fe2008-07-26 22:42:5251
[email protected]218aa6a12011-09-13 17:38:3852#include "base/bind.h"
[email protected]8562034e2011-10-17 17:35:0453#include "base/callback.h"
skyostil4891b25b2015-06-11 11:43:4554#include "base/location.h"
initial.commit586acc5fe2008-07-26 22:42:5255#include "base/logging.h"
Avi Drissman13fc8932015-12-20 04:40:4656#include "base/macros.h"
danakja9850e12016-04-18 22:28:0857#include "base/memory/ptr_util.h"
erikchen1dd72a72015-05-06 20:45:0558#include "base/metrics/field_trial.h"
[email protected]835d7c82010-10-14 04:38:3859#include "base/metrics/histogram.h"
pkastingb60049a2015-02-07 03:25:2560#include "base/profiler/scoped_tracker.h"
anujk.sharmaafc45172015-05-15 00:50:3461#include "base/single_thread_task_runner.h"
[email protected]4b355212013-06-11 10:35:1962#include "base/strings/string_util.h"
63#include "base/strings/stringprintf.h"
gabf767595f2016-05-11 18:50:3564#include "base/threading/thread_task_runner_handle.h"
[email protected]be28b5f42012-07-20 11:31:2565#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
[email protected]4b355212013-06-11 10:35:1966#include "net/cookies/canonical_cookie.h"
[email protected]63ee33bd2012-03-15 09:29:5867#include "net/cookies/cookie_util.h"
[email protected]ebfe3172012-07-12 12:21:4168#include "net/cookies/parsed_cookie.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
84// request is for a specific URL, DoCookieTaskForURL is called, which triggers a
85// priority load if the key is not loaded yet by calling PersistentCookieStore
[email protected]0184df32013-05-14 00:53:5586// :: LoadCookiesForKey. The request is queued in
87// 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
104} // namespace
105
[email protected]8ac1a752008-07-31 19:40:37106namespace net {
107
[email protected]7a964a72010-09-07 19:33:26108// See comments at declaration of these variables in cookie_monster.h
109// for details.
mkwstbe84af312015-02-20 08:52:45110const size_t CookieMonster::kDomainMaxCookies = 180;
111const size_t CookieMonster::kDomainPurgeCookies = 30;
112const size_t CookieMonster::kMaxCookies = 3300;
113const size_t CookieMonster::kPurgeCookies = 300;
[email protected]8ad5d462013-05-02 08:45:26114
mkwst87734352016-03-03 17:36:23115const size_t CookieMonster::kDomainCookiesQuotaLow = 30;
116const size_t CookieMonster::kDomainCookiesQuotaMedium = 50;
117const size_t CookieMonster::kDomainCookiesQuotaHigh =
118 kDomainMaxCookies - kDomainPurgeCookies - kDomainCookiesQuotaLow -
119 kDomainCookiesQuotaMedium;
[email protected]8ad5d462013-05-02 08:45:26120
mkwstbe84af312015-02-20 08:52:45121const int CookieMonster::kSafeFromGlobalPurgeDays = 30;
[email protected]297a4ed02010-02-12 08:12:52122
[email protected]7a964a72010-09-07 19:33:26123namespace {
[email protected]e32306c52008-11-06 16:59:05124
[email protected]6210ce52013-09-20 03:33:14125bool ContainsControlCharacter(const std::string& s) {
126 for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
127 if ((*i >= 0) && (*i <= 31))
128 return true;
129 }
130
131 return false;
132}
133
[email protected]5b9bc352012-07-18 13:13:34134typedef std::vector<CanonicalCookie*> CanonicalCookieVector;
[email protected]34a160d2011-05-12 22:12:49135
[email protected]77e0a462008-11-01 00:43:35136// Default minimum delay after updating a cookie's LastAccessDate before we
137// will update it again.
[email protected]297a4ed02010-02-12 08:12:52138const int kDefaultAccessUpdateThresholdSeconds = 60;
139
140// Comparator to sort cookies from highest creation date to lowest
141// creation date.
142struct OrderByCreationTimeDesc {
143 bool operator()(const CookieMonster::CookieMap::iterator& a,
144 const CookieMonster::CookieMap::iterator& b) const {
145 return a->second->CreationDate() > b->second->CreationDate();
146 }
147};
148
[email protected]4d3ce782010-10-29 18:31:28149// Constants for use in VLOG
150const int kVlogPerCookieMonster = 1;
[email protected]4d3ce782010-10-29 18:31:28151const int kVlogGarbageCollection = 5;
152const int kVlogSetCookies = 7;
153const int kVlogGetCookies = 9;
154
[email protected]f48b9432011-01-11 07:25:40155// Mozilla sorts on the path length (longest first), and then it
156// sorts by creation time (oldest first).
157// The RFC says the sort order for the domain attribute is undefined.
[email protected]5b9bc352012-07-18 13:13:34158bool CookieSorter(CanonicalCookie* cc1, CanonicalCookie* cc2) {
[email protected]f48b9432011-01-11 07:25:40159 if (cc1->Path().length() == cc2->Path().length())
160 return cc1->CreationDate() < cc2->CreationDate();
161 return cc1->Path().length() > cc2->Path().length();
initial.commit586acc5fe2008-07-26 22:42:52162}
163
[email protected]8ad5d462013-05-02 08:45:26164bool LRACookieSorter(const CookieMonster::CookieMap::iterator& it1,
[email protected]f48b9432011-01-11 07:25:40165 const CookieMonster::CookieMap::iterator& it2) {
[email protected]f48b9432011-01-11 07:25:40166 if (it1->second->LastAccessDate() != it2->second->LastAccessDate())
167 return it1->second->LastAccessDate() < it2->second->LastAccessDate();
initial.commit586acc5fe2008-07-26 22:42:52168
mkwste079ac412016-03-11 09:04:06169 // Ensure stability for == last access times by falling back to creation.
[email protected]f48b9432011-01-11 07:25:40170 return it1->second->CreationDate() < it2->second->CreationDate();
[email protected]297a4ed02010-02-12 08:12:52171}
172
drogerd5d1278c2015-03-17 19:21:51173// Compare cookies using name, domain and path, so that "equivalent" cookies
174// (per RFC 2965) are equal to each other.
ttuttle859dc7a2015-04-23 19:42:29175bool PartialDiffCookieSorter(const CanonicalCookie& a,
176 const CanonicalCookie& b) {
drogerd5d1278c2015-03-17 19:21:51177 return a.PartialCompare(b);
178}
179
180// This is a stricter ordering than PartialDiffCookieOrdering, where all fields
181// are used.
ttuttle859dc7a2015-04-23 19:42:29182bool FullDiffCookieSorter(const CanonicalCookie& a, const CanonicalCookie& b) {
drogerd5d1278c2015-03-17 19:21:51183 return a.FullCompare(b);
184}
185
[email protected]297a4ed02010-02-12 08:12:52186// Our strategy to find duplicates is:
187// (1) Build a map from (cookiename, cookiepath) to
188// {list of cookies with this signature, sorted by creation time}.
189// (2) For each list with more than 1 entry, keep the cookie having the
190// most recent creation time, and delete the others.
[email protected]f48b9432011-01-11 07:25:40191//
[email protected]1655ba342010-07-14 18:17:42192// Two cookies are considered equivalent if they have the same domain,
193// name, and path.
194struct CookieSignature {
195 public:
[email protected]dedec0b2013-02-28 04:50:10196 CookieSignature(const std::string& name,
197 const std::string& domain,
[email protected]1655ba342010-07-14 18:17:42198 const std::string& path)
mkwstbe84af312015-02-20 08:52:45199 : name(name), domain(domain), path(path) {}
[email protected]1655ba342010-07-14 18:17:42200
201 // To be a key for a map this class needs to be assignable, copyable,
202 // and have an operator<. The default assignment operator
203 // and copy constructor are exactly what we want.
204
205 bool operator<(const CookieSignature& cs) const {
206 // Name compare dominates, then domain, then path.
207 int diff = name.compare(cs.name);
208 if (diff != 0)
209 return diff < 0;
210
211 diff = domain.compare(cs.domain);
212 if (diff != 0)
213 return diff < 0;
214
215 return path.compare(cs.path) < 0;
216 }
217
218 std::string name;
219 std::string domain;
220 std::string path;
221};
[email protected]f48b9432011-01-11 07:25:40222
[email protected]8ad5d462013-05-02 08:45:26223// For a CookieItVector iterator range [|it_begin|, |it_end|),
224// sorts the first |num_sort| + 1 elements by LastAccessDate().
225// The + 1 element exists so for any interval of length <= |num_sort| starting
226// from |cookies_its_begin|, a LastAccessDate() bound can be found.
mkwstbe84af312015-02-20 08:52:45227void SortLeastRecentlyAccessed(CookieMonster::CookieItVector::iterator it_begin,
228 CookieMonster::CookieItVector::iterator it_end,
229 size_t num_sort) {
[email protected]8ad5d462013-05-02 08:45:26230 DCHECK_LT(static_cast<int>(num_sort), it_end - it_begin);
231 std::partial_sort(it_begin, it_begin + num_sort + 1, it_end, LRACookieSorter);
232}
[email protected]f48b9432011-01-11 07:25:40233
jww82d99c12015-11-25 18:39:53234// Given a single cookie vector |cookie_its|, pushs all of the secure cookies in
235// |cookie_its| into |secure_cookie_its| and all of the non-secure cookies into
236// |non_secure_cookie_its|. Both |secure_cookie_its| and |non_secure_cookie_its|
237// must be non-NULL.
238void SplitCookieVectorIntoSecureAndNonSecure(
239 const CookieMonster::CookieItVector& cookie_its,
240 CookieMonster::CookieItVector* secure_cookie_its,
241 CookieMonster::CookieItVector* non_secure_cookie_its) {
242 DCHECK(secure_cookie_its && non_secure_cookie_its);
243 for (const auto& curit : cookie_its) {
244 if (curit->second->IsSecure())
245 secure_cookie_its->push_back(curit);
246 else
247 non_secure_cookie_its->push_back(curit);
248 }
249}
250
mkwstbe84af312015-02-20 08:52:45251bool LowerBoundAccessDateComparator(const CookieMonster::CookieMap::iterator it,
252 const Time& access_date) {
[email protected]8ad5d462013-05-02 08:45:26253 return it->second->LastAccessDate() < access_date;
254}
255
256// For a CookieItVector iterator range [|it_begin|, |it_end|)
257// from a CookieItVector sorted by LastAccessDate(), returns the
258// first iterator with access date >= |access_date|, or cookie_its_end if this
259// holds for all.
260CookieMonster::CookieItVector::iterator LowerBoundAccessDate(
261 const CookieMonster::CookieItVector::iterator its_begin,
262 const CookieMonster::CookieItVector::iterator its_end,
263 const Time& access_date) {
264 return std::lower_bound(its_begin, its_end, access_date,
265 LowerBoundAccessDateComparator);
[email protected]7a964a72010-09-07 19:33:26266}
267
nharper352933e2016-09-30 18:24:57268// Mapping between DeletionCause and CookieStore::ChangeCause; the
[email protected]7c4b66b2014-01-04 12:28:13269// mapping also provides a boolean that specifies whether or not an
270// OnCookieChanged notification ought to be generated.
[email protected]8bb846f2011-03-23 12:08:18271typedef struct ChangeCausePair_struct {
nharper352933e2016-09-30 18:24:57272 CookieStore::ChangeCause cause;
[email protected]8bb846f2011-03-23 12:08:18273 bool notify;
274} ChangeCausePair;
nharper352933e2016-09-30 18:24:57275const ChangeCausePair kChangeCauseMapping[] = {
mkwstbe84af312015-02-20 08:52:45276 // DELETE_COOKIE_EXPLICIT
nharper68903362017-01-20 04:07:14277 {CookieStore::ChangeCause::EXPLICIT, true},
mkwstbe84af312015-02-20 08:52:45278 // DELETE_COOKIE_OVERWRITE
nharper352933e2016-09-30 18:24:57279 {CookieStore::ChangeCause::OVERWRITE, true},
mkwstbe84af312015-02-20 08:52:45280 // DELETE_COOKIE_EXPIRED
nharper352933e2016-09-30 18:24:57281 {CookieStore::ChangeCause::EXPIRED, true},
mkwstbe84af312015-02-20 08:52:45282 // DELETE_COOKIE_EVICTED
nharper352933e2016-09-30 18:24:57283 {CookieStore::ChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45284 // DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE
nharper68903362017-01-20 04:07:14285 {CookieStore::ChangeCause::EXPLICIT, false},
mkwstbe84af312015-02-20 08:52:45286 // DELETE_COOKIE_DONT_RECORD
nharper68903362017-01-20 04:07:14287 {CookieStore::ChangeCause::EXPLICIT, false},
mkwstbe84af312015-02-20 08:52:45288 // DELETE_COOKIE_EVICTED_DOMAIN
nharper352933e2016-09-30 18:24:57289 {CookieStore::ChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45290 // DELETE_COOKIE_EVICTED_GLOBAL
nharper352933e2016-09-30 18:24:57291 {CookieStore::ChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45292 // DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE
nharper352933e2016-09-30 18:24:57293 {CookieStore::ChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45294 // DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE
nharper352933e2016-09-30 18:24:57295 {CookieStore::ChangeCause::EVICTED, true},
mkwstbe84af312015-02-20 08:52:45296 // DELETE_COOKIE_EXPIRED_OVERWRITE
nharper352933e2016-09-30 18:24:57297 {CookieStore::ChangeCause::EXPIRED_OVERWRITE, true},
mkwstbe84af312015-02-20 08:52:45298 // DELETE_COOKIE_CONTROL_CHAR
nharper352933e2016-09-30 18:24:57299 {CookieStore::ChangeCause::EVICTED, true},
jww82d99c12015-11-25 18:39:53300 // DELETE_COOKIE_NON_SECURE
nharper352933e2016-09-30 18:24:57301 {CookieStore::ChangeCause::EVICTED, true},
nharper68903362017-01-20 04:07:14302 // DELETE_COOKIE_CREATED_BETWEEN
303 {CookieStore::ChangeCause::EXPLICIT_DELETE_BETWEEN, true},
304 // DELETE_COOKIE_CREATED_BETWEEN_WITH_PREDICATE
305 {CookieStore::ChangeCause::EXPLICIT_DELETE_PREDICATE, true},
306 // DELETE_COOKIE_SINGLE
307 {CookieStore::ChangeCause::EXPLICIT_DELETE_SINGLE, true},
308 // DELETE_COOKIE_CANONICAL
309 {CookieStore::ChangeCause::EXPLICIT_DELETE_CANONICAL, true},
mkwstbe84af312015-02-20 08:52:45310 // DELETE_COOKIE_LAST_ENTRY
nharper68903362017-01-20 04:07:14311 {CookieStore::ChangeCause::EXPLICIT, false}};
[email protected]8bb846f2011-03-23 12:08:18312
ellyjones399e35a22014-10-27 11:09:56313void RunAsync(scoped_refptr<base::TaskRunner> proxy,
msarda0aad8f02014-10-30 09:22:39314 const CookieStore::CookieChangedCallback& callback,
315 const CanonicalCookie& cookie,
nharper352933e2016-09-30 18:24:57316 CookieStore::ChangeCause cause) {
317 proxy->PostTask(FROM_HERE, base::Bind(callback, cookie, cause));
ellyjones399e35a22014-10-27 11:09:56318}
319
jwwc00ac712016-05-05 22:21:44320bool IsCookieEligibleForEviction(CookiePriority current_priority_level,
321 bool protect_secure_cookies,
322 const CanonicalCookie* cookie) {
mmenke645ca6772016-06-17 18:46:43323 if (cookie->Priority() == current_priority_level && protect_secure_cookies)
324 return !cookie->IsSecure();
jwwc00ac712016-05-05 22:21:44325
mmenke645ca6772016-06-17 18:46:43326 return cookie->Priority() == current_priority_level;
327}
jwwc00ac712016-05-05 22:21:44328
mmenke645ca6772016-06-17 18:46:43329size_t CountCookiesForPossibleDeletion(
330 CookiePriority priority,
331 const CookieMonster::CookieItVector* cookies,
332 bool protect_secure_cookies) {
333 size_t cookies_count = 0U;
334 for (const auto& cookie : *cookies) {
335 if (cookie->second->Priority() == priority) {
336 if (!protect_secure_cookies || cookie->second->IsSecure())
337 cookies_count++;
338 }
339 }
340 return cookies_count;
jwwc00ac712016-05-05 22:21:44341}
342
[email protected]f48b9432011-01-11 07:25:40343} // namespace
344
[email protected]7c4b66b2014-01-04 12:28:13345CookieMonster::CookieMonster(PersistentCookieStore* store,
346 CookieMonsterDelegate* delegate)
shessf0bc1182016-05-19 04:35:58347 : CookieMonster(
348 store,
349 delegate,
350 base::TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds)) {}
[email protected]2d0f89a2010-12-06 12:02:23351
[email protected]f48b9432011-01-11 07:25:40352CookieMonster::CookieMonster(PersistentCookieStore* store,
[email protected]7c4b66b2014-01-04 12:28:13353 CookieMonsterDelegate* delegate,
shessf0bc1182016-05-19 04:35:58354 base::TimeDelta last_access_threshold)
[email protected]f48b9432011-01-11 07:25:40355 : initialized_(false),
erikchen1dd72a72015-05-06 20:45:05356 started_fetching_all_cookies_(false),
357 finished_fetching_all_cookies_(false),
358 fetch_strategy_(kUnknownFetch),
mmenkef49fca0e2016-03-08 12:46:24359 seen_global_task_(false),
[email protected]f48b9432011-01-11 07:25:40360 store_(store),
shessf0bc1182016-05-19 04:35:58361 last_access_threshold_(last_access_threshold),
[email protected]f48b9432011-01-11 07:25:40362 delegate_(delegate),
[email protected]82388662011-03-10 21:04:06363 last_statistic_record_time_(base::Time::Now()),
mmenkebe0910d2016-03-01 19:09:09364 persist_session_cookies_(false),
365 weak_ptr_factory_(this) {
[email protected]f48b9432011-01-11 07:25:40366 InitializeHistograms();
mmenke18dd8ba2016-02-01 18:42:10367 cookieable_schemes_.insert(
368 cookieable_schemes_.begin(), kDefaultCookieableSchemes,
369 kDefaultCookieableSchemes + kDefaultCookieableSchemesCount);
initial.commit586acc5fe2008-07-26 22:42:52370}
371
[email protected]218aa6a12011-09-13 17:38:38372// Task classes for queueing the coming request.
373
374class CookieMonster::CookieMonsterTask
375 : public base::RefCountedThreadSafe<CookieMonsterTask> {
376 public:
377 // Runs the task and invokes the client callback on the thread that
378 // originally constructed the task.
379 virtual void Run() = 0;
380
381 protected:
382 explicit CookieMonsterTask(CookieMonster* cookie_monster);
383 virtual ~CookieMonsterTask();
384
mkwstbe84af312015-02-20 08:52:45385 CookieMonster* cookie_monster() { return cookie_monster_; }
[email protected]218aa6a12011-09-13 17:38:38386
[email protected]a9813302012-04-28 09:29:28387 private:
[email protected]218aa6a12011-09-13 17:38:38388 friend class base::RefCountedThreadSafe<CookieMonsterTask>;
389
[email protected]218aa6a12011-09-13 17:38:38390 CookieMonster* cookie_monster_;
[email protected]218aa6a12011-09-13 17:38:38391
392 DISALLOW_COPY_AND_ASSIGN(CookieMonsterTask);
393};
394
395CookieMonster::CookieMonsterTask::CookieMonsterTask(
396 CookieMonster* cookie_monster)
mmenkebe0910d2016-03-01 19:09:09397 : cookie_monster_(cookie_monster) {}
[email protected]218aa6a12011-09-13 17:38:38398
mkwstbe84af312015-02-20 08:52:45399CookieMonster::CookieMonsterTask::~CookieMonsterTask() {
400}
[email protected]218aa6a12011-09-13 17:38:38401
[email protected]218aa6a12011-09-13 17:38:38402// Task class for SetCookieWithDetails call.
[email protected]5fa4f9a2013-10-03 10:13:16403class CookieMonster::SetCookieWithDetailsTask : public CookieMonsterTask {
[email protected]218aa6a12011-09-13 17:38:38404 public:
[email protected]dedec0b2013-02-28 04:50:10405 SetCookieWithDetailsTask(CookieMonster* cookie_monster,
406 const GURL& url,
407 const std::string& name,
408 const std::string& value,
409 const std::string& domain,
410 const std::string& path,
mmenkefdd4fc72016-02-05 20:53:24411 base::Time creation_time,
412 base::Time expiration_time,
413 base::Time last_access_time,
[email protected]dedec0b2013-02-28 04:50:10414 bool secure,
415 bool http_only,
mkwste1a29582016-03-15 10:07:52416 CookieSameSite same_site,
[email protected]ab2d75c82013-04-19 18:39:04417 CookiePriority priority,
[email protected]5fa4f9a2013-10-03 10:13:16418 const SetCookiesCallback& callback)
[email protected]218aa6a12011-09-13 17:38:38419 : CookieMonsterTask(cookie_monster),
420 url_(url),
421 name_(name),
422 value_(value),
423 domain_(domain),
424 path_(path),
mmenkeea4cd402016-02-02 04:03:10425 creation_time_(creation_time),
[email protected]218aa6a12011-09-13 17:38:38426 expiration_time_(expiration_time),
mmenkefdd4fc72016-02-05 20:53:24427 last_access_time_(last_access_time),
[email protected]218aa6a12011-09-13 17:38:38428 secure_(secure),
429 http_only_(http_only),
mkwst46549412016-02-01 10:05:37430 same_site_(same_site),
[email protected]ab2d75c82013-04-19 18:39:04431 priority_(priority),
mkwstbe84af312015-02-20 08:52:45432 callback_(callback) {}
[email protected]218aa6a12011-09-13 17:38:38433
[email protected]5fa4f9a2013-10-03 10:13:16434 // CookieMonsterTask:
dchengb03027d2014-10-21 12:00:20435 void Run() override;
[email protected]218aa6a12011-09-13 17:38:38436
[email protected]a9813302012-04-28 09:29:28437 protected:
dchengb03027d2014-10-21 12:00:20438 ~SetCookieWithDetailsTask() override {}
[email protected]a9813302012-04-28 09:29:28439
[email protected]218aa6a12011-09-13 17:38:38440 private:
441 GURL url_;
442 std::string name_;
443 std::string value_;
444 std::string domain_;
445 std::string path_;
mmenkeea4cd402016-02-02 04:03:10446 base::Time creation_time_;
[email protected]218aa6a12011-09-13 17:38:38447 base::Time expiration_time_;
mmenkefdd4fc72016-02-05 20:53:24448 base::Time last_access_time_;
[email protected]218aa6a12011-09-13 17:38:38449 bool secure_;
450 bool http_only_;
mkwste1a29582016-03-15 10:07:52451 CookieSameSite same_site_;
[email protected]ab2d75c82013-04-19 18:39:04452 CookiePriority priority_;
[email protected]5fa4f9a2013-10-03 10:13:16453 SetCookiesCallback callback_;
[email protected]218aa6a12011-09-13 17:38:38454
455 DISALLOW_COPY_AND_ASSIGN(SetCookieWithDetailsTask);
456};
457
458void CookieMonster::SetCookieWithDetailsTask::Run() {
mkwstbe84af312015-02-20 08:52:45459 bool success = this->cookie_monster()->SetCookieWithDetails(
mmenkeea4cd402016-02-02 04:03:10460 url_, name_, value_, domain_, path_, creation_time_, expiration_time_,
jwwa26e439d2017-01-27 18:17:27461 last_access_time_, secure_, http_only_, same_site_, priority_);
mmenkebe0910d2016-03-01 19:09:09462 if (!callback_.is_null())
463 callback_.Run(success);
[email protected]218aa6a12011-09-13 17:38:38464}
465
466// Task class for GetAllCookies call.
[email protected]5fa4f9a2013-10-03 10:13:16467class CookieMonster::GetAllCookiesTask : public CookieMonsterTask {
[email protected]218aa6a12011-09-13 17:38:38468 public:
469 GetAllCookiesTask(CookieMonster* cookie_monster,
[email protected]5fa4f9a2013-10-03 10:13:16470 const GetCookieListCallback& callback)
mkwstbe84af312015-02-20 08:52:45471 : CookieMonsterTask(cookie_monster), callback_(callback) {}
[email protected]218aa6a12011-09-13 17:38:38472
[email protected]5fa4f9a2013-10-03 10:13:16473 // CookieMonsterTask
dchengb03027d2014-10-21 12:00:20474 void Run() override;
[email protected]218aa6a12011-09-13 17:38:38475
[email protected]a9813302012-04-28 09:29:28476 protected:
dchengb03027d2014-10-21 12:00:20477 ~GetAllCookiesTask() override {}
[email protected]a9813302012-04-28 09:29:28478
[email protected]218aa6a12011-09-13 17:38:38479 private:
[email protected]5fa4f9a2013-10-03 10:13:16480 GetCookieListCallback callback_;
[email protected]218aa6a12011-09-13 17:38:38481
482 DISALLOW_COPY_AND_ASSIGN(GetAllCookiesTask);
483};
484
485void CookieMonster::GetAllCookiesTask::Run() {
486 if (!callback_.is_null()) {
487 CookieList cookies = this->cookie_monster()->GetAllCookies();
mmenkebe0910d2016-03-01 19:09:09488 callback_.Run(cookies);
mkwstbe84af312015-02-20 08:52:45489 }
[email protected]218aa6a12011-09-13 17:38:38490}
491
mkwstc611e6d2016-02-23 15:45:55492// Task class for GetCookieListWithOptionsAsync call.
493class CookieMonster::GetCookieListWithOptionsTask : public CookieMonsterTask {
[email protected]218aa6a12011-09-13 17:38:38494 public:
mkwstc611e6d2016-02-23 15:45:55495 GetCookieListWithOptionsTask(CookieMonster* cookie_monster,
496 const GURL& url,
497 const CookieOptions& options,
498 const GetCookieListCallback& callback)
[email protected]218aa6a12011-09-13 17:38:38499 : CookieMonsterTask(cookie_monster),
500 url_(url),
501 options_(options),
mkwstbe84af312015-02-20 08:52:45502 callback_(callback) {}
[email protected]218aa6a12011-09-13 17:38:38503
[email protected]5fa4f9a2013-10-03 10:13:16504 // CookieMonsterTask:
dchengb03027d2014-10-21 12:00:20505 void Run() override;
[email protected]218aa6a12011-09-13 17:38:38506
[email protected]a9813302012-04-28 09:29:28507 protected:
mkwstc611e6d2016-02-23 15:45:55508 ~GetCookieListWithOptionsTask() override {}
[email protected]a9813302012-04-28 09:29:28509
[email protected]218aa6a12011-09-13 17:38:38510 private:
511 GURL url_;
512 CookieOptions options_;
[email protected]5fa4f9a2013-10-03 10:13:16513 GetCookieListCallback callback_;
[email protected]218aa6a12011-09-13 17:38:38514
mkwstc611e6d2016-02-23 15:45:55515 DISALLOW_COPY_AND_ASSIGN(GetCookieListWithOptionsTask);
[email protected]218aa6a12011-09-13 17:38:38516};
517
mkwstc611e6d2016-02-23 15:45:55518void CookieMonster::GetCookieListWithOptionsTask::Run() {
[email protected]218aa6a12011-09-13 17:38:38519 if (!callback_.is_null()) {
mkwstbe84af312015-02-20 08:52:45520 CookieList cookies =
mkwstc611e6d2016-02-23 15:45:55521 this->cookie_monster()->GetCookieListWithOptions(url_, options_);
mmenkebe0910d2016-03-01 19:09:09522 callback_.Run(cookies);
[email protected]218aa6a12011-09-13 17:38:38523 }
524}
525
mkwstbe84af312015-02-20 08:52:45526template <typename Result>
527struct CallbackType {
[email protected]5fa4f9a2013-10-03 10:13:16528 typedef base::Callback<void(Result)> Type;
529};
530
mkwstbe84af312015-02-20 08:52:45531template <>
532struct CallbackType<void> {
[email protected]5fa4f9a2013-10-03 10:13:16533 typedef base::Closure Type;
534};
535
536// Base task class for Delete*Task.
537template <typename Result>
538class CookieMonster::DeleteTask : public CookieMonsterTask {
[email protected]218aa6a12011-09-13 17:38:38539 public:
[email protected]5fa4f9a2013-10-03 10:13:16540 DeleteTask(CookieMonster* cookie_monster,
541 const typename CallbackType<Result>::Type& callback)
mkwstbe84af312015-02-20 08:52:45542 : CookieMonsterTask(cookie_monster), callback_(callback) {}
[email protected]218aa6a12011-09-13 17:38:38543
[email protected]5fa4f9a2013-10-03 10:13:16544 // CookieMonsterTask:
nickd3f30d022015-04-23 10:18:37545 void Run() override;
[email protected]218aa6a12011-09-13 17:38:38546
dmichaeld6e570d2014-12-18 22:30:57547 protected:
548 ~DeleteTask() override;
549
[email protected]5fa4f9a2013-10-03 10:13:16550 private:
551 // Runs the delete task and returns a result.
552 virtual Result RunDeleteTask() = 0;
mmenkebe0910d2016-03-01 19:09:09553 // Runs the delete task and then returns a callback to be called after
554 // flushing the persistent store.
555 // TODO(mmenke): This seems like a pretty ugly and needlessly confusing API.
556 // Simplify it?
[email protected]5fa4f9a2013-10-03 10:13:16557 base::Closure RunDeleteTaskAndBindCallback();
[email protected]5fa4f9a2013-10-03 10:13:16558
559 typename CallbackType<Result>::Type callback_;
560
561 DISALLOW_COPY_AND_ASSIGN(DeleteTask);
562};
563
564template <typename Result>
dmichaeld6e570d2014-12-18 22:30:57565CookieMonster::DeleteTask<Result>::~DeleteTask() {
566}
567
568template <typename Result>
569base::Closure
570CookieMonster::DeleteTask<Result>::RunDeleteTaskAndBindCallback() {
[email protected]5fa4f9a2013-10-03 10:13:16571 Result result = RunDeleteTask();
572 if (callback_.is_null())
573 return base::Closure();
574 return base::Bind(callback_, result);
575}
576
577template <>
578base::Closure CookieMonster::DeleteTask<void>::RunDeleteTaskAndBindCallback() {
579 RunDeleteTask();
580 return callback_;
581}
582
583template <typename Result>
584void CookieMonster::DeleteTask<Result>::Run() {
mmenkebe0910d2016-03-01 19:09:09585 base::Closure callback = RunDeleteTaskAndBindCallback();
[email protected]5fa4f9a2013-10-03 10:13:16586 if (!callback.is_null()) {
mmenkebe0910d2016-03-01 19:09:09587 callback = base::Bind(
588 &CookieMonster::RunCallback,
589 this->cookie_monster()->weak_ptr_factory_.GetWeakPtr(), callback);
[email protected]5fa4f9a2013-10-03 10:13:16590 }
mmenkebe0910d2016-03-01 19:09:09591 this->cookie_monster()->FlushStore(callback);
[email protected]5fa4f9a2013-10-03 10:13:16592}
593
[email protected]218aa6a12011-09-13 17:38:38594// Task class for DeleteAllCreatedBetween call.
[email protected]5fa4f9a2013-10-03 10:13:16595class CookieMonster::DeleteAllCreatedBetweenTask : public DeleteTask<int> {
[email protected]218aa6a12011-09-13 17:38:38596 public:
[email protected]dedec0b2013-02-28 04:50:10597 DeleteAllCreatedBetweenTask(CookieMonster* cookie_monster,
598 const Time& delete_begin,
599 const Time& delete_end,
[email protected]5fa4f9a2013-10-03 10:13:16600 const DeleteCallback& callback)
[email protected]151132f2013-11-18 21:37:00601 : DeleteTask<int>(cookie_monster, callback),
[email protected]218aa6a12011-09-13 17:38:38602 delete_begin_(delete_begin),
mkwstbe84af312015-02-20 08:52:45603 delete_end_(delete_end) {}
[email protected]218aa6a12011-09-13 17:38:38604
[email protected]5fa4f9a2013-10-03 10:13:16605 // DeleteTask:
dchengb03027d2014-10-21 12:00:20606 int RunDeleteTask() override;
[email protected]218aa6a12011-09-13 17:38:38607
[email protected]a9813302012-04-28 09:29:28608 protected:
dchengb03027d2014-10-21 12:00:20609 ~DeleteAllCreatedBetweenTask() override {}
[email protected]a9813302012-04-28 09:29:28610
[email protected]218aa6a12011-09-13 17:38:38611 private:
612 Time delete_begin_;
613 Time delete_end_;
[email protected]218aa6a12011-09-13 17:38:38614
615 DISALLOW_COPY_AND_ASSIGN(DeleteAllCreatedBetweenTask);
616};
617
[email protected]5fa4f9a2013-10-03 10:13:16618int CookieMonster::DeleteAllCreatedBetweenTask::RunDeleteTask() {
mkwstbe84af312015-02-20 08:52:45619 return this->cookie_monster()->DeleteAllCreatedBetween(delete_begin_,
620 delete_end_);
[email protected]218aa6a12011-09-13 17:38:38621}
622
dmurphfaea244c2016-04-09 00:42:30623// Task class for DeleteAllCreatedBetweenWithPredicate call.
624class CookieMonster::DeleteAllCreatedBetweenWithPredicateTask
[email protected]5fa4f9a2013-10-03 10:13:16625 : public DeleteTask<int> {
[email protected]d8428d52013-08-07 06:58:25626 public:
dmurphfaea244c2016-04-09 00:42:30627 DeleteAllCreatedBetweenWithPredicateTask(
628 CookieMonster* cookie_monster,
629 Time delete_begin,
630 Time delete_end,
631 base::Callback<bool(const CanonicalCookie&)> predicate,
632 const DeleteCallback& callback)
[email protected]151132f2013-11-18 21:37:00633 : DeleteTask<int>(cookie_monster, callback),
[email protected]d8428d52013-08-07 06:58:25634 delete_begin_(delete_begin),
635 delete_end_(delete_end),
dmurphfaea244c2016-04-09 00:42:30636 predicate_(predicate) {}
[email protected]d8428d52013-08-07 06:58:25637
[email protected]5fa4f9a2013-10-03 10:13:16638 // DeleteTask:
dchengb03027d2014-10-21 12:00:20639 int RunDeleteTask() override;
[email protected]d8428d52013-08-07 06:58:25640
641 protected:
dmurphfaea244c2016-04-09 00:42:30642 ~DeleteAllCreatedBetweenWithPredicateTask() override {}
[email protected]d8428d52013-08-07 06:58:25643
644 private:
645 Time delete_begin_;
646 Time delete_end_;
dmurphfaea244c2016-04-09 00:42:30647 base::Callback<bool(const CanonicalCookie&)> predicate_;
[email protected]d8428d52013-08-07 06:58:25648
dmurphfaea244c2016-04-09 00:42:30649 DISALLOW_COPY_AND_ASSIGN(DeleteAllCreatedBetweenWithPredicateTask);
[email protected]d8428d52013-08-07 06:58:25650};
651
dmurphfaea244c2016-04-09 00:42:30652int CookieMonster::DeleteAllCreatedBetweenWithPredicateTask::RunDeleteTask() {
653 return this->cookie_monster()->DeleteAllCreatedBetweenWithPredicate(
654 delete_begin_, delete_end_, predicate_);
[email protected]d8428d52013-08-07 06:58:25655}
656
[email protected]218aa6a12011-09-13 17:38:38657// Task class for DeleteCanonicalCookie call.
mmenke24379d52016-02-05 23:50:17658class CookieMonster::DeleteCanonicalCookieTask : public DeleteTask<int> {
[email protected]218aa6a12011-09-13 17:38:38659 public:
[email protected]dedec0b2013-02-28 04:50:10660 DeleteCanonicalCookieTask(CookieMonster* cookie_monster,
661 const CanonicalCookie& cookie,
mmenke24379d52016-02-05 23:50:17662 const DeleteCallback& callback)
663 : DeleteTask<int>(cookie_monster, callback), cookie_(cookie) {}
[email protected]218aa6a12011-09-13 17:38:38664
[email protected]5fa4f9a2013-10-03 10:13:16665 // DeleteTask:
mmenke24379d52016-02-05 23:50:17666 int RunDeleteTask() override;
[email protected]218aa6a12011-09-13 17:38:38667
[email protected]a9813302012-04-28 09:29:28668 protected:
dchengb03027d2014-10-21 12:00:20669 ~DeleteCanonicalCookieTask() override {}
[email protected]a9813302012-04-28 09:29:28670
[email protected]218aa6a12011-09-13 17:38:38671 private:
[email protected]5b9bc352012-07-18 13:13:34672 CanonicalCookie cookie_;
[email protected]218aa6a12011-09-13 17:38:38673
674 DISALLOW_COPY_AND_ASSIGN(DeleteCanonicalCookieTask);
675};
676
mmenke24379d52016-02-05 23:50:17677int CookieMonster::DeleteCanonicalCookieTask::RunDeleteTask() {
[email protected]5fa4f9a2013-10-03 10:13:16678 return this->cookie_monster()->DeleteCanonicalCookie(cookie_);
[email protected]218aa6a12011-09-13 17:38:38679}
680
681// Task class for SetCookieWithOptions call.
[email protected]5fa4f9a2013-10-03 10:13:16682class CookieMonster::SetCookieWithOptionsTask : public CookieMonsterTask {
[email protected]218aa6a12011-09-13 17:38:38683 public:
684 SetCookieWithOptionsTask(CookieMonster* cookie_monster,
685 const GURL& url,
686 const std::string& cookie_line,
687 const CookieOptions& options,
[email protected]5fa4f9a2013-10-03 10:13:16688 const SetCookiesCallback& callback)
[email protected]218aa6a12011-09-13 17:38:38689 : CookieMonsterTask(cookie_monster),
690 url_(url),
691 cookie_line_(cookie_line),
692 options_(options),
mkwstbe84af312015-02-20 08:52:45693 callback_(callback) {}
[email protected]218aa6a12011-09-13 17:38:38694
[email protected]5fa4f9a2013-10-03 10:13:16695 // CookieMonsterTask:
dchengb03027d2014-10-21 12:00:20696 void Run() override;
[email protected]218aa6a12011-09-13 17:38:38697
[email protected]a9813302012-04-28 09:29:28698 protected:
dchengb03027d2014-10-21 12:00:20699 ~SetCookieWithOptionsTask() override {}
[email protected]a9813302012-04-28 09:29:28700
[email protected]218aa6a12011-09-13 17:38:38701 private:
702 GURL url_;
703 std::string cookie_line_;
704 CookieOptions options_;
[email protected]5fa4f9a2013-10-03 10:13:16705 SetCookiesCallback callback_;
[email protected]218aa6a12011-09-13 17:38:38706
707 DISALLOW_COPY_AND_ASSIGN(SetCookieWithOptionsTask);
708};
709
710void CookieMonster::SetCookieWithOptionsTask::Run() {
mkwstbe84af312015-02-20 08:52:45711 bool result = this->cookie_monster()->SetCookieWithOptions(url_, cookie_line_,
712 options_);
mmenkebe0910d2016-03-01 19:09:09713 if (!callback_.is_null())
714 callback_.Run(result);
[email protected]218aa6a12011-09-13 17:38:38715}
716
drogerd5d1278c2015-03-17 19:21:51717// Task class for SetAllCookies call.
718class CookieMonster::SetAllCookiesTask : public CookieMonsterTask {
719 public:
720 SetAllCookiesTask(CookieMonster* cookie_monster,
721 const CookieList& list,
722 const SetCookiesCallback& callback)
723 : CookieMonsterTask(cookie_monster), list_(list), callback_(callback) {}
724
725 // CookieMonsterTask:
726 void Run() override;
727
728 protected:
729 ~SetAllCookiesTask() override {}
730
731 private:
732 CookieList list_;
733 SetCookiesCallback callback_;
734
735 DISALLOW_COPY_AND_ASSIGN(SetAllCookiesTask);
736};
737
738void CookieMonster::SetAllCookiesTask::Run() {
739 CookieList positive_diff;
740 CookieList negative_diff;
741 CookieList old_cookies = this->cookie_monster()->GetAllCookies();
742 this->cookie_monster()->ComputeCookieDiff(&old_cookies, &list_,
743 &positive_diff, &negative_diff);
744
745 for (CookieList::const_iterator it = negative_diff.begin();
746 it != negative_diff.end(); ++it) {
747 this->cookie_monster()->DeleteCanonicalCookie(*it);
748 }
749
750 bool result = true;
751 if (positive_diff.size() > 0)
752 result = this->cookie_monster()->SetCanonicalCookies(list_);
753
mmenkebe0910d2016-03-01 19:09:09754 if (!callback_.is_null())
755 callback_.Run(result);
drogerd5d1278c2015-03-17 19:21:51756}
757
[email protected]218aa6a12011-09-13 17:38:38758// Task class for GetCookiesWithOptions call.
[email protected]5fa4f9a2013-10-03 10:13:16759class CookieMonster::GetCookiesWithOptionsTask : public CookieMonsterTask {
[email protected]218aa6a12011-09-13 17:38:38760 public:
761 GetCookiesWithOptionsTask(CookieMonster* cookie_monster,
[email protected]0298caf82011-12-20 23:15:46762 const GURL& url,
[email protected]218aa6a12011-09-13 17:38:38763 const CookieOptions& options,
[email protected]5fa4f9a2013-10-03 10:13:16764 const GetCookiesCallback& callback)
[email protected]218aa6a12011-09-13 17:38:38765 : CookieMonsterTask(cookie_monster),
766 url_(url),
767 options_(options),
mkwstbe84af312015-02-20 08:52:45768 callback_(callback) {}
[email protected]218aa6a12011-09-13 17:38:38769
[email protected]5fa4f9a2013-10-03 10:13:16770 // CookieMonsterTask:
dchengb03027d2014-10-21 12:00:20771 void Run() override;
[email protected]218aa6a12011-09-13 17:38:38772
[email protected]a9813302012-04-28 09:29:28773 protected:
dchengb03027d2014-10-21 12:00:20774 ~GetCookiesWithOptionsTask() override {}
[email protected]a9813302012-04-28 09:29:28775
[email protected]218aa6a12011-09-13 17:38:38776 private:
777 GURL url_;
778 CookieOptions options_;
[email protected]5fa4f9a2013-10-03 10:13:16779 GetCookiesCallback callback_;
[email protected]218aa6a12011-09-13 17:38:38780
781 DISALLOW_COPY_AND_ASSIGN(GetCookiesWithOptionsTask);
782};
783
784void CookieMonster::GetCookiesWithOptionsTask::Run() {
mkwstbe84af312015-02-20 08:52:45785 std::string cookie =
786 this->cookie_monster()->GetCookiesWithOptions(url_, options_);
mmenkebe0910d2016-03-01 19:09:09787 if (!callback_.is_null())
788 callback_.Run(cookie);
[email protected]218aa6a12011-09-13 17:38:38789}
790
[email protected]218aa6a12011-09-13 17:38:38791// Task class for DeleteCookie call.
[email protected]5fa4f9a2013-10-03 10:13:16792class CookieMonster::DeleteCookieTask : public DeleteTask<void> {
[email protected]218aa6a12011-09-13 17:38:38793 public:
794 DeleteCookieTask(CookieMonster* cookie_monster,
[email protected]0298caf82011-12-20 23:15:46795 const GURL& url,
[email protected]218aa6a12011-09-13 17:38:38796 const std::string& cookie_name,
797 const base::Closure& callback)
[email protected]151132f2013-11-18 21:37:00798 : DeleteTask<void>(cookie_monster, callback),
[email protected]218aa6a12011-09-13 17:38:38799 url_(url),
mkwstbe84af312015-02-20 08:52:45800 cookie_name_(cookie_name) {}
[email protected]218aa6a12011-09-13 17:38:38801
[email protected]5fa4f9a2013-10-03 10:13:16802 // DeleteTask:
dchengb03027d2014-10-21 12:00:20803 void RunDeleteTask() override;
[email protected]218aa6a12011-09-13 17:38:38804
[email protected]a9813302012-04-28 09:29:28805 protected:
dchengb03027d2014-10-21 12:00:20806 ~DeleteCookieTask() override {}
[email protected]a9813302012-04-28 09:29:28807
[email protected]218aa6a12011-09-13 17:38:38808 private:
809 GURL url_;
810 std::string cookie_name_;
[email protected]218aa6a12011-09-13 17:38:38811
812 DISALLOW_COPY_AND_ASSIGN(DeleteCookieTask);
813};
814
[email protected]5fa4f9a2013-10-03 10:13:16815void CookieMonster::DeleteCookieTask::RunDeleteTask() {
[email protected]218aa6a12011-09-13 17:38:38816 this->cookie_monster()->DeleteCookie(url_, cookie_name_);
[email protected]218aa6a12011-09-13 17:38:38817}
818
[email protected]264807b2012-04-25 14:49:37819// Task class for DeleteSessionCookies call.
[email protected]5fa4f9a2013-10-03 10:13:16820class CookieMonster::DeleteSessionCookiesTask : public DeleteTask<int> {
[email protected]264807b2012-04-25 14:49:37821 public:
[email protected]dedec0b2013-02-28 04:50:10822 DeleteSessionCookiesTask(CookieMonster* cookie_monster,
[email protected]5fa4f9a2013-10-03 10:13:16823 const DeleteCallback& callback)
mkwstbe84af312015-02-20 08:52:45824 : DeleteTask<int>(cookie_monster, callback) {}
[email protected]264807b2012-04-25 14:49:37825
[email protected]5fa4f9a2013-10-03 10:13:16826 // DeleteTask:
dchengb03027d2014-10-21 12:00:20827 int RunDeleteTask() override;
[email protected]264807b2012-04-25 14:49:37828
[email protected]a9813302012-04-28 09:29:28829 protected:
dchengb03027d2014-10-21 12:00:20830 ~DeleteSessionCookiesTask() override {}
[email protected]a9813302012-04-28 09:29:28831
[email protected]264807b2012-04-25 14:49:37832 private:
[email protected]264807b2012-04-25 14:49:37833 DISALLOW_COPY_AND_ASSIGN(DeleteSessionCookiesTask);
834};
835
[email protected]5fa4f9a2013-10-03 10:13:16836int CookieMonster::DeleteSessionCookiesTask::RunDeleteTask() {
837 return this->cookie_monster()->DeleteSessionCookies();
[email protected]264807b2012-04-25 14:49:37838}
839
[email protected]218aa6a12011-09-13 17:38:38840// Asynchronous CookieMonster API
841
842void CookieMonster::SetCookieWithDetailsAsync(
[email protected]dedec0b2013-02-28 04:50:10843 const GURL& url,
844 const std::string& name,
845 const std::string& value,
846 const std::string& domain,
847 const std::string& path,
mmenkefdd4fc72016-02-05 20:53:24848 Time creation_time,
849 Time expiration_time,
850 Time last_access_time,
[email protected]dedec0b2013-02-28 04:50:10851 bool secure,
852 bool http_only,
mkwste1a29582016-03-15 10:07:52853 CookieSameSite same_site,
[email protected]ab2d75c82013-04-19 18:39:04854 CookiePriority priority,
[email protected]218aa6a12011-09-13 17:38:38855 const SetCookiesCallback& callback) {
mkwstbe84af312015-02-20 08:52:45856 scoped_refptr<SetCookieWithDetailsTask> task = new SetCookieWithDetailsTask(
mmenkeea4cd402016-02-02 04:03:10857 this, url, name, value, domain, path, creation_time, expiration_time,
jwwa26e439d2017-01-27 18:17:27858 last_access_time, secure, http_only, same_site, priority, callback);
[email protected]8562034e2011-10-17 17:35:04859 DoCookieTaskForURL(task, url);
[email protected]218aa6a12011-09-13 17:38:38860}
861
mmenke74bcbd52016-01-21 17:17:56862void CookieMonster::FlushStore(const base::Closure& callback) {
mmenkebe0910d2016-03-01 19:09:09863 DCHECK(thread_checker_.CalledOnValidThread());
mmenke606c59c2016-03-07 18:20:55864
mmenke74bcbd52016-01-21 17:17:56865 if (initialized_ && store_.get())
866 store_->Flush(callback);
867 else if (!callback.is_null())
868 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
869}
870
mmenkeded79da2016-02-06 08:28:51871void CookieMonster::SetForceKeepSessionState() {
mmenkebe0910d2016-03-01 19:09:09872 DCHECK(thread_checker_.CalledOnValidThread());
mmenke606c59c2016-03-07 18:20:55873
mmenkeded79da2016-02-06 08:28:51874 if (store_)
875 store_->SetForceKeepSessionState();
876}
877
drogerd5d1278c2015-03-17 19:21:51878void CookieMonster::SetAllCookiesAsync(const CookieList& list,
879 const SetCookiesCallback& callback) {
880 scoped_refptr<SetAllCookiesTask> task =
881 new SetAllCookiesTask(this, list, callback);
882 DoCookieTask(task);
883}
884
[email protected]218aa6a12011-09-13 17:38:38885void CookieMonster::SetCookieWithOptionsAsync(
886 const GURL& url,
887 const std::string& cookie_line,
888 const CookieOptions& options,
889 const SetCookiesCallback& callback) {
890 scoped_refptr<SetCookieWithOptionsTask> task =
891 new SetCookieWithOptionsTask(this, url, cookie_line, options, callback);
892
[email protected]8562034e2011-10-17 17:35:04893 DoCookieTaskForURL(task, url);
[email protected]218aa6a12011-09-13 17:38:38894}
895
896void CookieMonster::GetCookiesWithOptionsAsync(
897 const GURL& url,
898 const CookieOptions& options,
899 const GetCookiesCallback& callback) {
900 scoped_refptr<GetCookiesWithOptionsTask> task =
901 new GetCookiesWithOptionsTask(this, url, options, callback);
902
[email protected]8562034e2011-10-17 17:35:04903 DoCookieTaskForURL(task, url);
[email protected]218aa6a12011-09-13 17:38:38904}
905
mkwstc611e6d2016-02-23 15:45:55906void CookieMonster::GetCookieListWithOptionsAsync(
mmenke74bcbd52016-01-21 17:17:56907 const GURL& url,
mkwstc611e6d2016-02-23 15:45:55908 const CookieOptions& options,
mmenke74bcbd52016-01-21 17:17:56909 const GetCookieListCallback& callback) {
mkwstc611e6d2016-02-23 15:45:55910 scoped_refptr<GetCookieListWithOptionsTask> task =
911 new GetCookieListWithOptionsTask(this, url, options, callback);
mmenke74bcbd52016-01-21 17:17:56912
913 DoCookieTaskForURL(task, url);
914}
915
mmenke9fa44f2d2016-01-22 23:36:39916void CookieMonster::GetAllCookiesAsync(const GetCookieListCallback& callback) {
917 scoped_refptr<GetAllCookiesTask> task = new GetAllCookiesTask(this, callback);
918
919 DoCookieTask(task);
920}
921
[email protected]218aa6a12011-09-13 17:38:38922void CookieMonster::DeleteCookieAsync(const GURL& url,
923 const std::string& cookie_name,
924 const base::Closure& callback) {
925 scoped_refptr<DeleteCookieTask> task =
926 new DeleteCookieTask(this, url, cookie_name, callback);
927
[email protected]8562034e2011-10-17 17:35:04928 DoCookieTaskForURL(task, url);
[email protected]218aa6a12011-09-13 17:38:38929}
930
mmenke24379d52016-02-05 23:50:17931void CookieMonster::DeleteCanonicalCookieAsync(const CanonicalCookie& cookie,
932 const DeleteCallback& callback) {
933 scoped_refptr<DeleteCanonicalCookieTask> task =
934 new DeleteCanonicalCookieTask(this, cookie, callback);
935
936 DoCookieTask(task);
937}
938
mmenke74bcbd52016-01-21 17:17:56939void CookieMonster::DeleteAllCreatedBetweenAsync(
940 const Time& delete_begin,
941 const Time& delete_end,
942 const DeleteCallback& callback) {
943 scoped_refptr<DeleteAllCreatedBetweenTask> task =
944 new DeleteAllCreatedBetweenTask(this, delete_begin, delete_end, callback);
945
946 DoCookieTask(task);
947}
948
dmurphfaea244c2016-04-09 00:42:30949void CookieMonster::DeleteAllCreatedBetweenWithPredicateAsync(
950 const Time& delete_begin,
951 const Time& delete_end,
952 const base::Callback<bool(const CanonicalCookie&)>& predicate,
mmenke74bcbd52016-01-21 17:17:56953 const DeleteCallback& callback) {
dmurphfaea244c2016-04-09 00:42:30954 if (predicate.is_null()) {
955 callback.Run(0);
956 return;
957 }
958 scoped_refptr<DeleteAllCreatedBetweenWithPredicateTask> task =
959 new DeleteAllCreatedBetweenWithPredicateTask(
960 this, delete_begin, delete_end, predicate, callback);
961 DoCookieTask(task);
mmenke74bcbd52016-01-21 17:17:56962}
963
[email protected]264807b2012-04-25 14:49:37964void CookieMonster::DeleteSessionCookiesAsync(
965 const CookieStore::DeleteCallback& callback) {
966 scoped_refptr<DeleteSessionCookiesTask> task =
967 new DeleteSessionCookiesTask(this, callback);
968
969 DoCookieTask(task);
970}
971
mmenke18dd8ba2016-02-01 18:42:10972void CookieMonster::SetCookieableSchemes(
973 const std::vector<std::string>& schemes) {
mmenkebe0910d2016-03-01 19:09:09974 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56975
976 // Calls to this method will have no effect if made after a WebView or
977 // CookieManager instance has been created.
mmenke18dd8ba2016-02-01 18:42:10978 if (initialized_)
mmenke74bcbd52016-01-21 17:17:56979 return;
mmenke74bcbd52016-01-21 17:17:56980
mmenke18dd8ba2016-02-01 18:42:10981 cookieable_schemes_ = schemes;
mmenke74bcbd52016-01-21 17:17:56982}
983
mmenke74bcbd52016-01-21 17:17:56984// This function must be called before the CookieMonster is used.
985void CookieMonster::SetPersistSessionCookies(bool persist_session_cookies) {
mmenkebe0910d2016-03-01 19:09:09986 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56987 DCHECK(!initialized_);
988 persist_session_cookies_ = persist_session_cookies;
989}
990
991bool CookieMonster::IsCookieableScheme(const std::string& scheme) {
mmenkebe0910d2016-03-01 19:09:09992 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:56993
994 return std::find(cookieable_schemes_.begin(), cookieable_schemes_.end(),
995 scheme) != cookieable_schemes_.end();
996}
997
mmenke18dd8ba2016-02-01 18:42:10998const char* const CookieMonster::kDefaultCookieableSchemes[] = {"http", "https",
999 "ws", "wss"};
mmenke74bcbd52016-01-21 17:17:561000const int CookieMonster::kDefaultCookieableSchemesCount =
1001 arraysize(kDefaultCookieableSchemes);
1002
danakja9850e12016-04-18 22:28:081003std::unique_ptr<CookieStore::CookieChangedSubscription>
mmenke74bcbd52016-01-21 17:17:561004CookieMonster::AddCallbackForCookie(const GURL& gurl,
1005 const std::string& name,
1006 const CookieChangedCallback& callback) {
mmenkebe0910d2016-03-01 19:09:091007 DCHECK(thread_checker_.CalledOnValidThread());
mmenke606c59c2016-03-07 18:20:551008
mmenke74bcbd52016-01-21 17:17:561009 std::pair<GURL, std::string> key(gurl, name);
1010 if (hook_map_.count(key) == 0)
avie7cd11a2016-10-11 02:00:351011 hook_map_[key] = base::MakeUnique<CookieChangedCallbackList>();
mmenke74bcbd52016-01-21 17:17:561012 return hook_map_[key]->Add(
1013 base::Bind(&RunAsync, base::ThreadTaskRunnerHandle::Get(), callback));
1014}
1015
nharper5babb5e62016-03-09 18:58:071016bool CookieMonster::IsEphemeral() {
1017 return store_.get() == nullptr;
1018}
1019
mmenke74bcbd52016-01-21 17:17:561020CookieMonster::~CookieMonster() {
mmenkebe0910d2016-03-01 19:09:091021 DCHECK(thread_checker_.CalledOnValidThread());
mmenke05255cf2016-02-03 15:49:311022
mmenke606c59c2016-03-07 18:20:551023 // TODO(mmenke): Does it really make sense to run |delegate_| and
1024 // CookieChanged callbacks when the CookieStore is destroyed?
mmenke05255cf2016-02-03 15:49:311025 for (CookieMap::iterator cookie_it = cookies_.begin();
1026 cookie_it != cookies_.end();) {
1027 CookieMap::iterator current_cookie_it = cookie_it;
1028 ++cookie_it;
1029 InternalDeleteCookie(current_cookie_it, false /* sync_to_store */,
1030 DELETE_COOKIE_DONT_RECORD);
1031 }
[email protected]8562034e2011-10-17 17:35:041032}
1033
[email protected]dedec0b2013-02-28 04:50:101034bool CookieMonster::SetCookieWithDetails(const GURL& url,
1035 const std::string& name,
1036 const std::string& value,
1037 const std::string& domain,
1038 const std::string& path,
mmenkefdd4fc72016-02-05 20:53:241039 base::Time creation_time,
1040 base::Time expiration_time,
1041 base::Time last_access_time,
[email protected]dedec0b2013-02-28 04:50:101042 bool secure,
[email protected]ab2d75c82013-04-19 18:39:041043 bool http_only,
mkwste1a29582016-03-15 10:07:521044 CookieSameSite same_site,
[email protected]ab2d75c82013-04-19 18:39:041045 CookiePriority priority) {
mmenkebe0910d2016-03-01 19:09:091046 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]69bb5872010-01-12 20:33:521047
[email protected]f48b9432011-01-11 07:25:401048 if (!HasCookieableScheme(url))
initial.commit586acc5fe2008-07-26 22:42:521049 return false;
1050
mmenkeea4cd402016-02-02 04:03:101051 // TODO(mmenke): This class assumes each cookie to have a unique creation
1052 // time. Allowing the caller to set the creation time violates that
1053 // assumption. Worth fixing? Worth noting that time changes between browser
1054 // restarts can cause the same issue.
1055 base::Time actual_creation_time = creation_time;
1056 if (creation_time.is_null()) {
1057 actual_creation_time = CurrentTime();
1058 last_time_seen_ = actual_creation_time;
1059 }
[email protected]f48b9432011-01-11 07:25:401060
danakja9850e12016-04-18 22:28:081061 std::unique_ptr<CanonicalCookie> cc(CanonicalCookie::Create(
mmenkeea4cd402016-02-02 04:03:101062 url, name, value, domain, path, actual_creation_time, expiration_time,
jwwa26e439d2017-01-27 18:17:271063 secure, http_only, same_site, priority));
[email protected]f48b9432011-01-11 07:25:401064
1065 if (!cc.get())
1066 return false;
1067
mmenkefdd4fc72016-02-05 20:53:241068 if (!last_access_time.is_null())
1069 cc->SetLastAccessDate(last_access_time);
1070
[email protected]f48b9432011-01-11 07:25:401071 CookieOptions options;
1072 options.set_include_httponly();
mkwstf71d0bd2016-03-21 14:15:241073 options.set_same_site_cookie_mode(
1074 CookieOptions::SameSiteCookieMode::INCLUDE_STRICT_AND_LAX);
mmenke009cf62e2016-07-18 19:33:311075 return SetCanonicalCookie(std::move(cc), url, options);
initial.commit586acc5fe2008-07-26 22:42:521076}
1077
[email protected]f48b9432011-01-11 07:25:401078CookieList CookieMonster::GetAllCookies() {
mmenkebe0910d2016-03-01 19:09:091079 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401080
1081 // This function is being called to scrape the cookie list for management UI
1082 // or similar. We shouldn't show expired cookies in this list since it will
1083 // just be confusing to users, and this function is called rarely enough (and
1084 // is already slow enough) that it's OK to take the time to garbage collect
1085 // the expired cookies now.
1086 //
1087 // Note that this does not prune cookies to be below our limits (if we've
1088 // exceeded them) the way that calling GarbageCollect() would.
mkwstbe84af312015-02-20 08:52:451089 GarbageCollectExpired(
1090 Time::Now(), CookieMapItPair(cookies_.begin(), cookies_.end()), NULL);
[email protected]f48b9432011-01-11 07:25:401091
1092 // Copy the CanonicalCookie pointers from the map so that we can use the same
1093 // sorter as elsewhere, then copy the result out.
1094 std::vector<CanonicalCookie*> cookie_ptrs;
1095 cookie_ptrs.reserve(cookies_.size());
avie7cd11a2016-10-11 02:00:351096 for (const auto& cookie : cookies_)
1097 cookie_ptrs.push_back(cookie.second.get());
[email protected]f48b9432011-01-11 07:25:401098 std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
1099
1100 CookieList cookie_list;
1101 cookie_list.reserve(cookie_ptrs.size());
vmpstr6d9996c82017-02-23 00:43:251102 for (auto* cookie_ptr : cookie_ptrs)
avie7cd11a2016-10-11 02:00:351103 cookie_list.push_back(*cookie_ptr);
[email protected]f48b9432011-01-11 07:25:401104
1105 return cookie_list;
[email protected]f325f1e12010-04-30 22:38:551106}
1107
mkwstc611e6d2016-02-23 15:45:551108CookieList CookieMonster::GetCookieListWithOptions(
[email protected]f48b9432011-01-11 07:25:401109 const GURL& url,
1110 const CookieOptions& options) {
mmenkebe0910d2016-03-01 19:09:091111 DCHECK(thread_checker_.CalledOnValidThread());
initial.commit586acc5fe2008-07-26 22:42:521112
mkwstc611e6d2016-02-23 15:45:551113 CookieList cookies;
1114 if (!HasCookieableScheme(url))
1115 return cookies;
1116
[email protected]f48b9432011-01-11 07:25:401117 std::vector<CanonicalCookie*> cookie_ptrs;
mkwst72b65162016-02-22 19:58:541118 FindCookiesForHostAndDomain(url, options, &cookie_ptrs);
[email protected]f48b9432011-01-11 07:25:401119 std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
initial.commit586acc5fe2008-07-26 22:42:521120
georgesakc15df6722014-12-02 23:52:121121 cookies.reserve(cookie_ptrs.size());
[email protected]f48b9432011-01-11 07:25:401122 for (std::vector<CanonicalCookie*>::const_iterator it = cookie_ptrs.begin();
1123 it != cookie_ptrs.end(); it++)
1124 cookies.push_back(**it);
initial.commit586acc5fe2008-07-26 22:42:521125
[email protected]f48b9432011-01-11 07:25:401126 return cookies;
initial.commit586acc5fe2008-07-26 22:42:521127}
1128
[email protected]f48b9432011-01-11 07:25:401129int CookieMonster::DeleteAllCreatedBetween(const Time& delete_begin,
[email protected]218aa6a12011-09-13 17:38:381130 const Time& delete_end) {
mmenkebe0910d2016-03-01 19:09:091131 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]d0980332010-11-16 17:08:531132
[email protected]f48b9432011-01-11 07:25:401133 int num_deleted = 0;
1134 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
1135 CookieMap::iterator curit = it;
avie7cd11a2016-10-11 02:00:351136 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:401137 ++it;
[email protected]d0980332010-11-16 17:08:531138
[email protected]f48b9432011-01-11 07:25:401139 if (cc->CreationDate() >= delete_begin &&
1140 (delete_end.is_null() || cc->CreationDate() < delete_end)) {
mkwstbe84af312015-02-20 08:52:451141 InternalDeleteCookie(curit, true, /*sync_to_store*/
nharper68903362017-01-20 04:07:141142 DELETE_COOKIE_CREATED_BETWEEN);
[email protected]f48b9432011-01-11 07:25:401143 ++num_deleted;
initial.commit586acc5fe2008-07-26 22:42:521144 }
1145 }
1146
[email protected]f48b9432011-01-11 07:25:401147 return num_deleted;
1148}
1149
dmurphfaea244c2016-04-09 00:42:301150int CookieMonster::DeleteAllCreatedBetweenWithPredicate(
1151 const base::Time& delete_begin,
1152 const base::Time& delete_end,
1153 const base::Callback<bool(const CanonicalCookie&)>& predicate) {
[email protected]f48b9432011-01-11 07:25:401154 int num_deleted = 0;
dmurphfaea244c2016-04-09 00:42:301155 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
1156 CookieMap::iterator curit = it;
avie7cd11a2016-10-11 02:00:351157 CanonicalCookie* cc = curit->second.get();
dmurphfaea244c2016-04-09 00:42:301158 ++it;
[email protected]f48b9432011-01-11 07:25:401159
dmurphfaea244c2016-04-09 00:42:301160 if (cc->CreationDate() >= delete_begin &&
[email protected]d8428d52013-08-07 06:58:251161 // The assumption that null |delete_end| is equivalent to
1162 // Time::Max() is confusing.
dmurphfaea244c2016-04-09 00:42:301163 (delete_end.is_null() || cc->CreationDate() < delete_end) &&
1164 predicate.Run(*cc)) {
1165 InternalDeleteCookie(curit, true, /*sync_to_store*/
nharper68903362017-01-20 04:07:141166 DELETE_COOKIE_CREATED_BETWEEN_WITH_PREDICATE);
dmurphfaea244c2016-04-09 00:42:301167 ++num_deleted;
[email protected]f48b9432011-01-11 07:25:401168 }
1169 }
dmurphfaea244c2016-04-09 00:42:301170
[email protected]f48b9432011-01-11 07:25:401171 return num_deleted;
1172}
1173
[email protected]f48b9432011-01-11 07:25:401174bool CookieMonster::SetCookieWithOptions(const GURL& url,
1175 const std::string& cookie_line,
1176 const CookieOptions& options) {
mmenkebe0910d2016-03-01 19:09:091177 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401178
1179 if (!HasCookieableScheme(url)) {
1180 return false;
1181 }
1182
[email protected]f48b9432011-01-11 07:25:401183 return SetCookieWithCreationTimeAndOptions(url, cookie_line, Time(), options);
1184}
1185
1186std::string CookieMonster::GetCookiesWithOptions(const GURL& url,
1187 const CookieOptions& options) {
mmenkebe0910d2016-03-01 19:09:091188 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401189
[email protected]34a160d2011-05-12 22:12:491190 if (!HasCookieableScheme(url))
[email protected]f48b9432011-01-11 07:25:401191 return std::string();
[email protected]f48b9432011-01-11 07:25:401192
[email protected]f48b9432011-01-11 07:25:401193 std::vector<CanonicalCookie*> cookies;
mkwst72b65162016-02-22 19:58:541194 FindCookiesForHostAndDomain(url, options, &cookies);
[email protected]f48b9432011-01-11 07:25:401195 std::sort(cookies.begin(), cookies.end(), CookieSorter);
1196
[email protected]34a160d2011-05-12 22:12:491197 std::string cookie_line = BuildCookieLine(cookies);
[email protected]f48b9432011-01-11 07:25:401198
[email protected]f48b9432011-01-11 07:25:401199 VLOG(kVlogGetCookies) << "GetCookies() result: " << cookie_line;
1200
1201 return cookie_line;
1202}
1203
1204void CookieMonster::DeleteCookie(const GURL& url,
1205 const std::string& cookie_name) {
mmenkebe0910d2016-03-01 19:09:091206 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401207
1208 if (!HasCookieableScheme(url))
1209 return;
1210
1211 CookieOptions options;
1212 options.set_include_httponly();
mkwstf71d0bd2016-03-21 14:15:241213 options.set_same_site_cookie_mode(
1214 CookieOptions::SameSiteCookieMode::INCLUDE_STRICT_AND_LAX);
[email protected]f48b9432011-01-11 07:25:401215 // Get the cookies for this host and its domain(s).
1216 std::vector<CanonicalCookie*> cookies;
mkwst72b65162016-02-22 19:58:541217 FindCookiesForHostAndDomain(url, options, &cookies);
[email protected]f48b9432011-01-11 07:25:401218 std::set<CanonicalCookie*> matching_cookies;
1219
vmpstr6f21f242016-06-29 02:16:471220 for (auto* cookie : cookies) {
mmenke4379aeb2016-03-05 12:22:071221 if (cookie->Name() != cookie_name)
[email protected]f48b9432011-01-11 07:25:401222 continue;
mmenke4379aeb2016-03-05 12:22:071223 if (!cookie->IsOnPath(url.path()))
[email protected]f48b9432011-01-11 07:25:401224 continue;
mmenke4379aeb2016-03-05 12:22:071225 matching_cookies.insert(cookie);
[email protected]f48b9432011-01-11 07:25:401226 }
1227
1228 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
1229 CookieMap::iterator curit = it;
1230 ++it;
avie7cd11a2016-10-11 02:00:351231 if (matching_cookies.find(curit->second.get()) != matching_cookies.end()) {
nharper68903362017-01-20 04:07:141232 InternalDeleteCookie(curit, true, DELETE_COOKIE_SINGLE);
[email protected]f48b9432011-01-11 07:25:401233 }
1234 }
1235}
1236
mmenke24379d52016-02-05 23:50:171237int CookieMonster::DeleteCanonicalCookie(const CanonicalCookie& cookie) {
mmenkebe0910d2016-03-01 19:09:091238 DCHECK(thread_checker_.CalledOnValidThread());
mmenke24379d52016-02-05 23:50:171239
1240 for (CookieMapItPair its = cookies_.equal_range(GetKey(cookie.Domain()));
1241 its.first != its.second; ++its.first) {
1242 // The creation date acts as the unique index...
1243 if (its.first->second->CreationDate() == cookie.CreationDate()) {
nharper68903362017-01-20 04:07:141244 InternalDeleteCookie(its.first, true, DELETE_COOKIE_CANONICAL);
mmenke24379d52016-02-05 23:50:171245 return 1;
1246 }
1247 }
1248 return 0;
1249}
1250
mmenke74bcbd52016-01-21 17:17:561251bool CookieMonster::SetCookieWithCreationTime(const GURL& url,
1252 const std::string& cookie_line,
1253 const base::Time& creation_time) {
mmenkebe0910d2016-03-01 19:09:091254 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:561255 DCHECK(!store_.get()) << "This method is only to be used by unit-tests.";
mmenke74bcbd52016-01-21 17:17:561256
1257 if (!HasCookieableScheme(url)) {
1258 return false;
1259 }
1260
1261 MarkCookieStoreAsInitialized();
1262 if (ShouldFetchAllCookiesWhenFetchingAnyCookie())
1263 FetchAllCookiesIfNecessary();
1264
1265 return SetCookieWithCreationTimeAndOptions(url, cookie_line, creation_time,
1266 CookieOptions());
1267}
1268
[email protected]264807b2012-04-25 14:49:371269int CookieMonster::DeleteSessionCookies() {
mmenkebe0910d2016-03-01 19:09:091270 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]264807b2012-04-25 14:49:371271
1272 int num_deleted = 0;
1273 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
1274 CookieMap::iterator curit = it;
avie7cd11a2016-10-11 02:00:351275 CanonicalCookie* cc = curit->second.get();
[email protected]264807b2012-04-25 14:49:371276 ++it;
1277
1278 if (!cc->IsPersistent()) {
mkwstbe84af312015-02-20 08:52:451279 InternalDeleteCookie(curit, true, /*sync_to_store*/
[email protected]264807b2012-04-25 14:49:371280 DELETE_COOKIE_EXPIRED);
1281 ++num_deleted;
1282 }
1283 }
1284
1285 return num_deleted;
1286}
1287
erikchen1dd72a72015-05-06 20:45:051288void CookieMonster::MarkCookieStoreAsInitialized() {
mmenkebe0910d2016-03-01 19:09:091289 DCHECK(thread_checker_.CalledOnValidThread());
erikchen1dd72a72015-05-06 20:45:051290 initialized_ = true;
1291}
1292
1293void CookieMonster::FetchAllCookiesIfNecessary() {
mmenkebe0910d2016-03-01 19:09:091294 DCHECK(thread_checker_.CalledOnValidThread());
erikchen1dd72a72015-05-06 20:45:051295 if (store_.get() && !started_fetching_all_cookies_) {
1296 started_fetching_all_cookies_ = true;
1297 FetchAllCookies();
1298 }
1299}
1300
mmenke74bcbd52016-01-21 17:17:561301void CookieMonster::FetchAllCookies() {
mmenkebe0910d2016-03-01 19:09:091302 DCHECK(thread_checker_.CalledOnValidThread());
mmenke74bcbd52016-01-21 17:17:561303 DCHECK(store_.get()) << "Store must exist to initialize";
1304 DCHECK(!finished_fetching_all_cookies_)
1305 << "All cookies have already been fetched.";
1306
1307 // We bind in the current time so that we can report the wall-clock time for
1308 // loading cookies.
mmenkebe0910d2016-03-01 19:09:091309 store_->Load(base::Bind(&CookieMonster::OnLoaded,
1310 weak_ptr_factory_.GetWeakPtr(), TimeTicks::Now()));
mmenke74bcbd52016-01-21 17:17:561311}
1312
erikchen1dd72a72015-05-06 20:45:051313bool CookieMonster::ShouldFetchAllCookiesWhenFetchingAnyCookie() {
mmenkebe0910d2016-03-01 19:09:091314 DCHECK(thread_checker_.CalledOnValidThread());
1315
erikchen1dd72a72015-05-06 20:45:051316 if (fetch_strategy_ == kUnknownFetch) {
1317 const std::string group_name =
1318 base::FieldTrialList::FindFullName(kCookieMonsterFetchStrategyName);
1319 if (group_name == kFetchWhenNecessaryName) {
1320 fetch_strategy_ = kFetchWhenNecessary;
1321 } else if (group_name == kAlwaysFetchName) {
1322 fetch_strategy_ = kAlwaysFetch;
1323 } else {
1324 // The logic in the conditional is redundant, but it makes trials of
1325 // the Finch experiment more explicit.
1326 fetch_strategy_ = kAlwaysFetch;
1327 }
1328 }
1329
1330 return fetch_strategy_ == kAlwaysFetch;
1331}
1332
avie7cd11a2016-10-11 02:00:351333void CookieMonster::OnLoaded(
1334 TimeTicks beginning_time,
1335 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:091336 DCHECK(thread_checker_.CalledOnValidThread());
avie7cd11a2016-10-11 02:00:351337 StoreLoadedCookies(std::move(cookies));
[email protected]c7593fb22011-11-14 23:54:271338 histogram_time_blocked_on_load_->AddTime(TimeTicks::Now() - beginning_time);
[email protected]218aa6a12011-09-13 17:38:381339
1340 // Invoke the task queue of cookie request.
1341 InvokeQueue();
1342}
1343
avie7cd11a2016-10-11 02:00:351344void CookieMonster::OnKeyLoaded(
1345 const std::string& key,
1346 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:091347 DCHECK(thread_checker_.CalledOnValidThread());
1348
avie7cd11a2016-10-11 02:00:351349 StoreLoadedCookies(std::move(cookies));
[email protected]8562034e2011-10-17 17:35:041350
mmenkebe0910d2016-03-01 19:09:091351 auto tasks_pending_for_key = tasks_pending_for_key_.find(key);
[email protected]8562034e2011-10-17 17:35:041352
mmenkebe0910d2016-03-01 19:09:091353 // TODO(mmenke): Can this be turned into a DCHECK?
1354 if (tasks_pending_for_key == tasks_pending_for_key_.end())
1355 return;
[email protected]bab72ec2013-10-30 20:50:021356
mmenkebe0910d2016-03-01 19:09:091357 // Run all tasks for the key. Note that running a task can result in multiple
1358 // tasks being added to the back of the deque.
1359 while (!tasks_pending_for_key->second.empty()) {
1360 scoped_refptr<CookieMonsterTask> task =
1361 tasks_pending_for_key->second.front();
1362 tasks_pending_for_key->second.pop_front();
1363
1364 task->Run();
[email protected]8562034e2011-10-17 17:35:041365 }
mmenkebe0910d2016-03-01 19:09:091366
1367 tasks_pending_for_key_.erase(tasks_pending_for_key);
1368
1369 // This has to be done last, in case running a task queues a new task for the
1370 // key, to ensure tasks are run in the correct order.
1371 keys_loaded_.insert(key);
[email protected]8562034e2011-10-17 17:35:041372}
1373
[email protected]218aa6a12011-09-13 17:38:381374void CookieMonster::StoreLoadedCookies(
avie7cd11a2016-10-11 02:00:351375 std::vector<std::unique_ptr<CanonicalCookie>> cookies) {
mmenkebe0910d2016-03-01 19:09:091376 DCHECK(thread_checker_.CalledOnValidThread());
1377
pkastingec2cdb52015-05-02 01:19:341378 // TODO(erikwright): Remove ScopedTracker below once crbug.com/457528 is
1379 // fixed.
1380 tracked_objects::ScopedTracker tracking_profile(
1381 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1382 "457528 CookieMonster::StoreLoadedCookies"));
1383
mmenkebe0910d2016-03-01 19:09:091384 // Even if a key is expired, insert it so it can be garbage collected,
1385 // removed, and sync'd.
[email protected]6210ce52013-09-20 03:33:141386 CookieItVector cookies_with_control_chars;
1387
avie7cd11a2016-10-11 02:00:351388 for (auto& cookie : cookies) {
1389 int64_t cookie_creation_time = cookie->CreationDate().ToInternalValue();
[email protected]f48b9432011-01-11 07:25:401390
[email protected]8562034e2011-10-17 17:35:041391 if (creation_times_.insert(cookie_creation_time).second) {
avie7cd11a2016-10-11 02:00:351392 CanonicalCookie* cookie_ptr = cookie.get();
1393 CookieMap::iterator inserted = InternalInsertCookie(
1394 GetKey(cookie_ptr->Domain()), std::move(cookie), GURL(), false);
1395 const Time cookie_access_time(cookie_ptr->LastAccessDate());
[email protected]8562034e2011-10-17 17:35:041396 if (earliest_access_time_.is_null() ||
1397 cookie_access_time < earliest_access_time_)
1398 earliest_access_time_ = cookie_access_time;
[email protected]6210ce52013-09-20 03:33:141399
avie7cd11a2016-10-11 02:00:351400 if (ContainsControlCharacter(cookie_ptr->Name()) ||
1401 ContainsControlCharacter(cookie_ptr->Value())) {
mkwstbe84af312015-02-20 08:52:451402 cookies_with_control_chars.push_back(inserted);
[email protected]6210ce52013-09-20 03:33:141403 }
[email protected]f48b9432011-01-11 07:25:401404 } else {
mkwstbe84af312015-02-20 08:52:451405 LOG(ERROR) << base::StringPrintf(
1406 "Found cookies with duplicate creation "
1407 "times in backing store: "
1408 "{name='%s', domain='%s', path='%s'}",
avie7cd11a2016-10-11 02:00:351409 cookie->Name().c_str(), cookie->Domain().c_str(),
1410 cookie->Path().c_str());
[email protected]f48b9432011-01-11 07:25:401411 }
1412 }
[email protected]f48b9432011-01-11 07:25:401413
[email protected]6210ce52013-09-20 03:33:141414 // Any cookies that contain control characters that we have loaded from the
1415 // persistent store should be deleted. See http://crbug.com/238041.
1416 for (CookieItVector::iterator it = cookies_with_control_chars.begin();
1417 it != cookies_with_control_chars.end();) {
1418 CookieItVector::iterator curit = it;
1419 ++it;
1420
1421 InternalDeleteCookie(*curit, true, DELETE_COOKIE_CONTROL_CHAR);
1422 }
1423
[email protected]f48b9432011-01-11 07:25:401424 // After importing cookies from the PersistentCookieStore, verify that
1425 // none of our other constraints are violated.
[email protected]f48b9432011-01-11 07:25:401426 // In particular, the backing store might have given us duplicate cookies.
[email protected]8562034e2011-10-17 17:35:041427
1428 // This method could be called multiple times due to priority loading, thus
1429 // cookies loaded in previous runs will be validated again, but this is OK
1430 // since they are expected to be much fewer than total DB.
[email protected]f48b9432011-01-11 07:25:401431 EnsureCookiesMapIsValid();
[email protected]218aa6a12011-09-13 17:38:381432}
[email protected]f48b9432011-01-11 07:25:401433
[email protected]218aa6a12011-09-13 17:38:381434void CookieMonster::InvokeQueue() {
mmenkebe0910d2016-03-01 19:09:091435 DCHECK(thread_checker_.CalledOnValidThread());
1436
mmenkef49fca0e2016-03-08 12:46:241437 // Move all per-key tasks into the global queue, if there are any. This is
1438 // protection about a race where the store learns about all cookies loading
1439 // before it learned about the cookies for a key loading.
1440
1441 // Needed to prevent any recursively queued tasks from going back into the
1442 // per-key queues.
1443 seen_global_task_ = true;
1444 for (const auto& tasks_for_key : tasks_pending_for_key_) {
1445 tasks_pending_.insert(tasks_pending_.begin(), tasks_for_key.second.begin(),
1446 tasks_for_key.second.end());
1447 }
1448 tasks_pending_for_key_.clear();
1449
mmenkebe0910d2016-03-01 19:09:091450 while (!tasks_pending_.empty()) {
1451 scoped_refptr<CookieMonsterTask> request_task = tasks_pending_.front();
mmenkef49fca0e2016-03-08 12:46:241452 tasks_pending_.pop_front();
[email protected]218aa6a12011-09-13 17:38:381453 request_task->Run();
1454 }
mmenkebe0910d2016-03-01 19:09:091455
mmenkef49fca0e2016-03-08 12:46:241456 DCHECK(tasks_pending_for_key_.empty());
1457
mmenkebe0910d2016-03-01 19:09:091458 finished_fetching_all_cookies_ = true;
1459 creation_times_.clear();
1460 keys_loaded_.clear();
[email protected]f48b9432011-01-11 07:25:401461}
1462
1463void CookieMonster::EnsureCookiesMapIsValid() {
mmenkebe0910d2016-03-01 19:09:091464 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401465
[email protected]f48b9432011-01-11 07:25:401466 // Iterate through all the of the cookies, grouped by host.
1467 CookieMap::iterator prev_range_end = cookies_.begin();
1468 while (prev_range_end != cookies_.end()) {
1469 CookieMap::iterator cur_range_begin = prev_range_end;
1470 const std::string key = cur_range_begin->first; // Keep a copy.
1471 CookieMap::iterator cur_range_end = cookies_.upper_bound(key);
1472 prev_range_end = cur_range_end;
1473
1474 // Ensure no equivalent cookies for this host.
ellyjonescabf57422015-08-21 18:44:511475 TrimDuplicateCookiesForKey(key, cur_range_begin, cur_range_end);
[email protected]f48b9432011-01-11 07:25:401476 }
[email protected]f48b9432011-01-11 07:25:401477}
1478
ellyjonescabf57422015-08-21 18:44:511479void CookieMonster::TrimDuplicateCookiesForKey(const std::string& key,
1480 CookieMap::iterator begin,
1481 CookieMap::iterator end) {
mmenkebe0910d2016-03-01 19:09:091482 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401483
1484 // Set of cookies ordered by creation time.
1485 typedef std::set<CookieMap::iterator, OrderByCreationTimeDesc> CookieSet;
1486
1487 // Helper map we populate to find the duplicates.
1488 typedef std::map<CookieSignature, CookieSet> EquivalenceMap;
1489 EquivalenceMap equivalent_cookies;
1490
1491 // The number of duplicate cookies that have been found.
1492 int num_duplicates = 0;
1493
1494 // Iterate through all of the cookies in our range, and insert them into
1495 // the equivalence map.
1496 for (CookieMap::iterator it = begin; it != end; ++it) {
1497 DCHECK_EQ(key, it->first);
avie7cd11a2016-10-11 02:00:351498 CanonicalCookie* cookie = it->second.get();
[email protected]f48b9432011-01-11 07:25:401499
mkwstbe84af312015-02-20 08:52:451500 CookieSignature signature(cookie->Name(), cookie->Domain(), cookie->Path());
[email protected]f48b9432011-01-11 07:25:401501 CookieSet& set = equivalent_cookies[signature];
1502
1503 // We found a duplicate!
1504 if (!set.empty())
1505 num_duplicates++;
1506
1507 // We save the iterator into |cookies_| rather than the actual cookie
1508 // pointer, since we may need to delete it later.
1509 bool insert_success = set.insert(it).second;
mkwstbe84af312015-02-20 08:52:451510 DCHECK(insert_success)
1511 << "Duplicate creation times found in duplicate cookie name scan.";
[email protected]f48b9432011-01-11 07:25:401512 }
1513
1514 // If there were no duplicates, we are done!
1515 if (num_duplicates == 0)
ellyjonescabf57422015-08-21 18:44:511516 return;
[email protected]f48b9432011-01-11 07:25:401517
1518 // Make sure we find everything below that we did above.
1519 int num_duplicates_found = 0;
1520
1521 // Otherwise, delete all the duplicate cookies, both from our in-memory store
1522 // and from the backing store.
1523 for (EquivalenceMap::iterator it = equivalent_cookies.begin();
mkwstbe84af312015-02-20 08:52:451524 it != equivalent_cookies.end(); ++it) {
[email protected]f48b9432011-01-11 07:25:401525 const CookieSignature& signature = it->first;
1526 CookieSet& dupes = it->second;
1527
1528 if (dupes.size() <= 1)
1529 continue; // This cookiename/path has no duplicates.
1530 num_duplicates_found += dupes.size() - 1;
1531
1532 // Since |dups| is sorted by creation time (descending), the first cookie
1533 // is the most recent one, so we will keep it. The rest are duplicates.
1534 dupes.erase(dupes.begin());
1535
1536 LOG(ERROR) << base::StringPrintf(
1537 "Found %d duplicate cookies for host='%s', "
1538 "with {name='%s', domain='%s', path='%s'}",
mkwstbe84af312015-02-20 08:52:451539 static_cast<int>(dupes.size()), key.c_str(), signature.name.c_str(),
1540 signature.domain.c_str(), signature.path.c_str());
[email protected]f48b9432011-01-11 07:25:401541
1542 // Remove all the cookies identified by |dupes|. It is valid to delete our
1543 // list of iterators one at a time, since |cookies_| is a multimap (they
1544 // don't invalidate existing iterators following deletion).
mkwstbe84af312015-02-20 08:52:451545 for (CookieSet::iterator dupes_it = dupes.begin(); dupes_it != dupes.end();
[email protected]f48b9432011-01-11 07:25:401546 ++dupes_it) {
[email protected]218aa6a12011-09-13 17:38:381547 InternalDeleteCookie(*dupes_it, true,
[email protected]f48b9432011-01-11 07:25:401548 DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE);
1549 }
1550 }
1551 DCHECK_EQ(num_duplicates, num_duplicates_found);
[email protected]f48b9432011-01-11 07:25:401552}
1553
[email protected]f48b9432011-01-11 07:25:401554void CookieMonster::FindCookiesForHostAndDomain(
1555 const GURL& url,
1556 const CookieOptions& options,
[email protected]f48b9432011-01-11 07:25:401557 std::vector<CanonicalCookie*>* cookies) {
mmenkebe0910d2016-03-01 19:09:091558 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401559
1560 const Time current_time(CurrentTime());
1561
1562 // Probe to save statistics relatively frequently. We do it here rather
1563 // than in the set path as many websites won't set cookies, and we
1564 // want to collect statistics whenever the browser's being used.
1565 RecordPeriodicStats(current_time);
1566
[email protected]8e1583672012-02-11 04:39:411567 // Can just dispatch to FindCookiesForKey
1568 const std::string key(GetKey(url.host()));
mkwst72b65162016-02-22 19:58:541569 FindCookiesForKey(key, url, options, current_time, cookies);
[email protected]f48b9432011-01-11 07:25:401570}
1571
[email protected]dedec0b2013-02-28 04:50:101572void CookieMonster::FindCookiesForKey(const std::string& key,
1573 const GURL& url,
1574 const CookieOptions& options,
1575 const Time& current,
[email protected]dedec0b2013-02-28 04:50:101576 std::vector<CanonicalCookie*>* cookies) {
mmenkebe0910d2016-03-01 19:09:091577 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401578
[email protected]f48b9432011-01-11 07:25:401579 for (CookieMapItPair its = cookies_.equal_range(key);
mkwstbe84af312015-02-20 08:52:451580 its.first != its.second;) {
[email protected]f48b9432011-01-11 07:25:401581 CookieMap::iterator curit = its.first;
avie7cd11a2016-10-11 02:00:351582 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:401583 ++its.first;
1584
1585 // If the cookie is expired, delete it.
mmenke3c79a652016-02-12 14:39:201586 if (cc->IsExpired(current)) {
[email protected]f48b9432011-01-11 07:25:401587 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
1588 continue;
1589 }
1590
[email protected]65f4e7e2012-12-12 21:56:541591 // Filter out cookies that should not be included for a request to the
1592 // given |url|. HTTP only cookies are filtered depending on the passed
1593 // cookie |options|.
1594 if (!cc->IncludeForRequestURL(url, options))
[email protected]f48b9432011-01-11 07:25:401595 continue;
1596
[email protected]65f4e7e2012-12-12 21:56:541597 // Add this cookie to the set of matching cookies. Update the access
[email protected]f48b9432011-01-11 07:25:401598 // time if we've been requested to do so.
mkwst72b65162016-02-22 19:58:541599 if (options.update_access_time()) {
[email protected]f48b9432011-01-11 07:25:401600 InternalUpdateCookieAccessTime(cc, current);
1601 }
1602 cookies->push_back(cc);
1603 }
1604}
1605
1606bool CookieMonster::DeleteAnyEquivalentCookie(const std::string& key,
1607 const CanonicalCookie& ecc,
mmenke009cf62e2016-07-18 19:33:311608 const GURL& source_url,
[email protected]e7c590e52011-03-30 08:33:551609 bool skip_httponly,
jwwa26e439d2017-01-27 18:17:271610 bool already_expired) {
mmenkebe0910d2016-03-01 19:09:091611 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:401612
1613 bool found_equivalent_cookie = false;
1614 bool skipped_httponly = false;
jww601411a2015-11-20 19:46:571615 bool skipped_secure_cookie = false;
jww31e32632015-12-16 23:38:341616
1617 histogram_cookie_delete_equivalent_->Add(COOKIE_DELETE_EQUIVALENT_ATTEMPT);
1618
[email protected]f48b9432011-01-11 07:25:401619 for (CookieMapItPair its = cookies_.equal_range(key);
mkwstbe84af312015-02-20 08:52:451620 its.first != its.second;) {
[email protected]f48b9432011-01-11 07:25:401621 CookieMap::iterator curit = its.first;
avie7cd11a2016-10-11 02:00:351622 CanonicalCookie* cc = curit->second.get();
[email protected]f48b9432011-01-11 07:25:401623 ++its.first;
1624
jwwa26e439d2017-01-27 18:17:271625 // If the cookie is being set from an insecure scheme, then if a cookie
1626 // already exists with the same name and it is Secure, then the cookie
1627 // should *not* be updated if they domain-match and ignoring the path
1628 // attribute.
jww601411a2015-11-20 19:46:571629 //
jwwa26e439d2017-01-27 18:17:271630 // See: https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone
1631 if (cc->IsSecure() && !source_url.SchemeIsCryptographic() &&
mmenke2830b0722016-07-20 16:02:501632 ecc.IsEquivalentForSecureCookieMatching(*cc)) {
jww601411a2015-11-20 19:46:571633 skipped_secure_cookie = true;
jww31e32632015-12-16 23:38:341634 histogram_cookie_delete_equivalent_->Add(
1635 COOKIE_DELETE_EQUIVALENT_SKIPPING_SECURE);
1636 // If the cookie is equivalent to the new cookie and wouldn't have been
1637 // skipped for being HTTP-only, record that it is a skipped secure cookie
1638 // that would have been deleted otherwise.
1639 if (ecc.IsEquivalent(*cc)) {
jwwa9a0d482015-12-16 18:19:411640 found_equivalent_cookie = true;
jww31e32632015-12-16 23:38:341641
1642 if (!skip_httponly || !cc->IsHttpOnly()) {
1643 histogram_cookie_delete_equivalent_->Add(
1644 COOKIE_DELETE_EQUIVALENT_WOULD_HAVE_DELETED);
1645 }
1646 }
jww601411a2015-11-20 19:46:571647 } else if (ecc.IsEquivalent(*cc)) {
[email protected]f48b9432011-01-11 07:25:401648 // We should never have more than one equivalent cookie, since they should
jww601411a2015-11-20 19:46:571649 // overwrite each other, unless secure cookies require secure scheme is
1650 // being enforced. In that case, cookies with different paths might exist
1651 // and be considered equivalent.
mkwstbe84af312015-02-20 08:52:451652 CHECK(!found_equivalent_cookie)
1653 << "Duplicate equivalent cookies found, cookie store is corrupted.";
[email protected]f48b9432011-01-11 07:25:401654 if (skip_httponly && cc->IsHttpOnly()) {
1655 skipped_httponly = true;
1656 } else {
jww31e32632015-12-16 23:38:341657 histogram_cookie_delete_equivalent_->Add(
1658 COOKIE_DELETE_EQUIVALENT_FOUND);
mkwstbe84af312015-02-20 08:52:451659 InternalDeleteCookie(curit, true, already_expired
1660 ? DELETE_COOKIE_EXPIRED_OVERWRITE
1661 : DELETE_COOKIE_OVERWRITE);
[email protected]f48b9432011-01-11 07:25:401662 }
1663 found_equivalent_cookie = true;
1664 }
1665 }
jww601411a2015-11-20 19:46:571666 return skipped_httponly || skipped_secure_cookie;
[email protected]f48b9432011-01-11 07:25:401667}
1668
[email protected]6210ce52013-09-20 03:33:141669CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie(
1670 const std::string& key,
avie7cd11a2016-10-11 02:00:351671 std::unique_ptr<CanonicalCookie> cc,
mmenke009cf62e2016-07-18 19:33:311672 const GURL& source_url,
[email protected]6210ce52013-09-20 03:33:141673 bool sync_to_store) {
mmenkebe0910d2016-03-01 19:09:091674 DCHECK(thread_checker_.CalledOnValidThread());
avie7cd11a2016-10-11 02:00:351675 CanonicalCookie* cc_ptr = cc.get();
mmenkebe0910d2016-03-01 19:09:091676
avie7cd11a2016-10-11 02:00:351677 if ((cc_ptr->IsPersistent() || persist_session_cookies_) && store_.get() &&
[email protected]90499482013-06-01 00:39:501678 sync_to_store)
avie7cd11a2016-10-11 02:00:351679 store_->AddCookie(*cc_ptr);
[email protected]6210ce52013-09-20 03:33:141680 CookieMap::iterator inserted =
avie7cd11a2016-10-11 02:00:351681 cookies_.insert(CookieMap::value_type(key, std::move(cc)));
1682 if (delegate_.get()) {
1683 delegate_->OnCookieChanged(*cc_ptr, false,
1684 CookieStore::ChangeCause::INSERTED);
1685 }
mkwstc1aa4cc2015-04-03 19:57:451686
1687 // See InitializeHistograms() for details.
avie7cd11a2016-10-11 02:00:351688 int32_t type_sample = cc_ptr->SameSite() != CookieSameSite::NO_RESTRICTION
mkwste1a29582016-03-15 10:07:521689 ? 1 << COOKIE_TYPE_SAME_SITE
1690 : 0;
avie7cd11a2016-10-11 02:00:351691 type_sample |= cc_ptr->IsHttpOnly() ? 1 << COOKIE_TYPE_HTTPONLY : 0;
1692 type_sample |= cc_ptr->IsSecure() ? 1 << COOKIE_TYPE_SECURE : 0;
mkwst46549412016-02-01 10:05:371693 histogram_cookie_type_->Add(type_sample);
estark7feb65c2b2015-08-21 23:38:201694
1695 // Histogram the type of scheme used on URLs that set cookies. This
1696 // intentionally includes cookies that are set or overwritten by
1697 // http:// URLs, but not cookies that are cleared by http:// URLs, to
1698 // understand if the former behavior can be deprecated for Secure
1699 // cookies.
mmenke009cf62e2016-07-18 19:33:311700 if (!source_url.is_empty()) {
estark7feb65c2b2015-08-21 23:38:201701 CookieSource cookie_source_sample;
mmenke009cf62e2016-07-18 19:33:311702 if (source_url.SchemeIsCryptographic()) {
estark7feb65c2b2015-08-21 23:38:201703 cookie_source_sample =
avie7cd11a2016-10-11 02:00:351704 cc_ptr->IsSecure()
1705 ? COOKIE_SOURCE_SECURE_COOKIE_CRYPTOGRAPHIC_SCHEME
1706 : COOKIE_SOURCE_NONSECURE_COOKIE_CRYPTOGRAPHIC_SCHEME;
estark7feb65c2b2015-08-21 23:38:201707 } else {
1708 cookie_source_sample =
avie7cd11a2016-10-11 02:00:351709 cc_ptr->IsSecure()
estark7feb65c2b2015-08-21 23:38:201710 ? COOKIE_SOURCE_SECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME
1711 : COOKIE_SOURCE_NONSECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME;
1712 }
1713 histogram_cookie_source_scheme_->Add(cookie_source_sample);
1714 }
mkwstc1aa4cc2015-04-03 19:57:451715
avie7cd11a2016-10-11 02:00:351716 RunCookieChangedCallbacks(*cc_ptr, CookieStore::ChangeCause::INSERTED);
[email protected]6210ce52013-09-20 03:33:141717
1718 return inserted;
[email protected]f48b9432011-01-11 07:25:401719}
1720
[email protected]34602282010-02-03 22:14:151721bool CookieMonster::SetCookieWithCreationTimeAndOptions(
1722 const GURL& url,
1723 const std::string& cookie_line,
1724 const Time& creation_time_or_null,
1725 const CookieOptions& options) {
mmenkebe0910d2016-03-01 19:09:091726 DCHECK(thread_checker_.CalledOnValidThread());
initial.commit586acc5fe2008-07-26 22:42:521727
[email protected]4d3ce782010-10-29 18:31:281728 VLOG(kVlogSetCookies) << "SetCookie() line: " << cookie_line;
initial.commit586acc5fe2008-07-26 22:42:521729
[email protected]34602282010-02-03 22:14:151730 Time creation_time = creation_time_or_null;
1731 if (creation_time.is_null()) {
1732 creation_time = CurrentTime();
1733 last_time_seen_ = creation_time;
1734 }
1735
danakja9850e12016-04-18 22:28:081736 std::unique_ptr<CanonicalCookie> cc(
[email protected]abbd13b2012-11-15 17:54:201737 CanonicalCookie::Create(url, cookie_line, creation_time, options));
initial.commit586acc5fe2008-07-26 22:42:521738
1739 if (!cc.get()) {
[email protected]4d3ce782010-10-29 18:31:281740 VLOG(kVlogSetCookies) << "WARNING: Failed to allocate CanonicalCookie";
initial.commit586acc5fe2008-07-26 22:42:521741 return false;
1742 }
mmenke009cf62e2016-07-18 19:33:311743 return SetCanonicalCookie(std::move(cc), url, options);
[email protected]f325f1e12010-04-30 22:38:551744}
initial.commit586acc5fe2008-07-26 22:42:521745
danakja9850e12016-04-18 22:28:081746bool CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc,
mmenke009cf62e2016-07-18 19:33:311747 const GURL& source_url,
[email protected]f325f1e12010-04-30 22:38:551748 const CookieOptions& options) {
mmenkebe0910d2016-03-01 19:09:091749 DCHECK(thread_checker_.CalledOnValidThread());
1750
mmenkeea4cd402016-02-02 04:03:101751 Time creation_time = cc->CreationDate();
1752 const std::string key(GetKey(cc->Domain()));
1753 bool already_expired = cc->IsExpired(creation_time);
ellyjones399e35a22014-10-27 11:09:561754
mmenke009cf62e2016-07-18 19:33:311755 if (DeleteAnyEquivalentCookie(key, *cc, source_url,
jwwa26e439d2017-01-27 18:17:271756 options.exclude_httponly(), already_expired)) {
jww601411a2015-11-20 19:46:571757 std::string error;
jwwa26e439d2017-01-27 18:17:271758 error =
1759 "SetCookie() not clobbering httponly cookie or secure cookie for "
1760 "insecure scheme";
jww601411a2015-11-20 19:46:571761
1762 VLOG(kVlogSetCookies) << error;
[email protected]3a96c742008-11-19 19:46:271763 return false;
1764 }
initial.commit586acc5fe2008-07-26 22:42:521765
mkwstbe84af312015-02-20 08:52:451766 VLOG(kVlogSetCookies) << "SetCookie() key: " << key
mmenkeea4cd402016-02-02 04:03:101767 << " cc: " << cc->DebugString();
initial.commit586acc5fe2008-07-26 22:42:521768
1769 // Realize that we might be setting an expired cookie, and the only point
1770 // was to delete the cookie which we've already done.
mmenke3c79a652016-02-12 14:39:201771 if (!already_expired) {
[email protected]374f58b2010-07-20 15:29:261772 // See InitializeHistograms() for details.
mmenkeea4cd402016-02-02 04:03:101773 if (cc->IsPersistent()) {
[email protected]8475bee2011-03-17 18:40:241774 histogram_expiration_duration_minutes_->Add(
mmenkeea4cd402016-02-02 04:03:101775 (cc->ExpiryDate() - creation_time).InMinutes());
[email protected]8475bee2011-03-17 18:40:241776 }
1777
avie7cd11a2016-10-11 02:00:351778 InternalInsertCookie(key, std::move(cc), source_url, true);
[email protected]348dd662013-03-13 20:25:071779 } else {
1780 VLOG(kVlogSetCookies) << "SetCookie() not storing already expired cookie.";
[email protected]c4058fb2010-06-22 17:25:261781 }
initial.commit586acc5fe2008-07-26 22:42:521782
1783 // We assume that hopefully setting a cookie will be less common than
1784 // querying a cookie. Since setting a cookie can put us over our limits,
1785 // make sure that we garbage collect... We can also make the assumption that
1786 // if a cookie was set, in the common case it will be used soon after,
1787 // and we will purge the expired cookies in GetCookies().
jwwa26e439d2017-01-27 18:17:271788 GarbageCollect(creation_time, key);
initial.commit586acc5fe2008-07-26 22:42:521789
1790 return true;
1791}
1792
drogerd5d1278c2015-03-17 19:21:511793bool CookieMonster::SetCanonicalCookies(const CookieList& list) {
mmenkebe0910d2016-03-01 19:09:091794 DCHECK(thread_checker_.CalledOnValidThread());
drogerd5d1278c2015-03-17 19:21:511795
ttuttle859dc7a2015-04-23 19:42:291796 CookieOptions options;
drogerd5d1278c2015-03-17 19:21:511797 options.set_include_httponly();
1798
mmenkeea4cd402016-02-02 04:03:101799 for (const auto& cookie : list) {
mmenke009cf62e2016-07-18 19:33:311800 // Use an empty GURL. This method does not support setting secure cookies.
ricea2deef682016-09-09 08:04:071801 if (!SetCanonicalCookie(base::MakeUnique<CanonicalCookie>(cookie), GURL(),
1802 options)) {
drogerd5d1278c2015-03-17 19:21:511803 return false;
mmenkeea4cd402016-02-02 04:03:101804 }
drogerd5d1278c2015-03-17 19:21:511805 }
1806
1807 return true;
1808}
1809
[email protected]7a964a72010-09-07 19:33:261810void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc,
1811 const Time& current) {
mmenkebe0910d2016-03-01 19:09:091812 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041813
[email protected]77e0a462008-11-01 00:43:351814 // Based off the Mozilla code. When a cookie has been accessed recently,
1815 // don't bother updating its access time again. This reduces the number of
1816 // updates we do during pageload, which in turn reduces the chance our storage
1817 // backend will hit its batch thresholds and be forced to update.
[email protected]77e0a462008-11-01 00:43:351818 if ((current - cc->LastAccessDate()) < last_access_threshold_)
1819 return;
1820
1821 cc->SetLastAccessDate(current);
[email protected]90499482013-06-01 00:39:501822 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get())
[email protected]77e0a462008-11-01 00:43:351823 store_->UpdateCookieAccessTime(*cc);
1824}
1825
[email protected]6210ce52013-09-20 03:33:141826// InternalDeleteCookies must not invalidate iterators other than the one being
1827// deleted.
initial.commit586acc5fe2008-07-26 22:42:521828void CookieMonster::InternalDeleteCookie(CookieMap::iterator it,
[email protected]c4058fb2010-06-22 17:25:261829 bool sync_to_store,
1830 DeletionCause deletion_cause) {
mmenkebe0910d2016-03-01 19:09:091831 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041832
nharper352933e2016-09-30 18:24:571833 // Ideally, this would be asserted up where we define kChangeCauseMapping,
[email protected]8bb846f2011-03-23 12:08:181834 // but DeletionCause's visibility (or lack thereof) forces us to make
1835 // this check here.
nharper352933e2016-09-30 18:24:571836 static_assert(arraysize(kChangeCauseMapping) == DELETE_COOKIE_LAST_ENTRY + 1,
1837 "kChangeCauseMapping size should match DeletionCause size");
[email protected]8bb846f2011-03-23 12:08:181838
[email protected]374f58b2010-07-20 15:29:261839 // See InitializeHistograms() for details.
nharper68903362017-01-20 04:07:141840 DeletionCause deletion_cause_to_record = deletion_cause;
1841 if (deletion_cause >= DELETE_COOKIE_CREATED_BETWEEN &&
1842 deletion_cause <= DELETE_COOKIE_CANONICAL) {
1843 deletion_cause_to_record = DELETE_COOKIE_EXPLICIT;
1844 }
[email protected]7a964a72010-09-07 19:33:261845 if (deletion_cause != DELETE_COOKIE_DONT_RECORD)
nharper68903362017-01-20 04:07:141846 histogram_cookie_deletion_cause_->Add(deletion_cause_to_record);
[email protected]c4058fb2010-06-22 17:25:261847
avie7cd11a2016-10-11 02:00:351848 CanonicalCookie* cc = it->second.get();
xiyuan8dbb89892015-04-13 17:04:301849 VLOG(kVlogSetCookies) << "InternalDeleteCookie()"
1850 << ", cause:" << deletion_cause
1851 << ", cc: " << cc->DebugString();
[email protected]7a964a72010-09-07 19:33:261852
[email protected]90499482013-06-01 00:39:501853 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get() &&
1854 sync_to_store)
initial.commit586acc5fe2008-07-26 22:42:521855 store_->DeleteCookie(*cc);
nharper352933e2016-09-30 18:24:571856 ChangeCausePair mapping = kChangeCauseMapping[deletion_cause];
1857 if (delegate_.get() && mapping.notify)
1858 delegate_->OnCookieChanged(*cc, true, mapping.cause);
1859 RunCookieChangedCallbacks(*cc, mapping.cause);
initial.commit586acc5fe2008-07-26 22:42:521860 cookies_.erase(it);
initial.commit586acc5fe2008-07-26 22:42:521861}
1862
[email protected]8807b322010-10-01 17:10:141863// Domain expiry behavior is unchanged by key/expiry scheme (the
[email protected]8ad5d462013-05-02 08:45:261864// meaning of the key is different, but that's not visible to this routine).
jww82d99c12015-11-25 18:39:531865size_t CookieMonster::GarbageCollect(const Time& current,
jwwa26e439d2017-01-27 18:17:271866 const std::string& key) {
mmenkebe0910d2016-03-01 19:09:091867 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:041868
jww82d99c12015-11-25 18:39:531869 size_t num_deleted = 0;
mkwstbe84af312015-02-20 08:52:451870 Time safe_date(Time::Now() - TimeDelta::FromDays(kSafeFromGlobalPurgeDays));
initial.commit586acc5fe2008-07-26 22:42:521871
[email protected]8ad5d462013-05-02 08:45:261872 // Collect garbage for this key, minding cookie priorities.
[email protected]7a964a72010-09-07 19:33:261873 if (cookies_.count(key) > kDomainMaxCookies) {
[email protected]4d3ce782010-10-29 18:31:281874 VLOG(kVlogGarbageCollection) << "GarbageCollect() key: " << key;
[email protected]7a964a72010-09-07 19:33:261875
mkwst87734352016-03-03 17:36:231876 CookieItVector* cookie_its;
jww601411a2015-11-20 19:46:571877
mkwst87734352016-03-03 17:36:231878 CookieItVector non_expired_cookie_its;
1879 cookie_its = &non_expired_cookie_its;
jww82d99c12015-11-25 18:39:531880 num_deleted +=
mkwst87734352016-03-03 17:36:231881 GarbageCollectExpired(current, cookies_.equal_range(key), cookie_its);
jww82d99c12015-11-25 18:39:531882
mkwst87734352016-03-03 17:36:231883 if (cookie_its->size() > kDomainMaxCookies) {
[email protected]8ad5d462013-05-02 08:45:261884 VLOG(kVlogGarbageCollection) << "Deep Garbage Collect domain.";
1885 size_t purge_goal =
mkwst87734352016-03-03 17:36:231886 cookie_its->size() - (kDomainMaxCookies - kDomainPurgeCookies);
[email protected]8ad5d462013-05-02 08:45:261887 DCHECK(purge_goal > kDomainPurgeCookies);
1888
mkwste079ac412016-03-11 09:04:061889 // Sort the cookies by access date, from least-recent to most-recent.
1890 std::sort(cookie_its->begin(), cookie_its->end(), LRACookieSorter);
[email protected]8ad5d462013-05-02 08:45:261891
mkwste079ac412016-03-11 09:04:061892 // Remove all but the kDomainCookiesQuotaLow most-recently accessed
1893 // cookies with low-priority. Then, if cookies still need to be removed,
1894 // bump the quota and remove low- and medium-priority. Then, if cookies
1895 // _still_ need to be removed, bump the quota and remove cookies with
1896 // any priority.
jwwc00ac712016-05-05 22:21:441897 //
1898 // 1. Low-priority non-secure cookies.
1899 // 2. Low-priority secure cookies.
1900 // 3. Medium-priority non-secure cookies.
1901 // 4. High-priority non-secure cookies.
1902 // 5. Medium-priority secure cookies.
1903 // 6. High-priority secure cookies.
1904 const static struct {
1905 CookiePriority priority;
1906 bool protect_secure_cookies;
1907 } purge_rounds[] = {
1908 // 1. Low-priority non-secure cookies.
1909 {COOKIE_PRIORITY_LOW, true},
1910 // 2. Low-priority secure cookies.
1911 {COOKIE_PRIORITY_LOW, false},
1912 // 3. Medium-priority non-secure cookies.
1913 {COOKIE_PRIORITY_MEDIUM, true},
1914 // 4. High-priority non-secure cookies.
1915 {COOKIE_PRIORITY_HIGH, true},
1916 // 5. Medium-priority secure cookies.
1917 {COOKIE_PRIORITY_MEDIUM, false},
1918 // 6. High-priority secure cookies.
1919 {COOKIE_PRIORITY_HIGH, false},
1920 };
1921
mkwste079ac412016-03-11 09:04:061922 size_t quota = 0;
jwwc00ac712016-05-05 22:21:441923 for (const auto& purge_round : purge_rounds) {
mmenke645ca6772016-06-17 18:46:431924 // Adjust quota according to the priority of cookies. Each round should
1925 // protect certain number of cookies in order to avoid starvation.
1926 // For example, when each round starts to remove cookies, the number of
1927 // cookies of that priority are counted and a decision whether they
1928 // should be deleted or not is made. If yes, some number of cookies of
1929 // that priority are deleted considering the quota.
jwwc00ac712016-05-05 22:21:441930 switch (purge_round.priority) {
1931 case COOKIE_PRIORITY_LOW:
mmenke645ca6772016-06-17 18:46:431932 quota = kDomainCookiesQuotaLow;
jwwc00ac712016-05-05 22:21:441933 break;
1934 case COOKIE_PRIORITY_MEDIUM:
mmenke645ca6772016-06-17 18:46:431935 quota = kDomainCookiesQuotaMedium;
jwwc00ac712016-05-05 22:21:441936 break;
1937 case COOKIE_PRIORITY_HIGH:
mmenke645ca6772016-06-17 18:46:431938 quota = kDomainCookiesQuotaHigh;
jwwc00ac712016-05-05 22:21:441939 break;
1940 }
jwwc00ac712016-05-05 22:21:441941 size_t just_deleted = 0u;
jwwa26e439d2017-01-27 18:17:271942 // Purge up to |purge_goal| for all cookies at the given priority. This
1943 // path will be taken only if the initial non-secure purge did not evict
1944 // enough cookies.
jwwc00ac712016-05-05 22:21:441945 if (purge_goal > 0) {
1946 just_deleted = PurgeLeastRecentMatches(
1947 cookie_its, purge_round.priority, quota, purge_goal,
1948 purge_round.protect_secure_cookies);
1949 DCHECK_LE(just_deleted, purge_goal);
1950 purge_goal -= just_deleted;
1951 num_deleted += just_deleted;
1952 }
mkwst162d2712016-02-18 18:21:291953 }
mkwste079ac412016-03-11 09:04:061954
jwwc00ac712016-05-05 22:21:441955 DCHECK_EQ(0u, purge_goal);
[email protected]8807b322010-10-01 17:10:141956 }
initial.commit586acc5fe2008-07-26 22:42:521957 }
1958
[email protected]8ad5d462013-05-02 08:45:261959 // Collect garbage for everything. With firefox style we want to preserve
1960 // cookies accessed in kSafeFromGlobalPurgeDays, otherwise evict.
mkwstbe84af312015-02-20 08:52:451961 if (cookies_.size() > kMaxCookies && earliest_access_time_ < safe_date) {
[email protected]4d3ce782010-10-29 18:31:281962 VLOG(kVlogGarbageCollection) << "GarbageCollect() everything";
[email protected]8ad5d462013-05-02 08:45:261963 CookieItVector cookie_its;
jww82d99c12015-11-25 18:39:531964
[email protected]7a964a72010-09-07 19:33:261965 num_deleted += GarbageCollectExpired(
1966 current, CookieMapItPair(cookies_.begin(), cookies_.end()),
1967 &cookie_its);
jww82d99c12015-11-25 18:39:531968
[email protected]8ad5d462013-05-02 08:45:261969 if (cookie_its.size() > kMaxCookies) {
1970 VLOG(kVlogGarbageCollection) << "Deep Garbage Collect everything.";
1971 size_t purge_goal = cookie_its.size() - (kMaxCookies - kPurgeCookies);
1972 DCHECK(purge_goal > kPurgeCookies);
jww82d99c12015-11-25 18:39:531973
jwwa26e439d2017-01-27 18:17:271974 CookieItVector secure_cookie_its;
1975 CookieItVector non_secure_cookie_its;
1976 SplitCookieVectorIntoSecureAndNonSecure(cookie_its, &secure_cookie_its,
1977 &non_secure_cookie_its);
1978 size_t non_secure_purge_goal =
1979 std::min<size_t>(purge_goal, non_secure_cookie_its.size() - 1);
jww82d99c12015-11-25 18:39:531980
jwwa26e439d2017-01-27 18:17:271981 size_t just_deleted = GarbageCollectLeastRecentlyAccessed(
1982 current, safe_date, non_secure_purge_goal, non_secure_cookie_its);
1983 num_deleted += just_deleted;
jww82d99c12015-11-25 18:39:531984
jwwa26e439d2017-01-27 18:17:271985 if (just_deleted < purge_goal && secure_cookie_its.size() > 0) {
1986 size_t secure_purge_goal = std::min<size_t>(
1987 purge_goal - just_deleted, secure_cookie_its.size() - 1);
jww82d99c12015-11-25 18:39:531988 num_deleted += GarbageCollectLeastRecentlyAccessed(
jwwa26e439d2017-01-27 18:17:271989 current, safe_date, secure_purge_goal, secure_cookie_its);
jww82d99c12015-11-25 18:39:531990 }
[email protected]8807b322010-10-01 17:10:141991 }
[email protected]c890ed192008-10-30 23:45:531992 }
1993
1994 return num_deleted;
1995}
1996
mkwste079ac412016-03-11 09:04:061997size_t CookieMonster::PurgeLeastRecentMatches(CookieItVector* cookies,
1998 CookiePriority priority,
1999 size_t to_protect,
jwwc00ac712016-05-05 22:21:442000 size_t purge_goal,
2001 bool protect_secure_cookies) {
mkwste079ac412016-03-11 09:04:062002 DCHECK(thread_checker_.CalledOnValidThread());
2003
mmenke645ca6772016-06-17 18:46:432004 // 1. Count number of the cookies at |priority|
2005 size_t cookies_count_possibly_to_be_deleted = CountCookiesForPossibleDeletion(
2006 priority, cookies, false /* count all cookies */);
2007
2008 // 2. If |cookies_count_possibly_to_be_deleted| at |priority| is less than or
2009 // equal |to_protect|, skip round in order to preserve the quota. This
2010 // involves secure and non-secure cookies at |priority|.
2011 if (cookies_count_possibly_to_be_deleted <= to_protect)
2012 return 0u;
2013
2014 // 3. Calculate number of secure cookies at |priority|
2015 // and number of cookies at |priority| that can possibly be deleted.
2016 // It is guaranteed we do not delete more than |purge_goal| even if
2017 // |cookies_count_possibly_to_be_deleted| is higher.
2018 size_t secure_cookies = 0u;
jwwc00ac712016-05-05 22:21:442019 if (protect_secure_cookies) {
mmenke645ca6772016-06-17 18:46:432020 secure_cookies = CountCookiesForPossibleDeletion(
2021 priority, cookies, protect_secure_cookies /* count secure cookies */);
2022 cookies_count_possibly_to_be_deleted -=
2023 std::max(secure_cookies, to_protect - secure_cookies);
2024 } else {
2025 cookies_count_possibly_to_be_deleted -= to_protect;
jwwc00ac712016-05-05 22:21:442026 }
2027
mmenke645ca6772016-06-17 18:46:432028 size_t removed = 0u;
2029 size_t current = 0u;
2030 while ((removed < purge_goal && current < cookies->size()) &&
2031 cookies_count_possibly_to_be_deleted > 0) {
avie7cd11a2016-10-11 02:00:352032 const CanonicalCookie* current_cookie = cookies->at(current)->second.get();
mmenke645ca6772016-06-17 18:46:432033 // Only delete the current cookie if the priority is equal to
2034 // the current level.
jwwc00ac712016-05-05 22:21:442035 if (IsCookieEligibleForEviction(priority, protect_secure_cookies,
2036 current_cookie)) {
mkwstaa07ee82016-03-11 15:32:142037 InternalDeleteCookie(cookies->at(current), true,
2038 DELETE_COOKIE_EVICTED_DOMAIN);
mkwste079ac412016-03-11 09:04:062039 cookies->erase(cookies->begin() + current);
2040 removed++;
mmenke645ca6772016-06-17 18:46:432041 cookies_count_possibly_to_be_deleted--;
mkwste079ac412016-03-11 09:04:062042 } else {
2043 current++;
2044 }
2045 }
2046 return removed;
2047}
2048
jww82d99c12015-11-25 18:39:532049size_t CookieMonster::GarbageCollectExpired(const Time& current,
2050 const CookieMapItPair& itpair,
2051 CookieItVector* cookie_its) {
mmenkebe0910d2016-03-01 19:09:092052 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]bb8905722010-05-21 17:29:042053
[email protected]c890ed192008-10-30 23:45:532054 int num_deleted = 0;
2055 for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) {
2056 CookieMap::iterator curit = it;
2057 ++it;
2058
2059 if (curit->second->IsExpired(current)) {
[email protected]2f3f3592010-07-07 20:11:512060 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
[email protected]c890ed192008-10-30 23:45:532061 ++num_deleted;
2062 } else if (cookie_its) {
2063 cookie_its->push_back(curit);
2064 }
initial.commit586acc5fe2008-07-26 22:42:522065 }
2066
2067 return num_deleted;
2068}
2069
jww82d99c12015-11-25 18:39:532070size_t CookieMonster::GarbageCollectDeleteRange(
2071 const Time& current,
2072 DeletionCause cause,
2073 CookieItVector::iterator it_begin,
2074 CookieItVector::iterator it_end) {
mmenkebe0910d2016-03-01 19:09:092075 DCHECK(thread_checker_.CalledOnValidThread());
2076
[email protected]8ad5d462013-05-02 08:45:262077 for (CookieItVector::iterator it = it_begin; it != it_end; it++) {
2078 histogram_evicted_last_access_minutes_->Add(
2079 (current - (*it)->second->LastAccessDate()).InMinutes());
2080 InternalDeleteCookie((*it), true, cause);
[email protected]c10da4b02010-03-25 14:38:322081 }
[email protected]8ad5d462013-05-02 08:45:262082 return it_end - it_begin;
[email protected]c10da4b02010-03-25 14:38:322083}
2084
mmenke74bcbd52016-01-21 17:17:562085size_t CookieMonster::GarbageCollectLeastRecentlyAccessed(
2086 const base::Time& current,
2087 const base::Time& safe_date,
2088 size_t purge_goal,
2089 CookieItVector cookie_its) {
mmenkebe0910d2016-03-01 19:09:092090 DCHECK(thread_checker_.CalledOnValidThread());
2091
mmenke74bcbd52016-01-21 17:17:562092 // Sorts up to *and including* |cookie_its[purge_goal]|, so
2093 // |earliest_access_time| will be properly assigned even if
2094 // |global_purge_it| == |cookie_its.begin() + purge_goal|.
2095 SortLeastRecentlyAccessed(cookie_its.begin(), cookie_its.end(), purge_goal);
2096 // Find boundary to cookies older than safe_date.
2097 CookieItVector::iterator global_purge_it = LowerBoundAccessDate(
2098 cookie_its.begin(), cookie_its.begin() + purge_goal, safe_date);
jwwa26e439d2017-01-27 18:17:272099 // Only delete the old cookies and delete non-secure ones first.
mmenke74bcbd52016-01-21 17:17:562100 size_t num_deleted =
2101 GarbageCollectDeleteRange(current, DELETE_COOKIE_EVICTED_GLOBAL,
2102 cookie_its.begin(), global_purge_it);
2103 // Set access day to the oldest cookie that wasn't deleted.
2104 earliest_access_time_ = (*global_purge_it)->second->LastAccessDate();
2105 return num_deleted;
2106}
2107
[email protected]ed32c212013-05-14 20:49:292108// A wrapper around registry_controlled_domains::GetDomainAndRegistry
[email protected]f48b9432011-01-11 07:25:402109// to make clear we're creating a key for our local map. Here and
2110// in FindCookiesForHostAndDomain() are the only two places where
2111// we need to conditionalize based on key type.
2112//
2113// Note that this key algorithm explicitly ignores the scheme. This is
2114// because when we're entering cookies into the map from the backing store,
2115// we in general won't have the scheme at that point.
2116// In practical terms, this means that file cookies will be stored
2117// in the map either by an empty string or by UNC name (and will be
2118// limited by kMaxCookiesPerHost), and extension cookies will be stored
2119// based on the single extension id, as the extension id won't have the
2120// form of a DNS host and hence GetKey() will return it unchanged.
2121//
2122// Arguably the right thing to do here is to make the key
2123// algorithm dependent on the scheme, and make sure that the scheme is
2124// available everywhere the key must be obtained (specfically at backing
2125// store load time). This would require either changing the backing store
2126// database schema to include the scheme (far more trouble than it's worth), or
2127// separating out file cookies into their own CookieMonster instance and
2128// thus restricting each scheme to a single cookie monster (which might
2129// be worth it, but is still too much trouble to solve what is currently a
2130// non-problem).
2131std::string CookieMonster::GetKey(const std::string& domain) const {
mmenkebe0910d2016-03-01 19:09:092132 DCHECK(thread_checker_.CalledOnValidThread());
2133
[email protected]f48b9432011-01-11 07:25:402134 std::string effective_domain(
[email protected]ed32c212013-05-14 20:49:292135 registry_controlled_domains::GetDomainAndRegistry(
[email protected]aabe1792014-01-30 21:37:462136 domain, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES));
[email protected]f48b9432011-01-11 07:25:402137 if (effective_domain.empty())
2138 effective_domain = domain;
2139
2140 if (!effective_domain.empty() && effective_domain[0] == '.')
2141 return effective_domain.substr(1);
2142 return effective_domain;
2143}
2144
2145bool CookieMonster::HasCookieableScheme(const GURL& url) {
mmenkebe0910d2016-03-01 19:09:092146 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]f48b9432011-01-11 07:25:402147
2148 // Make sure the request is on a cookie-able url scheme.
2149 for (size_t i = 0; i < cookieable_schemes_.size(); ++i) {
2150 // We matched a scheme.
2151 if (url.SchemeIs(cookieable_schemes_[i].c_str())) {
2152 // We've matched a supported scheme.
initial.commit586acc5fe2008-07-26 22:42:522153 return true;
2154 }
2155 }
[email protected]f48b9432011-01-11 07:25:402156
2157 // The scheme didn't match any in our whitelist.
mkwstbe84af312015-02-20 08:52:452158 VLOG(kVlogPerCookieMonster)
2159 << "WARNING: Unsupported cookie scheme: " << url.scheme();
initial.commit586acc5fe2008-07-26 22:42:522160 return false;
2161}
2162
[email protected]c4058fb2010-06-22 17:25:262163// Test to see if stats should be recorded, and record them if so.
2164// The goal here is to get sampling for the average browser-hour of
2165// activity. We won't take samples when the web isn't being surfed,
2166// and when the web is being surfed, we'll take samples about every
2167// kRecordStatisticsIntervalSeconds.
2168// last_statistic_record_time_ is initialized to Now() rather than null
2169// in the constructor so that we won't take statistics right after
2170// startup, to avoid bias from browsers that are started but not used.
2171void CookieMonster::RecordPeriodicStats(const base::Time& current_time) {
mmenkebe0910d2016-03-01 19:09:092172 DCHECK(thread_checker_.CalledOnValidThread());
2173
[email protected]c4058fb2010-06-22 17:25:262174 const base::TimeDelta kRecordStatisticsIntervalTime(
2175 base::TimeDelta::FromSeconds(kRecordStatisticsIntervalSeconds));
2176
[email protected]7a964a72010-09-07 19:33:262177 // If we've taken statistics recently, return.
2178 if (current_time - last_statistic_record_time_ <=
[email protected]c4058fb2010-06-22 17:25:262179 kRecordStatisticsIntervalTime) {
[email protected]7a964a72010-09-07 19:33:262180 return;
[email protected]c4058fb2010-06-22 17:25:262181 }
[email protected]7a964a72010-09-07 19:33:262182
2183 // See InitializeHistograms() for details.
2184 histogram_count_->Add(cookies_.size());
2185
2186 // More detailed statistics on cookie counts at different granularities.
[email protected]7a964a72010-09-07 19:33:262187 last_statistic_record_time_ = current_time;
[email protected]c4058fb2010-06-22 17:25:262188}
2189
[email protected]f48b9432011-01-11 07:25:402190// Initialize all histogram counter variables used in this class.
2191//
2192// Normal histogram usage involves using the macros defined in
2193// histogram.h, which automatically takes care of declaring these
2194// variables (as statics), initializing them, and accumulating into
2195// them, all from a single entry point. Unfortunately, that solution
2196// doesn't work for the CookieMonster, as it's vulnerable to races between
2197// separate threads executing the same functions and hence initializing the
2198// same static variables. There isn't a race danger in the histogram
2199// accumulation calls; they are written to be resilient to simultaneous
2200// calls from multiple threads.
2201//
2202// The solution taken here is to have per-CookieMonster instance
2203// variables that are constructed during CookieMonster construction.
2204// Note that these variables refer to the same underlying histogram,
2205// so we still race (but safely) with other CookieMonster instances
2206// for accumulation.
2207//
2208// To do this we've expanded out the individual histogram macros calls,
2209// with declarations of the variables in the class decl, initialization here
2210// (done from the class constructor) and direct calls to the accumulation
2211// methods where needed. The specific histogram macro calls on which the
2212// initialization is based are included in comments below.
2213void CookieMonster::InitializeHistograms() {
mmenkebe0910d2016-03-01 19:09:092214 DCHECK(thread_checker_.CalledOnValidThread());
2215
[email protected]f48b9432011-01-11 07:25:402216 // From UMA_HISTOGRAM_CUSTOM_COUNTS
2217 histogram_expiration_duration_minutes_ = base::Histogram::FactoryGet(
mkwstbe84af312015-02-20 08:52:452218 "Cookie.ExpirationDurationMinutes", 1, kMinutesInTenYears, 50,
[email protected]f48b9432011-01-11 07:25:402219 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:402220 histogram_evicted_last_access_minutes_ = base::Histogram::FactoryGet(
mkwstbe84af312015-02-20 08:52:452221 "Cookie.EvictedLastAccessMinutes", 1, kMinutesInTenYears, 50,
[email protected]f48b9432011-01-11 07:25:402222 base::Histogram::kUmaTargetedHistogramFlag);
2223 histogram_count_ = base::Histogram::FactoryGet(
mkwstbe84af312015-02-20 08:52:452224 "Cookie.Count", 1, 4000, 50, base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:402225
2226 // From UMA_HISTOGRAM_ENUMERATION
2227 histogram_cookie_deletion_cause_ = base::LinearHistogram::FactoryGet(
mkwstbe84af312015-02-20 08:52:452228 "Cookie.DeletionCause", 1, DELETE_COOKIE_LAST_ENTRY - 1,
2229 DELETE_COOKIE_LAST_ENTRY, base::Histogram::kUmaTargetedHistogramFlag);
mkwstc1aa4cc2015-04-03 19:57:452230 histogram_cookie_type_ = base::LinearHistogram::FactoryGet(
mkwst87378d92015-04-10 21:22:112231 "Cookie.Type", 1, (1 << COOKIE_TYPE_LAST_ENTRY) - 1,
2232 1 << COOKIE_TYPE_LAST_ENTRY, base::Histogram::kUmaTargetedHistogramFlag);
estark7feb65c2b2015-08-21 23:38:202233 histogram_cookie_source_scheme_ = base::LinearHistogram::FactoryGet(
2234 "Cookie.CookieSourceScheme", 1, COOKIE_SOURCE_LAST_ENTRY - 1,
2235 COOKIE_SOURCE_LAST_ENTRY, base::Histogram::kUmaTargetedHistogramFlag);
jww31e32632015-12-16 23:38:342236 histogram_cookie_delete_equivalent_ = base::LinearHistogram::FactoryGet(
2237 "Cookie.CookieDeleteEquivalent", 1,
2238 COOKIE_DELETE_EQUIVALENT_LAST_ENTRY - 1,
2239 COOKIE_DELETE_EQUIVALENT_LAST_ENTRY,
2240 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:402241
2242 // From UMA_HISTOGRAM_{CUSTOM_,}TIMES
[email protected]c7593fb22011-11-14 23:54:272243 histogram_time_blocked_on_load_ = base::Histogram::FactoryTimeGet(
mkwstbe84af312015-02-20 08:52:452244 "Cookie.TimeBlockedOnLoad", base::TimeDelta::FromMilliseconds(1),
2245 base::TimeDelta::FromMinutes(1), 50,
2246 base::Histogram::kUmaTargetedHistogramFlag);
[email protected]f48b9432011-01-11 07:25:402247}
2248
[email protected]f48b9432011-01-11 07:25:402249// The system resolution is not high enough, so we can have multiple
2250// set cookies that result in the same system time. When this happens, we
2251// increment by one Time unit. Let's hope computers don't get too fast.
2252Time CookieMonster::CurrentTime() {
mkwstbe84af312015-02-20 08:52:452253 return std::max(Time::Now(), Time::FromInternalValue(
2254 last_time_seen_.ToInternalValue() + 1));
[email protected]f48b9432011-01-11 07:25:402255}
2256
mmenke74bcbd52016-01-21 17:17:562257void CookieMonster::DoCookieTask(
2258 const scoped_refptr<CookieMonsterTask>& task_item) {
mmenkebe0910d2016-03-01 19:09:092259 DCHECK(thread_checker_.CalledOnValidThread());
2260
2261 MarkCookieStoreAsInitialized();
2262 FetchAllCookiesIfNecessary();
mmenkef49fca0e2016-03-08 12:46:242263 seen_global_task_ = true;
mmenkebe0910d2016-03-01 19:09:092264
2265 if (!finished_fetching_all_cookies_ && store_.get()) {
mmenkef49fca0e2016-03-08 12:46:242266 tasks_pending_.push_back(task_item);
mmenkebe0910d2016-03-01 19:09:092267 return;
mmenke74bcbd52016-01-21 17:17:562268 }
2269
2270 task_item->Run();
2271}
2272
2273void CookieMonster::DoCookieTaskForURL(
2274 const scoped_refptr<CookieMonsterTask>& task_item,
2275 const GURL& url) {
mmenkebe0910d2016-03-01 19:09:092276 MarkCookieStoreAsInitialized();
2277 if (ShouldFetchAllCookiesWhenFetchingAnyCookie())
2278 FetchAllCookiesIfNecessary();
2279
2280 // If cookies for the requested domain key (eTLD+1) have been loaded from DB
2281 // then run the task, otherwise load from DB.
2282 if (!finished_fetching_all_cookies_ && store_.get()) {
mmenkef49fca0e2016-03-08 12:46:242283 // If a global task has been previously seen, queue the task as a global
2284 // task. Note that the CookieMonster may be in the middle of executing
2285 // the global queue, |tasks_pending_| may be empty, which is why another
2286 // bool is needed.
2287 if (seen_global_task_) {
2288 tasks_pending_.push_back(task_item);
2289 return;
2290 }
2291
mmenkebe0910d2016-03-01 19:09:092292 // Checks if the domain key has been loaded.
2293 std::string key(cookie_util::GetEffectiveDomain(url.scheme(), url.host()));
2294 if (keys_loaded_.find(key) == keys_loaded_.end()) {
2295 std::map<std::string,
2296 std::deque<scoped_refptr<CookieMonsterTask>>>::iterator it =
2297 tasks_pending_for_key_.find(key);
2298 if (it == tasks_pending_for_key_.end()) {
2299 store_->LoadCookiesForKey(
2300 key, base::Bind(&CookieMonster::OnKeyLoaded,
2301 weak_ptr_factory_.GetWeakPtr(), key));
2302 it = tasks_pending_for_key_
2303 .insert(std::make_pair(
2304 key, std::deque<scoped_refptr<CookieMonsterTask>>()))
2305 .first;
mmenke74bcbd52016-01-21 17:17:562306 }
mmenkebe0910d2016-03-01 19:09:092307 it->second.push_back(task_item);
2308 return;
mmenke74bcbd52016-01-21 17:17:562309 }
2310 }
mmenkebe0910d2016-03-01 19:09:092311
mmenke74bcbd52016-01-21 17:17:562312 task_item->Run();
2313}
2314
drogerd5d1278c2015-03-17 19:21:512315void CookieMonster::ComputeCookieDiff(CookieList* old_cookies,
2316 CookieList* new_cookies,
2317 CookieList* cookies_to_add,
2318 CookieList* cookies_to_delete) {
mmenkebe0910d2016-03-01 19:09:092319 DCHECK(thread_checker_.CalledOnValidThread());
2320
drogerd5d1278c2015-03-17 19:21:512321 DCHECK(old_cookies);
2322 DCHECK(new_cookies);
2323 DCHECK(cookies_to_add);
2324 DCHECK(cookies_to_delete);
2325 DCHECK(cookies_to_add->empty());
2326 DCHECK(cookies_to_delete->empty());
2327
2328 // Sort both lists.
2329 // A set ordered by FullDiffCookieSorter is also ordered by
2330 // PartialDiffCookieSorter.
2331 std::sort(old_cookies->begin(), old_cookies->end(), FullDiffCookieSorter);
2332 std::sort(new_cookies->begin(), new_cookies->end(), FullDiffCookieSorter);
2333
2334 // Select any old cookie for deletion if no new cookie has the same name,
2335 // domain, and path.
2336 std::set_difference(
2337 old_cookies->begin(), old_cookies->end(), new_cookies->begin(),
2338 new_cookies->end(),
2339 std::inserter(*cookies_to_delete, cookies_to_delete->begin()),
2340 PartialDiffCookieSorter);
2341
2342 // Select any new cookie for addition (or update) if no old cookie is exactly
2343 // equivalent.
2344 std::set_difference(new_cookies->begin(), new_cookies->end(),
2345 old_cookies->begin(), old_cookies->end(),
2346 std::inserter(*cookies_to_add, cookies_to_add->begin()),
2347 FullDiffCookieSorter);
2348}
2349
mmenkebe0910d2016-03-01 19:09:092350void CookieMonster::RunCallback(const base::Closure& callback) {
2351 DCHECK(thread_checker_.CalledOnValidThread());
2352 callback.Run();
2353}
2354
2355void CookieMonster::RunCookieChangedCallbacks(const CanonicalCookie& cookie,
nharper352933e2016-09-30 18:24:572356 ChangeCause cause) {
mmenkebe0910d2016-03-01 19:09:092357 DCHECK(thread_checker_.CalledOnValidThread());
2358
ellyjones399e35a22014-10-27 11:09:562359 CookieOptions opts;
2360 opts.set_include_httponly();
mkwstf71d0bd2016-03-21 14:15:242361 opts.set_same_site_cookie_mode(
2362 CookieOptions::SameSiteCookieMode::INCLUDE_STRICT_AND_LAX);
mmenkebe0910d2016-03-01 19:09:092363 // Note that the callbacks in hook_map_ are wrapped with RunAsync(), so they
ellyjones399e35a22014-10-27 11:09:562364 // are guaranteed to not take long - they just post a RunAsync task back to
mmenkebe0910d2016-03-01 19:09:092365 // the appropriate thread's message loop and return.
2366 // TODO(mmenke): Consider running these synchronously?
ellyjones399e35a22014-10-27 11:09:562367 for (CookieChangedHookMap::iterator it = hook_map_.begin();
2368 it != hook_map_.end(); ++it) {
2369 std::pair<GURL, std::string> key = it->first;
2370 if (cookie.IncludeForRequestURL(key.first, opts) &&
2371 cookie.Name() == key.second) {
nharper352933e2016-09-30 18:24:572372 it->second->Notify(cookie, cause);
ellyjones399e35a22014-10-27 11:09:562373 }
2374 }
2375}
2376
[email protected]63725312012-07-19 08:24:162377} // namespace net