1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 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 (dwitte (at) stanford.edu) 29 * Michiel van Leeuwen (mvl (at) exedo.nl) 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 45 #include "net/cookies/cookie_monster.h" 46 47 #include <algorithm> 48 #include <functional> 49 #include <set> 50 51 #include "base/basictypes.h" 52 #include "base/bind.h" 53 #include "base/callback.h" 54 #include "base/logging.h" 55 #include "base/memory/scoped_ptr.h" 56 #include "base/message_loop/message_loop.h" 57 #include "base/message_loop/message_loop_proxy.h" 58 #include "base/metrics/histogram.h" 59 #include "base/strings/string_util.h" 60 #include "base/strings/stringprintf.h" 61 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" 62 #include "net/cookies/canonical_cookie.h" 63 #include "net/cookies/cookie_util.h" 64 #include "net/cookies/parsed_cookie.h" 65 #include "url/gurl.h" 66 67 using base::Time; 68 using base::TimeDelta; 69 using base::TimeTicks; 70 71 // In steady state, most cookie requests can be satisfied by the in memory 72 // cookie monster store. However, if a request comes in during the initial 73 // cookie load, it must be delayed until that load completes. That is done by 74 // queueing it on CookieMonster::tasks_pending_ and running it when notification 75 // of cookie load completion is received via CookieMonster::OnLoaded. This 76 // callback is passed to the persistent store from CookieMonster::InitStore(), 77 // which is called on the first operation invoked on the CookieMonster. 78 // 79 // On the browser critical paths (e.g. for loading initial web pages in a 80 // session restore) it may take too long to wait for the full load. If a cookie 81 // request is for a specific URL, DoCookieTaskForURL is called, which triggers a 82 // priority load if the key is not loaded yet by calling PersistentCookieStore 83 // :: LoadCookiesForKey. The request is queued in 84 // CookieMonster::tasks_pending_for_key_ and executed upon receiving 85 // notification of key load completion via CookieMonster::OnKeyLoaded(). If 86 // multiple requests for the same eTLD+1 are received before key load 87 // completion, only the first request calls 88 // PersistentCookieStore::LoadCookiesForKey, all subsequent requests are queued 89 // in CookieMonster::tasks_pending_for_key_ and executed upon receiving 90 // notification of key load completion triggered by the first request for the 91 // same eTLD+1. 92 93 static const int kMinutesInTenYears = 10 * 365 * 24 * 60; 94 95 namespace net { 96 97 // See comments at declaration of these variables in cookie_monster.h 98 // for details. 99 const size_t CookieMonster::kDomainMaxCookies = 180; 100 const size_t CookieMonster::kDomainPurgeCookies = 30; 101 const size_t CookieMonster::kMaxCookies = 3300; 102 const size_t CookieMonster::kPurgeCookies = 300; 103 104 const size_t CookieMonster::kDomainCookiesQuotaLow = 30; 105 const size_t CookieMonster::kDomainCookiesQuotaMedium = 50; 106 const size_t CookieMonster::kDomainCookiesQuotaHigh = 107 CookieMonster::kDomainMaxCookies - CookieMonster::kDomainPurgeCookies 108 - CookieMonster::kDomainCookiesQuotaLow 109 - CookieMonster::kDomainCookiesQuotaMedium; 110 111 const int CookieMonster::kSafeFromGlobalPurgeDays = 30; 112 113 namespace { 114 115 typedef std::vector<CanonicalCookie*> CanonicalCookieVector; 116 117 // Default minimum delay after updating a cookie's LastAccessDate before we 118 // will update it again. 119 const int kDefaultAccessUpdateThresholdSeconds = 60; 120 121 // Comparator to sort cookies from highest creation date to lowest 122 // creation date. 123 struct OrderByCreationTimeDesc { 124 bool operator()(const CookieMonster::CookieMap::iterator& a, 125 const CookieMonster::CookieMap::iterator& b) const { 126 return a->second->CreationDate() > b->second->CreationDate(); 127 } 128 }; 129 130 // Constants for use in VLOG 131 const int kVlogPerCookieMonster = 1; 132 const int kVlogPeriodic = 3; 133 const int kVlogGarbageCollection = 5; 134 const int kVlogSetCookies = 7; 135 const int kVlogGetCookies = 9; 136 137 // Mozilla sorts on the path length (longest first), and then it 138 // sorts by creation time (oldest first). 139 // The RFC says the sort order for the domain attribute is undefined. 140 bool CookieSorter(CanonicalCookie* cc1, CanonicalCookie* cc2) { 141 if (cc1->Path().length() == cc2->Path().length()) 142 return cc1->CreationDate() < cc2->CreationDate(); 143 return cc1->Path().length() > cc2->Path().length(); 144 } 145 146 bool LRACookieSorter(const CookieMonster::CookieMap::iterator& it1, 147 const CookieMonster::CookieMap::iterator& it2) { 148 // Cookies accessed less recently should be deleted first. 149 if (it1->second->LastAccessDate() != it2->second->LastAccessDate()) 150 return it1->second->LastAccessDate() < it2->second->LastAccessDate(); 151 152 // In rare cases we might have two cookies with identical last access times. 153 // To preserve the stability of the sort, in these cases prefer to delete 154 // older cookies over newer ones. CreationDate() is guaranteed to be unique. 155 return it1->second->CreationDate() < it2->second->CreationDate(); 156 } 157 158 // Our strategy to find duplicates is: 159 // (1) Build a map from (cookiename, cookiepath) to 160 // {list of cookies with this signature, sorted by creation time}. 161 // (2) For each list with more than 1 entry, keep the cookie having the 162 // most recent creation time, and delete the others. 163 // 164 // Two cookies are considered equivalent if they have the same domain, 165 // name, and path. 166 struct CookieSignature { 167 public: 168 CookieSignature(const std::string& name, 169 const std::string& domain, 170 const std::string& path) 171 : name(name), domain(domain), path(path) { 172 } 173 174 // To be a key for a map this class needs to be assignable, copyable, 175 // and have an operator<. The default assignment operator 176 // and copy constructor are exactly what we want. 177 178 bool operator<(const CookieSignature& cs) const { 179 // Name compare dominates, then domain, then path. 180 int diff = name.compare(cs.name); 181 if (diff != 0) 182 return diff < 0; 183 184 diff = domain.compare(cs.domain); 185 if (diff != 0) 186 return diff < 0; 187 188 return path.compare(cs.path) < 0; 189 } 190 191 std::string name; 192 std::string domain; 193 std::string path; 194 }; 195 196 // Determine the cookie domain to use for setting the specified cookie. 197 bool GetCookieDomain(const GURL& url, 198 const ParsedCookie& pc, 199 std::string* result) { 200 std::string domain_string; 201 if (pc.HasDomain()) 202 domain_string = pc.Domain(); 203 return cookie_util::GetCookieDomainWithString(url, domain_string, result); 204 } 205 206 // For a CookieItVector iterator range [|it_begin|, |it_end|), 207 // sorts the first |num_sort| + 1 elements by LastAccessDate(). 208 // The + 1 element exists so for any interval of length <= |num_sort| starting 209 // from |cookies_its_begin|, a LastAccessDate() bound can be found. 210 void SortLeastRecentlyAccessed( 211 CookieMonster::CookieItVector::iterator it_begin, 212 CookieMonster::CookieItVector::iterator it_end, 213 size_t num_sort) { 214 DCHECK_LT(static_cast<int>(num_sort), it_end - it_begin); 215 std::partial_sort(it_begin, it_begin + num_sort + 1, it_end, LRACookieSorter); 216 } 217 218 // Predicate to support PartitionCookieByPriority(). 219 struct CookiePriorityEqualsTo 220 : std::unary_function<const CookieMonster::CookieMap::iterator, bool> { 221 CookiePriorityEqualsTo(CookiePriority priority) 222 : priority_(priority) {} 223 224 bool operator()(const CookieMonster::CookieMap::iterator it) const { 225 return it->second->Priority() == priority_; 226 } 227 228 const CookiePriority priority_; 229 }; 230 231 // For a CookieItVector iterator range [|it_begin|, |it_end|), 232 // moves all cookies with a given |priority| to the beginning of the list. 233 // Returns: An iterator in [it_begin, it_end) to the first element with 234 // priority != |priority|, or |it_end| if all have priority == |priority|. 235 CookieMonster::CookieItVector::iterator PartitionCookieByPriority( 236 CookieMonster::CookieItVector::iterator it_begin, 237 CookieMonster::CookieItVector::iterator it_end, 238 CookiePriority priority) { 239 return std::partition(it_begin, it_end, CookiePriorityEqualsTo(priority)); 240 } 241 242 bool LowerBoundAccessDateComparator( 243 const CookieMonster::CookieMap::iterator it, const Time& access_date) { 244 return it->second->LastAccessDate() < access_date; 245 } 246 247 // For a CookieItVector iterator range [|it_begin|, |it_end|) 248 // from a CookieItVector sorted by LastAccessDate(), returns the 249 // first iterator with access date >= |access_date|, or cookie_its_end if this 250 // holds for all. 251 CookieMonster::CookieItVector::iterator LowerBoundAccessDate( 252 const CookieMonster::CookieItVector::iterator its_begin, 253 const CookieMonster::CookieItVector::iterator its_end, 254 const Time& access_date) { 255 return std::lower_bound(its_begin, its_end, access_date, 256 LowerBoundAccessDateComparator); 257 } 258 259 // Mapping between DeletionCause and Delegate::ChangeCause; the mapping also 260 // provides a boolean that specifies whether or not an OnCookieChanged 261 // notification ought to be generated. 262 typedef struct ChangeCausePair_struct { 263 CookieMonster::Delegate::ChangeCause cause; 264 bool notify; 265 } ChangeCausePair; 266 ChangeCausePair ChangeCauseMapping[] = { 267 // DELETE_COOKIE_EXPLICIT 268 { CookieMonster::Delegate::CHANGE_COOKIE_EXPLICIT, true }, 269 // DELETE_COOKIE_OVERWRITE 270 { CookieMonster::Delegate::CHANGE_COOKIE_OVERWRITE, true }, 271 // DELETE_COOKIE_EXPIRED 272 { CookieMonster::Delegate::CHANGE_COOKIE_EXPIRED, true }, 273 // DELETE_COOKIE_EVICTED 274 { CookieMonster::Delegate::CHANGE_COOKIE_EVICTED, true }, 275 // DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE 276 { CookieMonster::Delegate::CHANGE_COOKIE_EXPLICIT, false }, 277 // DELETE_COOKIE_DONT_RECORD 278 { CookieMonster::Delegate::CHANGE_COOKIE_EXPLICIT, false }, 279 // DELETE_COOKIE_EVICTED_DOMAIN 280 { CookieMonster::Delegate::CHANGE_COOKIE_EVICTED, true }, 281 // DELETE_COOKIE_EVICTED_GLOBAL 282 { CookieMonster::Delegate::CHANGE_COOKIE_EVICTED, true }, 283 // DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE 284 { CookieMonster::Delegate::CHANGE_COOKIE_EVICTED, true }, 285 // DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE 286 { CookieMonster::Delegate::CHANGE_COOKIE_EVICTED, true }, 287 // DELETE_COOKIE_EXPIRED_OVERWRITE 288 { CookieMonster::Delegate::CHANGE_COOKIE_EXPIRED_OVERWRITE, true }, 289 // DELETE_COOKIE_LAST_ENTRY 290 { CookieMonster::Delegate::CHANGE_COOKIE_EXPLICIT, false } 291 }; 292 293 std::string BuildCookieLine(const CanonicalCookieVector& cookies) { 294 std::string cookie_line; 295 for (CanonicalCookieVector::const_iterator it = cookies.begin(); 296 it != cookies.end(); ++it) { 297 if (it != cookies.begin()) 298 cookie_line += "; "; 299 // In Mozilla if you set a cookie like AAAA, it will have an empty token 300 // and a value of AAAA. When it sends the cookie back, it will send AAAA, 301 // so we need to avoid sending =AAAA for a blank token value. 302 if (!(*it)->Name().empty()) 303 cookie_line += (*it)->Name() + "="; 304 cookie_line += (*it)->Value(); 305 } 306 return cookie_line; 307 } 308 309 } // namespace 310 311 // static 312 bool CookieMonster::default_enable_file_scheme_ = false; 313 314 CookieMonster::CookieMonster(PersistentCookieStore* store, Delegate* delegate) 315 : initialized_(false), 316 loaded_(false), 317 store_(store), 318 last_access_threshold_( 319 TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds)), 320 delegate_(delegate), 321 last_statistic_record_time_(Time::Now()), 322 keep_expired_cookies_(false), 323 persist_session_cookies_(false), 324 priority_aware_garbage_collection_(false) { 325 InitializeHistograms(); 326 SetDefaultCookieableSchemes(); 327 } 328 329 CookieMonster::CookieMonster(PersistentCookieStore* store, 330 Delegate* delegate, 331 int last_access_threshold_milliseconds) 332 : initialized_(false), 333 loaded_(false), 334 store_(store), 335 last_access_threshold_(base::TimeDelta::FromMilliseconds( 336 last_access_threshold_milliseconds)), 337 delegate_(delegate), 338 last_statistic_record_time_(base::Time::Now()), 339 keep_expired_cookies_(false), 340 persist_session_cookies_(false), 341 priority_aware_garbage_collection_(false) { 342 InitializeHistograms(); 343 SetDefaultCookieableSchemes(); 344 } 345 346 347 // Task classes for queueing the coming request. 348 349 class CookieMonster::CookieMonsterTask 350 : public base::RefCountedThreadSafe<CookieMonsterTask> { 351 public: 352 // Runs the task and invokes the client callback on the thread that 353 // originally constructed the task. 354 virtual void Run() = 0; 355 356 protected: 357 explicit CookieMonsterTask(CookieMonster* cookie_monster); 358 virtual ~CookieMonsterTask(); 359 360 // Invokes the callback immediately, if the current thread is the one 361 // that originated the task, or queues the callback for execution on the 362 // appropriate thread. Maintains a reference to this CookieMonsterTask 363 // instance until the callback completes. 364 void InvokeCallback(base::Closure callback); 365 366 CookieMonster* cookie_monster() { 367 return cookie_monster_; 368 } 369 370 private: 371 friend class base::RefCountedThreadSafe<CookieMonsterTask>; 372 373 CookieMonster* cookie_monster_; 374 scoped_refptr<base::MessageLoopProxy> thread_; 375 376 DISALLOW_COPY_AND_ASSIGN(CookieMonsterTask); 377 }; 378 379 CookieMonster::CookieMonsterTask::CookieMonsterTask( 380 CookieMonster* cookie_monster) 381 : cookie_monster_(cookie_monster), 382 thread_(base::MessageLoopProxy::current()) { 383 } 384 385 CookieMonster::CookieMonsterTask::~CookieMonsterTask() {} 386 387 // Unfortunately, one cannot re-bind a Callback with parameters into a closure. 388 // Therefore, the closure passed to InvokeCallback is a clumsy binding of 389 // Callback::Run on a wrapped Callback instance. Since Callback is not 390 // reference counted, we bind to an instance that is a member of the 391 // CookieMonsterTask subclass. Then, we cannot simply post the callback to a 392 // message loop because the underlying instance may be destroyed (along with the 393 // CookieMonsterTask instance) in the interim. Therefore, we post a callback 394 // bound to the CookieMonsterTask, which *is* reference counted (thus preventing 395 // destruction of the original callback), and which invokes the closure (which 396 // invokes the original callback with the returned data). 397 void CookieMonster::CookieMonsterTask::InvokeCallback(base::Closure callback) { 398 if (thread_->BelongsToCurrentThread()) { 399 callback.Run(); 400 } else { 401 thread_->PostTask(FROM_HERE, base::Bind( 402 &CookieMonster::CookieMonsterTask::InvokeCallback, this, callback)); 403 } 404 } 405 406 // Task class for SetCookieWithDetails call. 407 class CookieMonster::SetCookieWithDetailsTask 408 : public CookieMonster::CookieMonsterTask { 409 public: 410 SetCookieWithDetailsTask(CookieMonster* cookie_monster, 411 const GURL& url, 412 const std::string& name, 413 const std::string& value, 414 const std::string& domain, 415 const std::string& path, 416 const base::Time& expiration_time, 417 bool secure, 418 bool http_only, 419 CookiePriority priority, 420 const CookieMonster::SetCookiesCallback& callback) 421 : CookieMonsterTask(cookie_monster), 422 url_(url), 423 name_(name), 424 value_(value), 425 domain_(domain), 426 path_(path), 427 expiration_time_(expiration_time), 428 secure_(secure), 429 http_only_(http_only), 430 priority_(priority), 431 callback_(callback) { 432 } 433 434 // CookieMonster::CookieMonsterTask: 435 virtual void Run() OVERRIDE; 436 437 protected: 438 virtual ~SetCookieWithDetailsTask() {} 439 440 private: 441 GURL url_; 442 std::string name_; 443 std::string value_; 444 std::string domain_; 445 std::string path_; 446 base::Time expiration_time_; 447 bool secure_; 448 bool http_only_; 449 CookiePriority priority_; 450 CookieMonster::SetCookiesCallback callback_; 451 452 DISALLOW_COPY_AND_ASSIGN(SetCookieWithDetailsTask); 453 }; 454 455 void CookieMonster::SetCookieWithDetailsTask::Run() { 456 bool success = this->cookie_monster()-> 457 SetCookieWithDetails(url_, name_, value_, domain_, path_, 458 expiration_time_, secure_, http_only_, priority_); 459 if (!callback_.is_null()) { 460 this->InvokeCallback(base::Bind(&CookieMonster::SetCookiesCallback::Run, 461 base::Unretained(&callback_), success)); 462 } 463 } 464 465 // Task class for GetAllCookies call. 466 class CookieMonster::GetAllCookiesTask 467 : public CookieMonster::CookieMonsterTask { 468 public: 469 GetAllCookiesTask(CookieMonster* cookie_monster, 470 const CookieMonster::GetCookieListCallback& callback) 471 : CookieMonsterTask(cookie_monster), 472 callback_(callback) { 473 } 474 475 // CookieMonster::CookieMonsterTask 476 virtual void Run() OVERRIDE; 477 478 protected: 479 virtual ~GetAllCookiesTask() {} 480 481 private: 482 CookieMonster::GetCookieListCallback callback_; 483 484 DISALLOW_COPY_AND_ASSIGN(GetAllCookiesTask); 485 }; 486 487 void CookieMonster::GetAllCookiesTask::Run() { 488 if (!callback_.is_null()) { 489 CookieList cookies = this->cookie_monster()->GetAllCookies(); 490 this->InvokeCallback(base::Bind(&CookieMonster::GetCookieListCallback::Run, 491 base::Unretained(&callback_), cookies)); 492 } 493 } 494 495 // Task class for GetAllCookiesForURLWithOptions call. 496 class CookieMonster::GetAllCookiesForURLWithOptionsTask 497 : public CookieMonster::CookieMonsterTask { 498 public: 499 GetAllCookiesForURLWithOptionsTask( 500 CookieMonster* cookie_monster, 501 const GURL& url, 502 const CookieOptions& options, 503 const CookieMonster::GetCookieListCallback& callback) 504 : CookieMonsterTask(cookie_monster), 505 url_(url), 506 options_(options), 507 callback_(callback) { 508 } 509 510 // CookieMonster::CookieMonsterTask: 511 virtual void Run() OVERRIDE; 512 513 protected: 514 virtual ~GetAllCookiesForURLWithOptionsTask() {} 515 516 private: 517 GURL url_; 518 CookieOptions options_; 519 CookieMonster::GetCookieListCallback callback_; 520 521 DISALLOW_COPY_AND_ASSIGN(GetAllCookiesForURLWithOptionsTask); 522 }; 523 524 void CookieMonster::GetAllCookiesForURLWithOptionsTask::Run() { 525 if (!callback_.is_null()) { 526 CookieList cookies = this->cookie_monster()-> 527 GetAllCookiesForURLWithOptions(url_, options_); 528 this->InvokeCallback(base::Bind(&CookieMonster::GetCookieListCallback::Run, 529 base::Unretained(&callback_), cookies)); 530 } 531 } 532 533 // Task class for DeleteAll call. 534 class CookieMonster::DeleteAllTask : public CookieMonster::CookieMonsterTask { 535 public: 536 DeleteAllTask(CookieMonster* cookie_monster, 537 const CookieMonster::DeleteCallback& callback) 538 : CookieMonsterTask(cookie_monster), 539 callback_(callback) { 540 } 541 542 // CookieMonster::CookieMonsterTask: 543 virtual void Run() OVERRIDE; 544 545 protected: 546 virtual ~DeleteAllTask() {} 547 548 private: 549 CookieMonster::DeleteCallback callback_; 550 551 DISALLOW_COPY_AND_ASSIGN(DeleteAllTask); 552 }; 553 554 void CookieMonster::DeleteAllTask::Run() { 555 int num_deleted = this->cookie_monster()->DeleteAll(true); 556 if (!callback_.is_null()) { 557 this->InvokeCallback(base::Bind(&CookieMonster::DeleteCallback::Run, 558 base::Unretained(&callback_), num_deleted)); 559 } 560 } 561 562 // Task class for DeleteAllCreatedBetween call. 563 class CookieMonster::DeleteAllCreatedBetweenTask 564 : public CookieMonster::CookieMonsterTask { 565 public: 566 DeleteAllCreatedBetweenTask(CookieMonster* cookie_monster, 567 const Time& delete_begin, 568 const Time& delete_end, 569 const CookieMonster::DeleteCallback& callback) 570 : CookieMonsterTask(cookie_monster), 571 delete_begin_(delete_begin), 572 delete_end_(delete_end), 573 callback_(callback) { 574 } 575 576 // CookieMonster::CookieMonsterTask: 577 virtual void Run() OVERRIDE; 578 579 protected: 580 virtual ~DeleteAllCreatedBetweenTask() {} 581 582 private: 583 Time delete_begin_; 584 Time delete_end_; 585 CookieMonster::DeleteCallback callback_; 586 587 DISALLOW_COPY_AND_ASSIGN(DeleteAllCreatedBetweenTask); 588 }; 589 590 void CookieMonster::DeleteAllCreatedBetweenTask::Run() { 591 int num_deleted = this->cookie_monster()-> 592 DeleteAllCreatedBetween(delete_begin_, delete_end_); 593 if (!callback_.is_null()) { 594 this->InvokeCallback(base::Bind(&CookieMonster::DeleteCallback::Run, 595 base::Unretained(&callback_), num_deleted)); 596 } 597 } 598 599 // Task class for DeleteAllForHost call. 600 class CookieMonster::DeleteAllForHostTask 601 : public CookieMonster::CookieMonsterTask { 602 public: 603 DeleteAllForHostTask(CookieMonster* cookie_monster, 604 const GURL& url, 605 const CookieMonster::DeleteCallback& callback) 606 : CookieMonsterTask(cookie_monster), 607 url_(url), 608 callback_(callback) { 609 } 610 611 // CookieMonster::CookieMonsterTask: 612 virtual void Run() OVERRIDE; 613 614 protected: 615 virtual ~DeleteAllForHostTask() {} 616 617 private: 618 GURL url_; 619 CookieMonster::DeleteCallback callback_; 620 621 DISALLOW_COPY_AND_ASSIGN(DeleteAllForHostTask); 622 }; 623 624 void CookieMonster::DeleteAllForHostTask::Run() { 625 int num_deleted = this->cookie_monster()->DeleteAllForHost(url_); 626 if (!callback_.is_null()) { 627 this->InvokeCallback(base::Bind(&CookieMonster::DeleteCallback::Run, 628 base::Unretained(&callback_), num_deleted)); 629 } 630 } 631 632 // Task class for DeleteAllCreatedBetweenForHost call. 633 class CookieMonster::DeleteAllCreatedBetweenForHostTask 634 : public CookieMonster::CookieMonsterTask { 635 public: 636 DeleteAllCreatedBetweenForHostTask( 637 CookieMonster* cookie_monster, 638 Time delete_begin, 639 Time delete_end, 640 const GURL& url, 641 const CookieMonster::DeleteCallback& callback) 642 : CookieMonsterTask(cookie_monster), 643 delete_begin_(delete_begin), 644 delete_end_(delete_end), 645 url_(url), 646 callback_(callback) { 647 } 648 649 // CookieMonster::CookieMonsterTask: 650 virtual void Run() OVERRIDE; 651 652 protected: 653 virtual ~DeleteAllCreatedBetweenForHostTask() {} 654 655 private: 656 Time delete_begin_; 657 Time delete_end_; 658 GURL url_; 659 CookieMonster::DeleteCallback callback_; 660 661 DISALLOW_COPY_AND_ASSIGN(DeleteAllCreatedBetweenForHostTask); 662 }; 663 664 void CookieMonster::DeleteAllCreatedBetweenForHostTask::Run() { 665 int num_deleted = this->cookie_monster()->DeleteAllCreatedBetweenForHost( 666 delete_begin_, delete_end_, url_); 667 if (!callback_.is_null()) { 668 this->InvokeCallback(base::Bind(&CookieMonster::DeleteCallback::Run, 669 base::Unretained(&callback_), num_deleted)); 670 } 671 } 672 673 // Task class for DeleteCanonicalCookie call. 674 class CookieMonster::DeleteCanonicalCookieTask 675 : public CookieMonster::CookieMonsterTask { 676 public: 677 DeleteCanonicalCookieTask(CookieMonster* cookie_monster, 678 const CanonicalCookie& cookie, 679 const CookieMonster::DeleteCookieCallback& callback) 680 : CookieMonsterTask(cookie_monster), 681 cookie_(cookie), 682 callback_(callback) { 683 } 684 685 // CookieMonster::CookieMonsterTask: 686 virtual void Run() OVERRIDE; 687 688 protected: 689 virtual ~DeleteCanonicalCookieTask() {} 690 691 private: 692 CanonicalCookie cookie_; 693 CookieMonster::DeleteCookieCallback callback_; 694 695 DISALLOW_COPY_AND_ASSIGN(DeleteCanonicalCookieTask); 696 }; 697 698 void CookieMonster::DeleteCanonicalCookieTask::Run() { 699 bool result = this->cookie_monster()->DeleteCanonicalCookie(cookie_); 700 if (!callback_.is_null()) { 701 this->InvokeCallback(base::Bind(&CookieMonster::DeleteCookieCallback::Run, 702 base::Unretained(&callback_), result)); 703 } 704 } 705 706 // Task class for SetCookieWithOptions call. 707 class CookieMonster::SetCookieWithOptionsTask 708 : public CookieMonster::CookieMonsterTask { 709 public: 710 SetCookieWithOptionsTask(CookieMonster* cookie_monster, 711 const GURL& url, 712 const std::string& cookie_line, 713 const CookieOptions& options, 714 const CookieMonster::SetCookiesCallback& callback) 715 : CookieMonsterTask(cookie_monster), 716 url_(url), 717 cookie_line_(cookie_line), 718 options_(options), 719 callback_(callback) { 720 } 721 722 // CookieMonster::CookieMonsterTask: 723 virtual void Run() OVERRIDE; 724 725 protected: 726 virtual ~SetCookieWithOptionsTask() {} 727 728 private: 729 GURL url_; 730 std::string cookie_line_; 731 CookieOptions options_; 732 CookieMonster::SetCookiesCallback callback_; 733 734 DISALLOW_COPY_AND_ASSIGN(SetCookieWithOptionsTask); 735 }; 736 737 void CookieMonster::SetCookieWithOptionsTask::Run() { 738 bool result = this->cookie_monster()-> 739 SetCookieWithOptions(url_, cookie_line_, options_); 740 if (!callback_.is_null()) { 741 this->InvokeCallback(base::Bind(&CookieMonster::SetCookiesCallback::Run, 742 base::Unretained(&callback_), result)); 743 } 744 } 745 746 // Task class for GetCookiesWithOptions call. 747 class CookieMonster::GetCookiesWithOptionsTask 748 : public CookieMonster::CookieMonsterTask { 749 public: 750 GetCookiesWithOptionsTask(CookieMonster* cookie_monster, 751 const GURL& url, 752 const CookieOptions& options, 753 const CookieMonster::GetCookiesCallback& callback) 754 : CookieMonsterTask(cookie_monster), 755 url_(url), 756 options_(options), 757 callback_(callback) { 758 } 759 760 // CookieMonster::CookieMonsterTask: 761 virtual void Run() OVERRIDE; 762 763 protected: 764 virtual ~GetCookiesWithOptionsTask() {} 765 766 private: 767 GURL url_; 768 CookieOptions options_; 769 CookieMonster::GetCookiesCallback callback_; 770 771 DISALLOW_COPY_AND_ASSIGN(GetCookiesWithOptionsTask); 772 }; 773 774 void CookieMonster::GetCookiesWithOptionsTask::Run() { 775 std::string cookie = this->cookie_monster()-> 776 GetCookiesWithOptions(url_, options_); 777 if (!callback_.is_null()) { 778 this->InvokeCallback(base::Bind(&CookieMonster::GetCookiesCallback::Run, 779 base::Unretained(&callback_), cookie)); 780 } 781 } 782 783 // Task class for DeleteCookie call. 784 class CookieMonster::DeleteCookieTask 785 : public CookieMonster::CookieMonsterTask { 786 public: 787 DeleteCookieTask(CookieMonster* cookie_monster, 788 const GURL& url, 789 const std::string& cookie_name, 790 const base::Closure& callback) 791 : CookieMonsterTask(cookie_monster), 792 url_(url), 793 cookie_name_(cookie_name), 794 callback_(callback) { } 795 796 // CookieMonster::CookieMonsterTask: 797 virtual void Run() OVERRIDE; 798 799 protected: 800 virtual ~DeleteCookieTask() {} 801 802 private: 803 GURL url_; 804 std::string cookie_name_; 805 base::Closure callback_; 806 807 DISALLOW_COPY_AND_ASSIGN(DeleteCookieTask); 808 }; 809 810 void CookieMonster::DeleteCookieTask::Run() { 811 this->cookie_monster()->DeleteCookie(url_, cookie_name_); 812 if (!callback_.is_null()) { 813 this->InvokeCallback(callback_); 814 } 815 } 816 817 // Task class for DeleteSessionCookies call. 818 class CookieMonster::DeleteSessionCookiesTask 819 : public CookieMonster::CookieMonsterTask { 820 public: 821 DeleteSessionCookiesTask(CookieMonster* cookie_monster, 822 const CookieMonster::DeleteCallback& callback) 823 : CookieMonsterTask(cookie_monster), callback_(callback) { 824 } 825 826 // CookieMonster::CookieMonsterTask: 827 virtual void Run() OVERRIDE; 828 829 protected: 830 virtual ~DeleteSessionCookiesTask() {} 831 832 private: 833 CookieMonster::DeleteCallback callback_; 834 835 DISALLOW_COPY_AND_ASSIGN(DeleteSessionCookiesTask); 836 }; 837 838 void CookieMonster::DeleteSessionCookiesTask::Run() { 839 int num_deleted = this->cookie_monster()->DeleteSessionCookies(); 840 if (!callback_.is_null()) { 841 this->InvokeCallback(base::Bind(&CookieMonster::DeleteCallback::Run, 842 base::Unretained(&callback_), num_deleted)); 843 } 844 } 845 846 // Task class for HasCookiesForETLDP1Task call. 847 class CookieMonster::HasCookiesForETLDP1Task 848 : public CookieMonster::CookieMonsterTask { 849 public: 850 HasCookiesForETLDP1Task( 851 CookieMonster* cookie_monster, 852 const std::string& etldp1, 853 const CookieMonster::HasCookiesForETLDP1Callback& callback) 854 : CookieMonsterTask(cookie_monster), 855 etldp1_(etldp1), 856 callback_(callback) { 857 } 858 859 // CookieMonster::CookieMonsterTask: 860 virtual void Run() OVERRIDE; 861 862 protected: 863 virtual ~HasCookiesForETLDP1Task() {} 864 865 private: 866 std::string etldp1_; 867 CookieMonster::HasCookiesForETLDP1Callback callback_; 868 869 DISALLOW_COPY_AND_ASSIGN(HasCookiesForETLDP1Task); 870 }; 871 872 void CookieMonster::HasCookiesForETLDP1Task::Run() { 873 bool result = this->cookie_monster()->HasCookiesForETLDP1(etldp1_); 874 if (!callback_.is_null()) { 875 this->InvokeCallback( 876 base::Bind(&CookieMonster::HasCookiesForETLDP1Callback::Run, 877 base::Unretained(&callback_), result)); 878 } 879 } 880 881 // Asynchronous CookieMonster API 882 883 void CookieMonster::SetCookieWithDetailsAsync( 884 const GURL& url, 885 const std::string& name, 886 const std::string& value, 887 const std::string& domain, 888 const std::string& path, 889 const Time& expiration_time, 890 bool secure, 891 bool http_only, 892 CookiePriority priority, 893 const SetCookiesCallback& callback) { 894 scoped_refptr<SetCookieWithDetailsTask> task = 895 new SetCookieWithDetailsTask(this, url, name, value, domain, path, 896 expiration_time, secure, http_only, priority, 897 callback); 898 899 DoCookieTaskForURL(task, url); 900 } 901 902 void CookieMonster::GetAllCookiesAsync(const GetCookieListCallback& callback) { 903 scoped_refptr<GetAllCookiesTask> task = 904 new GetAllCookiesTask(this, callback); 905 906 DoCookieTask(task); 907 } 908 909 910 void CookieMonster::GetAllCookiesForURLWithOptionsAsync( 911 const GURL& url, 912 const CookieOptions& options, 913 const GetCookieListCallback& callback) { 914 scoped_refptr<GetAllCookiesForURLWithOptionsTask> task = 915 new GetAllCookiesForURLWithOptionsTask(this, url, options, callback); 916 917 DoCookieTaskForURL(task, url); 918 } 919 920 void CookieMonster::GetAllCookiesForURLAsync( 921 const GURL& url, const GetCookieListCallback& callback) { 922 CookieOptions options; 923 options.set_include_httponly(); 924 scoped_refptr<GetAllCookiesForURLWithOptionsTask> task = 925 new GetAllCookiesForURLWithOptionsTask(this, url, options, callback); 926 927 DoCookieTaskForURL(task, url); 928 } 929 930 void CookieMonster::HasCookiesForETLDP1Async( 931 const std::string& etldp1, 932 const HasCookiesForETLDP1Callback& callback) { 933 scoped_refptr<HasCookiesForETLDP1Task> task = 934 new HasCookiesForETLDP1Task(this, etldp1, callback); 935 936 DoCookieTaskForURL(task, GURL("http://" + etldp1)); 937 } 938 939 void CookieMonster::DeleteAllAsync(const DeleteCallback& callback) { 940 scoped_refptr<DeleteAllTask> task = 941 new DeleteAllTask(this, callback); 942 943 DoCookieTask(task); 944 } 945 946 void CookieMonster::DeleteAllCreatedBetweenAsync( 947 const Time& delete_begin, const Time& delete_end, 948 const DeleteCallback& callback) { 949 scoped_refptr<DeleteAllCreatedBetweenTask> task = 950 new DeleteAllCreatedBetweenTask(this, delete_begin, delete_end, 951 callback); 952 953 DoCookieTask(task); 954 } 955 956 void CookieMonster::DeleteAllCreatedBetweenForHostAsync( 957 const Time delete_begin, 958 const Time delete_end, 959 const GURL& url, 960 const DeleteCallback& callback) { 961 scoped_refptr<DeleteAllCreatedBetweenForHostTask> task = 962 new DeleteAllCreatedBetweenForHostTask( 963 this, delete_begin, delete_end, url, callback); 964 965 DoCookieTaskForURL(task, url); 966 } 967 968 void CookieMonster::DeleteAllForHostAsync( 969 const GURL& url, const DeleteCallback& callback) { 970 scoped_refptr<DeleteAllForHostTask> task = 971 new DeleteAllForHostTask(this, url, callback); 972 973 DoCookieTaskForURL(task, url); 974 } 975 976 void CookieMonster::DeleteCanonicalCookieAsync( 977 const CanonicalCookie& cookie, 978 const DeleteCookieCallback& callback) { 979 scoped_refptr<DeleteCanonicalCookieTask> task = 980 new DeleteCanonicalCookieTask(this, cookie, callback); 981 982 DoCookieTask(task); 983 } 984 985 void CookieMonster::SetCookieWithOptionsAsync( 986 const GURL& url, 987 const std::string& cookie_line, 988 const CookieOptions& options, 989 const SetCookiesCallback& callback) { 990 scoped_refptr<SetCookieWithOptionsTask> task = 991 new SetCookieWithOptionsTask(this, url, cookie_line, options, callback); 992 993 DoCookieTaskForURL(task, url); 994 } 995 996 void CookieMonster::GetCookiesWithOptionsAsync( 997 const GURL& url, 998 const CookieOptions& options, 999 const GetCookiesCallback& callback) { 1000 scoped_refptr<GetCookiesWithOptionsTask> task = 1001 new GetCookiesWithOptionsTask(this, url, options, callback); 1002 1003 DoCookieTaskForURL(task, url); 1004 } 1005 1006 void CookieMonster::DeleteCookieAsync(const GURL& url, 1007 const std::string& cookie_name, 1008 const base::Closure& callback) { 1009 scoped_refptr<DeleteCookieTask> task = 1010 new DeleteCookieTask(this, url, cookie_name, callback); 1011 1012 DoCookieTaskForURL(task, url); 1013 } 1014 1015 void CookieMonster::DeleteSessionCookiesAsync( 1016 const CookieStore::DeleteCallback& callback) { 1017 scoped_refptr<DeleteSessionCookiesTask> task = 1018 new DeleteSessionCookiesTask(this, callback); 1019 1020 DoCookieTask(task); 1021 } 1022 1023 void CookieMonster::DoCookieTask( 1024 const scoped_refptr<CookieMonsterTask>& task_item) { 1025 { 1026 base::AutoLock autolock(lock_); 1027 InitIfNecessary(); 1028 if (!loaded_) { 1029 tasks_pending_.push(task_item); 1030 return; 1031 } 1032 } 1033 1034 task_item->Run(); 1035 } 1036 1037 void CookieMonster::DoCookieTaskForURL( 1038 const scoped_refptr<CookieMonsterTask>& task_item, 1039 const GURL& url) { 1040 { 1041 base::AutoLock autolock(lock_); 1042 InitIfNecessary(); 1043 // If cookies for the requested domain key (eTLD+1) have been loaded from DB 1044 // then run the task, otherwise load from DB. 1045 if (!loaded_) { 1046 // Checks if the domain key has been loaded. 1047 std::string key(cookie_util::GetEffectiveDomain(url.scheme(), 1048 url.host())); 1049 if (keys_loaded_.find(key) == keys_loaded_.end()) { 1050 std::map<std::string, std::deque<scoped_refptr<CookieMonsterTask> > > 1051 ::iterator it = tasks_pending_for_key_.find(key); 1052 if (it == tasks_pending_for_key_.end()) { 1053 store_->LoadCookiesForKey(key, 1054 base::Bind(&CookieMonster::OnKeyLoaded, this, key)); 1055 it = tasks_pending_for_key_.insert(std::make_pair(key, 1056 std::deque<scoped_refptr<CookieMonsterTask> >())).first; 1057 } 1058 it->second.push_back(task_item); 1059 return; 1060 } 1061 } 1062 } 1063 task_item->Run(); 1064 } 1065 1066 bool CookieMonster::SetCookieWithDetails(const GURL& url, 1067 const std::string& name, 1068 const std::string& value, 1069 const std::string& domain, 1070 const std::string& path, 1071 const base::Time& expiration_time, 1072 bool secure, 1073 bool http_only, 1074 CookiePriority priority) { 1075 base::AutoLock autolock(lock_); 1076 1077 if (!HasCookieableScheme(url)) 1078 return false; 1079 1080 Time creation_time = CurrentTime(); 1081 last_time_seen_ = creation_time; 1082 1083 scoped_ptr<CanonicalCookie> cc; 1084 cc.reset(CanonicalCookie::Create(url, name, value, domain, path, 1085 creation_time, expiration_time, 1086 secure, http_only, priority)); 1087 1088 if (!cc.get()) 1089 return false; 1090 1091 CookieOptions options; 1092 options.set_include_httponly(); 1093 return SetCanonicalCookie(&cc, creation_time, options); 1094 } 1095 1096 bool CookieMonster::InitializeFrom(const CookieList& list) { 1097 base::AutoLock autolock(lock_); 1098 InitIfNecessary(); 1099 for (net::CookieList::const_iterator iter = list.begin(); 1100 iter != list.end(); ++iter) { 1101 scoped_ptr<CanonicalCookie> cookie(new CanonicalCookie(*iter)); 1102 net::CookieOptions options; 1103 options.set_include_httponly(); 1104 if (!SetCanonicalCookie(&cookie, cookie->CreationDate(), options)) 1105 return false; 1106 } 1107 return true; 1108 } 1109 1110 CookieList CookieMonster::GetAllCookies() { 1111 base::AutoLock autolock(lock_); 1112 1113 // This function is being called to scrape the cookie list for management UI 1114 // or similar. We shouldn't show expired cookies in this list since it will 1115 // just be confusing to users, and this function is called rarely enough (and 1116 // is already slow enough) that it's OK to take the time to garbage collect 1117 // the expired cookies now. 1118 // 1119 // Note that this does not prune cookies to be below our limits (if we've 1120 // exceeded them) the way that calling GarbageCollect() would. 1121 GarbageCollectExpired(Time::Now(), 1122 CookieMapItPair(cookies_.begin(), cookies_.end()), 1123 NULL); 1124 1125 // Copy the CanonicalCookie pointers from the map so that we can use the same 1126 // sorter as elsewhere, then copy the result out. 1127 std::vector<CanonicalCookie*> cookie_ptrs; 1128 cookie_ptrs.reserve(cookies_.size()); 1129 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end(); ++it) 1130 cookie_ptrs.push_back(it->second); 1131 std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter); 1132 1133 CookieList cookie_list; 1134 cookie_list.reserve(cookie_ptrs.size()); 1135 for (std::vector<CanonicalCookie*>::const_iterator it = cookie_ptrs.begin(); 1136 it != cookie_ptrs.end(); ++it) 1137 cookie_list.push_back(**it); 1138 1139 return cookie_list; 1140 } 1141 1142 CookieList CookieMonster::GetAllCookiesForURLWithOptions( 1143 const GURL& url, 1144 const CookieOptions& options) { 1145 base::AutoLock autolock(lock_); 1146 1147 std::vector<CanonicalCookie*> cookie_ptrs; 1148 FindCookiesForHostAndDomain(url, options, false, &cookie_ptrs); 1149 std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter); 1150 1151 CookieList cookies; 1152 for (std::vector<CanonicalCookie*>::const_iterator it = cookie_ptrs.begin(); 1153 it != cookie_ptrs.end(); it++) 1154 cookies.push_back(**it); 1155 1156 return cookies; 1157 } 1158 1159 CookieList CookieMonster::GetAllCookiesForURL(const GURL& url) { 1160 CookieOptions options; 1161 options.set_include_httponly(); 1162 1163 return GetAllCookiesForURLWithOptions(url, options); 1164 } 1165 1166 int CookieMonster::DeleteAll(bool sync_to_store) { 1167 base::AutoLock autolock(lock_); 1168 1169 int num_deleted = 0; 1170 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) { 1171 CookieMap::iterator curit = it; 1172 ++it; 1173 InternalDeleteCookie(curit, sync_to_store, 1174 sync_to_store ? DELETE_COOKIE_EXPLICIT : 1175 DELETE_COOKIE_DONT_RECORD /* Destruction. */); 1176 ++num_deleted; 1177 } 1178 1179 return num_deleted; 1180 } 1181 1182 int CookieMonster::DeleteAllCreatedBetween(const Time& delete_begin, 1183 const Time& delete_end) { 1184 base::AutoLock autolock(lock_); 1185 1186 int num_deleted = 0; 1187 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) { 1188 CookieMap::iterator curit = it; 1189 CanonicalCookie* cc = curit->second; 1190 ++it; 1191 1192 if (cc->CreationDate() >= delete_begin && 1193 (delete_end.is_null() || cc->CreationDate() < delete_end)) { 1194 InternalDeleteCookie(curit, 1195 true, /*sync_to_store*/ 1196 DELETE_COOKIE_EXPLICIT); 1197 ++num_deleted; 1198 } 1199 } 1200 1201 return num_deleted; 1202 } 1203 1204 int CookieMonster::DeleteAllCreatedBetweenForHost(const Time delete_begin, 1205 const Time delete_end, 1206 const GURL& url) { 1207 base::AutoLock autolock(lock_); 1208 1209 if (!HasCookieableScheme(url)) 1210 return 0; 1211 1212 const std::string host(url.host()); 1213 1214 // We store host cookies in the store by their canonical host name; 1215 // domain cookies are stored with a leading ".". So this is a pretty 1216 // simple lookup and per-cookie delete. 1217 int num_deleted = 0; 1218 for (CookieMapItPair its = cookies_.equal_range(GetKey(host)); 1219 its.first != its.second;) { 1220 CookieMap::iterator curit = its.first; 1221 ++its.first; 1222 1223 const CanonicalCookie* const cc = curit->second; 1224 1225 // Delete only on a match as a host cookie. 1226 if (cc->IsHostCookie() && cc->IsDomainMatch(host) && 1227 cc->CreationDate() >= delete_begin && 1228 // The assumption that null |delete_end| is equivalent to 1229 // Time::Max() is confusing. 1230 (delete_end.is_null() || cc->CreationDate() < delete_end)) { 1231 num_deleted++; 1232 1233 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPLICIT); 1234 } 1235 } 1236 return num_deleted; 1237 } 1238 1239 int CookieMonster::DeleteAllForHost(const GURL& url) { 1240 return DeleteAllCreatedBetweenForHost(Time(), Time::Max(), url); 1241 } 1242 1243 1244 bool CookieMonster::DeleteCanonicalCookie(const CanonicalCookie& cookie) { 1245 base::AutoLock autolock(lock_); 1246 1247 for (CookieMapItPair its = cookies_.equal_range(GetKey(cookie.Domain())); 1248 its.first != its.second; ++its.first) { 1249 // The creation date acts as our unique index... 1250 if (its.first->second->CreationDate() == cookie.CreationDate()) { 1251 InternalDeleteCookie(its.first, true, DELETE_COOKIE_EXPLICIT); 1252 return true; 1253 } 1254 } 1255 return false; 1256 } 1257 1258 void CookieMonster::SetCookieableSchemes(const char* schemes[], 1259 size_t num_schemes) { 1260 base::AutoLock autolock(lock_); 1261 1262 // Cookieable Schemes must be set before first use of function. 1263 DCHECK(!initialized_); 1264 1265 cookieable_schemes_.clear(); 1266 cookieable_schemes_.insert(cookieable_schemes_.end(), 1267 schemes, schemes + num_schemes); 1268 } 1269 1270 void CookieMonster::SetEnableFileScheme(bool accept) { 1271 // This assumes "file" is always at the end of the array. See the comment 1272 // above kDefaultCookieableSchemes. 1273 int num_schemes = accept ? kDefaultCookieableSchemesCount : 1274 kDefaultCookieableSchemesCount - 1; 1275 SetCookieableSchemes(kDefaultCookieableSchemes, num_schemes); 1276 } 1277 1278 void CookieMonster::SetKeepExpiredCookies() { 1279 keep_expired_cookies_ = true; 1280 } 1281 1282 // static 1283 void CookieMonster::EnableFileScheme() { 1284 default_enable_file_scheme_ = true; 1285 } 1286 1287 void CookieMonster::FlushStore(const base::Closure& callback) { 1288 base::AutoLock autolock(lock_); 1289 if (initialized_ && store_.get()) 1290 store_->Flush(callback); 1291 else if (!callback.is_null()) 1292 base::MessageLoop::current()->PostTask(FROM_HERE, callback); 1293 } 1294 1295 bool CookieMonster::SetCookieWithOptions(const GURL& url, 1296 const std::string& cookie_line, 1297 const CookieOptions& options) { 1298 base::AutoLock autolock(lock_); 1299 1300 if (!HasCookieableScheme(url)) { 1301 return false; 1302 } 1303 1304 return SetCookieWithCreationTimeAndOptions(url, cookie_line, Time(), options); 1305 } 1306 1307 std::string CookieMonster::GetCookiesWithOptions(const GURL& url, 1308 const CookieOptions& options) { 1309 base::AutoLock autolock(lock_); 1310 1311 if (!HasCookieableScheme(url)) 1312 return std::string(); 1313 1314 TimeTicks start_time(TimeTicks::Now()); 1315 1316 std::vector<CanonicalCookie*> cookies; 1317 FindCookiesForHostAndDomain(url, options, true, &cookies); 1318 std::sort(cookies.begin(), cookies.end(), CookieSorter); 1319 1320 std::string cookie_line = BuildCookieLine(cookies); 1321 1322 histogram_time_get_->AddTime(TimeTicks::Now() - start_time); 1323 1324 VLOG(kVlogGetCookies) << "GetCookies() result: " << cookie_line; 1325 1326 return cookie_line; 1327 } 1328 1329 void CookieMonster::DeleteCookie(const GURL& url, 1330 const std::string& cookie_name) { 1331 base::AutoLock autolock(lock_); 1332 1333 if (!HasCookieableScheme(url)) 1334 return; 1335 1336 CookieOptions options; 1337 options.set_include_httponly(); 1338 // Get the cookies for this host and its domain(s). 1339 std::vector<CanonicalCookie*> cookies; 1340 FindCookiesForHostAndDomain(url, options, true, &cookies); 1341 std::set<CanonicalCookie*> matching_cookies; 1342 1343 for (std::vector<CanonicalCookie*>::const_iterator it = cookies.begin(); 1344 it != cookies.end(); ++it) { 1345 if ((*it)->Name() != cookie_name) 1346 continue; 1347 if (url.path().find((*it)->Path())) 1348 continue; 1349 matching_cookies.insert(*it); 1350 } 1351 1352 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) { 1353 CookieMap::iterator curit = it; 1354 ++it; 1355 if (matching_cookies.find(curit->second) != matching_cookies.end()) { 1356 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPLICIT); 1357 } 1358 } 1359 } 1360 1361 int CookieMonster::DeleteSessionCookies() { 1362 base::AutoLock autolock(lock_); 1363 1364 int num_deleted = 0; 1365 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) { 1366 CookieMap::iterator curit = it; 1367 CanonicalCookie* cc = curit->second; 1368 ++it; 1369 1370 if (!cc->IsPersistent()) { 1371 InternalDeleteCookie(curit, 1372 true, /*sync_to_store*/ 1373 DELETE_COOKIE_EXPIRED); 1374 ++num_deleted; 1375 } 1376 } 1377 1378 return num_deleted; 1379 } 1380 1381 bool CookieMonster::HasCookiesForETLDP1(const std::string& etldp1) { 1382 base::AutoLock autolock(lock_); 1383 1384 const std::string key(GetKey(etldp1)); 1385 1386 CookieMapItPair its = cookies_.equal_range(key); 1387 return its.first != its.second; 1388 } 1389 1390 CookieMonster* CookieMonster::GetCookieMonster() { 1391 return this; 1392 } 1393 1394 // This function must be called before the CookieMonster is used. 1395 void CookieMonster::SetPersistSessionCookies(bool persist_session_cookies) { 1396 DCHECK(!initialized_); 1397 persist_session_cookies_ = persist_session_cookies; 1398 } 1399 1400 // This function must be called before the CookieMonster is used. 1401 void CookieMonster::SetPriorityAwareGarbageCollection( 1402 bool priority_aware_garbage_collection) { 1403 DCHECK(!initialized_); 1404 priority_aware_garbage_collection_ = priority_aware_garbage_collection; 1405 } 1406 1407 void CookieMonster::SetForceKeepSessionState() { 1408 if (store_.get()) { 1409 store_->SetForceKeepSessionState(); 1410 } 1411 } 1412 1413 CookieMonster::~CookieMonster() { 1414 DeleteAll(false); 1415 } 1416 1417 bool CookieMonster::SetCookieWithCreationTime(const GURL& url, 1418 const std::string& cookie_line, 1419 const base::Time& creation_time) { 1420 DCHECK(!store_.get()) << "This method is only to be used by unit-tests."; 1421 base::AutoLock autolock(lock_); 1422 1423 if (!HasCookieableScheme(url)) { 1424 return false; 1425 } 1426 1427 InitIfNecessary(); 1428 return SetCookieWithCreationTimeAndOptions(url, cookie_line, creation_time, 1429 CookieOptions()); 1430 } 1431 1432 void CookieMonster::InitStore() { 1433 DCHECK(store_.get()) << "Store must exist to initialize"; 1434 1435 // We bind in the current time so that we can report the wall-clock time for 1436 // loading cookies. 1437 store_->Load(base::Bind(&CookieMonster::OnLoaded, this, TimeTicks::Now())); 1438 } 1439 1440 void CookieMonster::OnLoaded(TimeTicks beginning_time, 1441 const std::vector<CanonicalCookie*>& cookies) { 1442 StoreLoadedCookies(cookies); 1443 histogram_time_blocked_on_load_->AddTime(TimeTicks::Now() - beginning_time); 1444 1445 // Invoke the task queue of cookie request. 1446 InvokeQueue(); 1447 } 1448 1449 void CookieMonster::OnKeyLoaded(const std::string& key, 1450 const std::vector<CanonicalCookie*>& cookies) { 1451 // This function does its own separate locking. 1452 StoreLoadedCookies(cookies); 1453 1454 std::deque<scoped_refptr<CookieMonsterTask> > tasks_pending_for_key; 1455 { 1456 base::AutoLock autolock(lock_); 1457 keys_loaded_.insert(key); 1458 std::map<std::string, std::deque<scoped_refptr<CookieMonsterTask> > > 1459 ::iterator it = tasks_pending_for_key_.find(key); 1460 if (it == tasks_pending_for_key_.end()) 1461 return; 1462 it->second.swap(tasks_pending_for_key); 1463 tasks_pending_for_key_.erase(it); 1464 } 1465 1466 while (!tasks_pending_for_key.empty()) { 1467 scoped_refptr<CookieMonsterTask> task = tasks_pending_for_key.front(); 1468 task->Run(); 1469 tasks_pending_for_key.pop_front(); 1470 } 1471 } 1472 1473 void CookieMonster::StoreLoadedCookies( 1474 const std::vector<CanonicalCookie*>& cookies) { 1475 // Initialize the store and sync in any saved persistent cookies. We don't 1476 // care if it's expired, insert it so it can be garbage collected, removed, 1477 // and sync'd. 1478 base::AutoLock autolock(lock_); 1479 1480 for (std::vector<CanonicalCookie*>::const_iterator it = cookies.begin(); 1481 it != cookies.end(); ++it) { 1482 int64 cookie_creation_time = (*it)->CreationDate().ToInternalValue(); 1483 1484 if (creation_times_.insert(cookie_creation_time).second) { 1485 InternalInsertCookie(GetKey((*it)->Domain()), *it, false); 1486 const Time cookie_access_time((*it)->LastAccessDate()); 1487 if (earliest_access_time_.is_null() || 1488 cookie_access_time < earliest_access_time_) 1489 earliest_access_time_ = cookie_access_time; 1490 } else { 1491 LOG(ERROR) << base::StringPrintf("Found cookies with duplicate creation " 1492 "times in backing store: " 1493 "{name='%s', domain='%s', path='%s'}", 1494 (*it)->Name().c_str(), 1495 (*it)->Domain().c_str(), 1496 (*it)->Path().c_str()); 1497 // We've been given ownership of the cookie and are throwing it 1498 // away; reclaim the space. 1499 delete (*it); 1500 } 1501 } 1502 1503 // After importing cookies from the PersistentCookieStore, verify that 1504 // none of our other constraints are violated. 1505 // In particular, the backing store might have given us duplicate cookies. 1506 1507 // This method could be called multiple times due to priority loading, thus 1508 // cookies loaded in previous runs will be validated again, but this is OK 1509 // since they are expected to be much fewer than total DB. 1510 EnsureCookiesMapIsValid(); 1511 } 1512 1513 void CookieMonster::InvokeQueue() { 1514 while (true) { 1515 scoped_refptr<CookieMonsterTask> request_task; 1516 { 1517 base::AutoLock autolock(lock_); 1518 if (tasks_pending_.empty()) { 1519 loaded_ = true; 1520 creation_times_.clear(); 1521 keys_loaded_.clear(); 1522 break; 1523 } 1524 request_task = tasks_pending_.front(); 1525 tasks_pending_.pop(); 1526 } 1527 request_task->Run(); 1528 } 1529 } 1530 1531 void CookieMonster::EnsureCookiesMapIsValid() { 1532 lock_.AssertAcquired(); 1533 1534 int num_duplicates_trimmed = 0; 1535 1536 // Iterate through all the of the cookies, grouped by host. 1537 CookieMap::iterator prev_range_end = cookies_.begin(); 1538 while (prev_range_end != cookies_.end()) { 1539 CookieMap::iterator cur_range_begin = prev_range_end; 1540 const std::string key = cur_range_begin->first; // Keep a copy. 1541 CookieMap::iterator cur_range_end = cookies_.upper_bound(key); 1542 prev_range_end = cur_range_end; 1543 1544 // Ensure no equivalent cookies for this host. 1545 num_duplicates_trimmed += 1546 TrimDuplicateCookiesForKey(key, cur_range_begin, cur_range_end); 1547 } 1548 1549 // Record how many duplicates were found in the database. 1550 // See InitializeHistograms() for details. 1551 histogram_cookie_deletion_cause_->Add(num_duplicates_trimmed); 1552 } 1553 1554 int CookieMonster::TrimDuplicateCookiesForKey( 1555 const std::string& key, 1556 CookieMap::iterator begin, 1557 CookieMap::iterator end) { 1558 lock_.AssertAcquired(); 1559 1560 // Set of cookies ordered by creation time. 1561 typedef std::set<CookieMap::iterator, OrderByCreationTimeDesc> CookieSet; 1562 1563 // Helper map we populate to find the duplicates. 1564 typedef std::map<CookieSignature, CookieSet> EquivalenceMap; 1565 EquivalenceMap equivalent_cookies; 1566 1567 // The number of duplicate cookies that have been found. 1568 int num_duplicates = 0; 1569 1570 // Iterate through all of the cookies in our range, and insert them into 1571 // the equivalence map. 1572 for (CookieMap::iterator it = begin; it != end; ++it) { 1573 DCHECK_EQ(key, it->first); 1574 CanonicalCookie* cookie = it->second; 1575 1576 CookieSignature signature(cookie->Name(), cookie->Domain(), 1577 cookie->Path()); 1578 CookieSet& set = equivalent_cookies[signature]; 1579 1580 // We found a duplicate! 1581 if (!set.empty()) 1582 num_duplicates++; 1583 1584 // We save the iterator into |cookies_| rather than the actual cookie 1585 // pointer, since we may need to delete it later. 1586 bool insert_success = set.insert(it).second; 1587 DCHECK(insert_success) << 1588 "Duplicate creation times found in duplicate cookie name scan."; 1589 } 1590 1591 // If there were no duplicates, we are done! 1592 if (num_duplicates == 0) 1593 return 0; 1594 1595 // Make sure we find everything below that we did above. 1596 int num_duplicates_found = 0; 1597 1598 // Otherwise, delete all the duplicate cookies, both from our in-memory store 1599 // and from the backing store. 1600 for (EquivalenceMap::iterator it = equivalent_cookies.begin(); 1601 it != equivalent_cookies.end(); 1602 ++it) { 1603 const CookieSignature& signature = it->first; 1604 CookieSet& dupes = it->second; 1605 1606 if (dupes.size() <= 1) 1607 continue; // This cookiename/path has no duplicates. 1608 num_duplicates_found += dupes.size() - 1; 1609 1610 // Since |dups| is sorted by creation time (descending), the first cookie 1611 // is the most recent one, so we will keep it. The rest are duplicates. 1612 dupes.erase(dupes.begin()); 1613 1614 LOG(ERROR) << base::StringPrintf( 1615 "Found %d duplicate cookies for host='%s', " 1616 "with {name='%s', domain='%s', path='%s'}", 1617 static_cast<int>(dupes.size()), 1618 key.c_str(), 1619 signature.name.c_str(), 1620 signature.domain.c_str(), 1621 signature.path.c_str()); 1622 1623 // Remove all the cookies identified by |dupes|. It is valid to delete our 1624 // list of iterators one at a time, since |cookies_| is a multimap (they 1625 // don't invalidate existing iterators following deletion). 1626 for (CookieSet::iterator dupes_it = dupes.begin(); 1627 dupes_it != dupes.end(); 1628 ++dupes_it) { 1629 InternalDeleteCookie(*dupes_it, true, 1630 DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE); 1631 } 1632 } 1633 DCHECK_EQ(num_duplicates, num_duplicates_found); 1634 1635 return num_duplicates; 1636 } 1637 1638 // Note: file must be the last scheme. 1639 const char* CookieMonster::kDefaultCookieableSchemes[] = 1640 { "http", "https", "file" }; 1641 const int CookieMonster::kDefaultCookieableSchemesCount = 1642 arraysize(CookieMonster::kDefaultCookieableSchemes); 1643 1644 void CookieMonster::SetDefaultCookieableSchemes() { 1645 int num_schemes = default_enable_file_scheme_ ? 1646 kDefaultCookieableSchemesCount : kDefaultCookieableSchemesCount - 1; 1647 SetCookieableSchemes(kDefaultCookieableSchemes, num_schemes); 1648 } 1649 1650 void CookieMonster::FindCookiesForHostAndDomain( 1651 const GURL& url, 1652 const CookieOptions& options, 1653 bool update_access_time, 1654 std::vector<CanonicalCookie*>* cookies) { 1655 lock_.AssertAcquired(); 1656 1657 const Time current_time(CurrentTime()); 1658 1659 // Probe to save statistics relatively frequently. We do it here rather 1660 // than in the set path as many websites won't set cookies, and we 1661 // want to collect statistics whenever the browser's being used. 1662 RecordPeriodicStats(current_time); 1663 1664 // Can just dispatch to FindCookiesForKey 1665 const std::string key(GetKey(url.host())); 1666 FindCookiesForKey(key, url, options, current_time, 1667 update_access_time, cookies); 1668 } 1669 1670 void CookieMonster::FindCookiesForKey(const std::string& key, 1671 const GURL& url, 1672 const CookieOptions& options, 1673 const Time& current, 1674 bool update_access_time, 1675 std::vector<CanonicalCookie*>* cookies) { 1676 lock_.AssertAcquired(); 1677 1678 for (CookieMapItPair its = cookies_.equal_range(key); 1679 its.first != its.second; ) { 1680 CookieMap::iterator curit = its.first; 1681 CanonicalCookie* cc = curit->second; 1682 ++its.first; 1683 1684 // If the cookie is expired, delete it. 1685 if (cc->IsExpired(current) && !keep_expired_cookies_) { 1686 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED); 1687 continue; 1688 } 1689 1690 // Filter out cookies that should not be included for a request to the 1691 // given |url|. HTTP only cookies are filtered depending on the passed 1692 // cookie |options|. 1693 if (!cc->IncludeForRequestURL(url, options)) 1694 continue; 1695 1696 // Add this cookie to the set of matching cookies. Update the access 1697 // time if we've been requested to do so. 1698 if (update_access_time) { 1699 InternalUpdateCookieAccessTime(cc, current); 1700 } 1701 cookies->push_back(cc); 1702 } 1703 } 1704 1705 bool CookieMonster::DeleteAnyEquivalentCookie(const std::string& key, 1706 const CanonicalCookie& ecc, 1707 bool skip_httponly, 1708 bool already_expired) { 1709 lock_.AssertAcquired(); 1710 1711 bool found_equivalent_cookie = false; 1712 bool skipped_httponly = false; 1713 for (CookieMapItPair its = cookies_.equal_range(key); 1714 its.first != its.second; ) { 1715 CookieMap::iterator curit = its.first; 1716 CanonicalCookie* cc = curit->second; 1717 ++its.first; 1718 1719 if (ecc.IsEquivalent(*cc)) { 1720 // We should never have more than one equivalent cookie, since they should 1721 // overwrite each other. 1722 CHECK(!found_equivalent_cookie) << 1723 "Duplicate equivalent cookies found, cookie store is corrupted."; 1724 if (skip_httponly && cc->IsHttpOnly()) { 1725 skipped_httponly = true; 1726 } else { 1727 InternalDeleteCookie(curit, true, already_expired ? 1728 DELETE_COOKIE_EXPIRED_OVERWRITE : DELETE_COOKIE_OVERWRITE); 1729 } 1730 found_equivalent_cookie = true; 1731 } 1732 } 1733 return skipped_httponly; 1734 } 1735 1736 void CookieMonster::InternalInsertCookie(const std::string& key, 1737 CanonicalCookie* cc, 1738 bool sync_to_store) { 1739 lock_.AssertAcquired(); 1740 1741 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get() && 1742 sync_to_store) 1743 store_->AddCookie(*cc); 1744 cookies_.insert(CookieMap::value_type(key, cc)); 1745 if (delegate_.get()) { 1746 delegate_->OnCookieChanged( 1747 *cc, false, CookieMonster::Delegate::CHANGE_COOKIE_EXPLICIT); 1748 } 1749 } 1750 1751 bool CookieMonster::SetCookieWithCreationTimeAndOptions( 1752 const GURL& url, 1753 const std::string& cookie_line, 1754 const Time& creation_time_or_null, 1755 const CookieOptions& options) { 1756 lock_.AssertAcquired(); 1757 1758 VLOG(kVlogSetCookies) << "SetCookie() line: " << cookie_line; 1759 1760 Time creation_time = creation_time_or_null; 1761 if (creation_time.is_null()) { 1762 creation_time = CurrentTime(); 1763 last_time_seen_ = creation_time; 1764 } 1765 1766 scoped_ptr<CanonicalCookie> cc( 1767 CanonicalCookie::Create(url, cookie_line, creation_time, options)); 1768 1769 if (!cc.get()) { 1770 VLOG(kVlogSetCookies) << "WARNING: Failed to allocate CanonicalCookie"; 1771 return false; 1772 } 1773 return SetCanonicalCookie(&cc, creation_time, options); 1774 } 1775 1776 bool CookieMonster::SetCanonicalCookie(scoped_ptr<CanonicalCookie>* cc, 1777 const Time& creation_time, 1778 const CookieOptions& options) { 1779 const std::string key(GetKey((*cc)->Domain())); 1780 bool already_expired = (*cc)->IsExpired(creation_time); 1781 if (DeleteAnyEquivalentCookie(key, **cc, options.exclude_httponly(), 1782 already_expired)) { 1783 VLOG(kVlogSetCookies) << "SetCookie() not clobbering httponly cookie"; 1784 return false; 1785 } 1786 1787 VLOG(kVlogSetCookies) << "SetCookie() key: " << key << " cc: " 1788 << (*cc)->DebugString(); 1789 1790 // Realize that we might be setting an expired cookie, and the only point 1791 // was to delete the cookie which we've already done. 1792 if (!already_expired || keep_expired_cookies_) { 1793 // See InitializeHistograms() for details. 1794 if ((*cc)->IsPersistent()) { 1795 histogram_expiration_duration_minutes_->Add( 1796 ((*cc)->ExpiryDate() - creation_time).InMinutes()); 1797 } 1798 1799 InternalInsertCookie(key, cc->release(), true); 1800 } else { 1801 VLOG(kVlogSetCookies) << "SetCookie() not storing already expired cookie."; 1802 } 1803 1804 // We assume that hopefully setting a cookie will be less common than 1805 // querying a cookie. Since setting a cookie can put us over our limits, 1806 // make sure that we garbage collect... We can also make the assumption that 1807 // if a cookie was set, in the common case it will be used soon after, 1808 // and we will purge the expired cookies in GetCookies(). 1809 GarbageCollect(creation_time, key); 1810 1811 return true; 1812 } 1813 1814 void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc, 1815 const Time& current) { 1816 lock_.AssertAcquired(); 1817 1818 // Based off the Mozilla code. When a cookie has been accessed recently, 1819 // don't bother updating its access time again. This reduces the number of 1820 // updates we do during pageload, which in turn reduces the chance our storage 1821 // backend will hit its batch thresholds and be forced to update. 1822 if ((current - cc->LastAccessDate()) < last_access_threshold_) 1823 return; 1824 1825 // See InitializeHistograms() for details. 1826 histogram_between_access_interval_minutes_->Add( 1827 (current - cc->LastAccessDate()).InMinutes()); 1828 1829 cc->SetLastAccessDate(current); 1830 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get()) 1831 store_->UpdateCookieAccessTime(*cc); 1832 } 1833 1834 void CookieMonster::InternalDeleteCookie(CookieMap::iterator it, 1835 bool sync_to_store, 1836 DeletionCause deletion_cause) { 1837 lock_.AssertAcquired(); 1838 1839 // Ideally, this would be asserted up where we define ChangeCauseMapping, 1840 // but DeletionCause's visibility (or lack thereof) forces us to make 1841 // this check here. 1842 COMPILE_ASSERT(arraysize(ChangeCauseMapping) == DELETE_COOKIE_LAST_ENTRY + 1, 1843 ChangeCauseMapping_size_not_eq_DeletionCause_enum_size); 1844 1845 // See InitializeHistograms() for details. 1846 if (deletion_cause != DELETE_COOKIE_DONT_RECORD) 1847 histogram_cookie_deletion_cause_->Add(deletion_cause); 1848 1849 CanonicalCookie* cc = it->second; 1850 VLOG(kVlogSetCookies) << "InternalDeleteCookie() cc: " << cc->DebugString(); 1851 1852 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get() && 1853 sync_to_store) 1854 store_->DeleteCookie(*cc); 1855 if (delegate_.get()) { 1856 ChangeCausePair mapping = ChangeCauseMapping[deletion_cause]; 1857 1858 if (mapping.notify) 1859 delegate_->OnCookieChanged(*cc, true, mapping.cause); 1860 } 1861 cookies_.erase(it); 1862 delete cc; 1863 } 1864 1865 // Domain expiry behavior is unchanged by key/expiry scheme (the 1866 // meaning of the key is different, but that's not visible to this routine). 1867 int CookieMonster::GarbageCollect(const Time& current, 1868 const std::string& key) { 1869 lock_.AssertAcquired(); 1870 1871 int num_deleted = 0; 1872 Time safe_date( 1873 Time::Now() - TimeDelta::FromDays(kSafeFromGlobalPurgeDays)); 1874 1875 // Collect garbage for this key, minding cookie priorities. 1876 if (cookies_.count(key) > kDomainMaxCookies) { 1877 VLOG(kVlogGarbageCollection) << "GarbageCollect() key: " << key; 1878 1879 CookieItVector cookie_its; 1880 num_deleted += GarbageCollectExpired( 1881 current, cookies_.equal_range(key), &cookie_its); 1882 if (cookie_its.size() > kDomainMaxCookies) { 1883 VLOG(kVlogGarbageCollection) << "Deep Garbage Collect domain."; 1884 size_t purge_goal = 1885 cookie_its.size() - (kDomainMaxCookies - kDomainPurgeCookies); 1886 DCHECK(purge_goal > kDomainPurgeCookies); 1887 1888 // Boundary iterators into |cookie_its| for different priorities. 1889 CookieItVector::iterator it_bdd[4]; 1890 // Intialize |it_bdd| while sorting |cookie_its| by priorities. 1891 // Schematic: [MLLHMHHLMM] => [LLL|MMMM|HHH], with 4 boundaries. 1892 it_bdd[0] = cookie_its.begin(); 1893 it_bdd[3] = cookie_its.end(); 1894 it_bdd[1] = PartitionCookieByPriority(it_bdd[0], it_bdd[3], 1895 COOKIE_PRIORITY_LOW); 1896 it_bdd[2] = PartitionCookieByPriority(it_bdd[1], it_bdd[3], 1897 COOKIE_PRIORITY_MEDIUM); 1898 size_t quota[3] = { 1899 kDomainCookiesQuotaLow, 1900 kDomainCookiesQuotaMedium, 1901 kDomainCookiesQuotaHigh 1902 }; 1903 1904 // Purge domain cookies in 3 rounds. 1905 // Round 1: consider low-priority cookies only: evict least-recently 1906 // accessed, while protecting quota[0] of these from deletion. 1907 // Round 2: consider {low, medium}-priority cookies, evict least-recently 1908 // accessed, while protecting quota[0] + quota[1]. 1909 // Round 3: consider all cookies, evict least-recently accessed. 1910 size_t accumulated_quota = 0; 1911 CookieItVector::iterator it_purge_begin = it_bdd[0]; 1912 for (int i = 0; i < 3 && purge_goal > 0; ++i) { 1913 accumulated_quota += quota[i]; 1914 1915 // If we are not using priority, only do Round 3. This reproduces the 1916 // old way of indiscriminately purging least-recently accessed cookies. 1917 if (!priority_aware_garbage_collection_ && i < 2) 1918 continue; 1919 1920 size_t num_considered = it_bdd[i + 1] - it_purge_begin; 1921 if (num_considered <= accumulated_quota) 1922 continue; 1923 1924 // Number of cookies that will be purged in this round. 1925 size_t round_goal = 1926 std::min(purge_goal, num_considered - accumulated_quota); 1927 purge_goal -= round_goal; 1928 1929 SortLeastRecentlyAccessed(it_purge_begin, it_bdd[i + 1], round_goal); 1930 // Cookies accessed on or after |safe_date| would have been safe from 1931 // global purge, and we want to keep track of this. 1932 CookieItVector::iterator it_purge_end = it_purge_begin + round_goal; 1933 CookieItVector::iterator it_purge_middle = 1934 LowerBoundAccessDate(it_purge_begin, it_purge_end, safe_date); 1935 // Delete cookies accessed before |safe_date|. 1936 num_deleted += GarbageCollectDeleteRange( 1937 current, 1938 DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE, 1939 it_purge_begin, 1940 it_purge_middle); 1941 // Delete cookies accessed on or after |safe_date|. 1942 num_deleted += GarbageCollectDeleteRange( 1943 current, 1944 DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE, 1945 it_purge_middle, 1946 it_purge_end); 1947 it_purge_begin = it_purge_end; 1948 } 1949 DCHECK_EQ(0U, purge_goal); 1950 } 1951 } 1952 1953 // Collect garbage for everything. With firefox style we want to preserve 1954 // cookies accessed in kSafeFromGlobalPurgeDays, otherwise evict. 1955 if (cookies_.size() > kMaxCookies && 1956 earliest_access_time_ < safe_date) { 1957 VLOG(kVlogGarbageCollection) << "GarbageCollect() everything"; 1958 CookieItVector cookie_its; 1959 num_deleted += GarbageCollectExpired( 1960 current, CookieMapItPair(cookies_.begin(), cookies_.end()), 1961 &cookie_its); 1962 if (cookie_its.size() > kMaxCookies) { 1963 VLOG(kVlogGarbageCollection) << "Deep Garbage Collect everything."; 1964 size_t purge_goal = cookie_its.size() - (kMaxCookies - kPurgeCookies); 1965 DCHECK(purge_goal > kPurgeCookies); 1966 // Sorts up to *and including* |cookie_its[purge_goal]|, so 1967 // |earliest_access_time| will be properly assigned even if 1968 // |global_purge_it| == |cookie_its.begin() + purge_goal|. 1969 SortLeastRecentlyAccessed(cookie_its.begin(), cookie_its.end(), 1970 purge_goal); 1971 // Find boundary to cookies older than safe_date. 1972 CookieItVector::iterator global_purge_it = 1973 LowerBoundAccessDate(cookie_its.begin(), 1974 cookie_its.begin() + purge_goal, 1975 safe_date); 1976 // Only delete the old cookies. 1977 num_deleted += GarbageCollectDeleteRange( 1978 current, 1979 DELETE_COOKIE_EVICTED_GLOBAL, 1980 cookie_its.begin(), 1981 global_purge_it); 1982 // Set access day to the oldest cookie that wasn't deleted. 1983 earliest_access_time_ = (*global_purge_it)->second->LastAccessDate(); 1984 } 1985 } 1986 1987 return num_deleted; 1988 } 1989 1990 int CookieMonster::GarbageCollectExpired( 1991 const Time& current, 1992 const CookieMapItPair& itpair, 1993 CookieItVector* cookie_its) { 1994 if (keep_expired_cookies_) 1995 return 0; 1996 1997 lock_.AssertAcquired(); 1998 1999 int num_deleted = 0; 2000 for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) { 2001 CookieMap::iterator curit = it; 2002 ++it; 2003 2004 if (curit->second->IsExpired(current)) { 2005 InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED); 2006 ++num_deleted; 2007 } else if (cookie_its) { 2008 cookie_its->push_back(curit); 2009 } 2010 } 2011 2012 return num_deleted; 2013 } 2014 2015 int CookieMonster::GarbageCollectDeleteRange( 2016 const Time& current, 2017 DeletionCause cause, 2018 CookieMonster::CookieItVector::iterator it_begin, 2019 CookieMonster::CookieItVector::iterator it_end) { 2020 for (CookieItVector::iterator it = it_begin; it != it_end; it++) { 2021 histogram_evicted_last_access_minutes_->Add( 2022 (current - (*it)->second->LastAccessDate()).InMinutes()); 2023 InternalDeleteCookie((*it), true, cause); 2024 } 2025 return it_end - it_begin; 2026 } 2027 2028 // A wrapper around registry_controlled_domains::GetDomainAndRegistry 2029 // to make clear we're creating a key for our local map. Here and 2030 // in FindCookiesForHostAndDomain() are the only two places where 2031 // we need to conditionalize based on key type. 2032 // 2033 // Note that this key algorithm explicitly ignores the scheme. This is 2034 // because when we're entering cookies into the map from the backing store, 2035 // we in general won't have the scheme at that point. 2036 // In practical terms, this means that file cookies will be stored 2037 // in the map either by an empty string or by UNC name (and will be 2038 // limited by kMaxCookiesPerHost), and extension cookies will be stored 2039 // based on the single extension id, as the extension id won't have the 2040 // form of a DNS host and hence GetKey() will return it unchanged. 2041 // 2042 // Arguably the right thing to do here is to make the key 2043 // algorithm dependent on the scheme, and make sure that the scheme is 2044 // available everywhere the key must be obtained (specfically at backing 2045 // store load time). This would require either changing the backing store 2046 // database schema to include the scheme (far more trouble than it's worth), or 2047 // separating out file cookies into their own CookieMonster instance and 2048 // thus restricting each scheme to a single cookie monster (which might 2049 // be worth it, but is still too much trouble to solve what is currently a 2050 // non-problem). 2051 std::string CookieMonster::GetKey(const std::string& domain) const { 2052 std::string effective_domain( 2053 registry_controlled_domains::GetDomainAndRegistry( 2054 domain, registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES)); 2055 if (effective_domain.empty()) 2056 effective_domain = domain; 2057 2058 if (!effective_domain.empty() && effective_domain[0] == '.') 2059 return effective_domain.substr(1); 2060 return effective_domain; 2061 } 2062 2063 bool CookieMonster::IsCookieableScheme(const std::string& scheme) { 2064 base::AutoLock autolock(lock_); 2065 2066 return std::find(cookieable_schemes_.begin(), cookieable_schemes_.end(), 2067 scheme) != cookieable_schemes_.end(); 2068 } 2069 2070 bool CookieMonster::HasCookieableScheme(const GURL& url) { 2071 lock_.AssertAcquired(); 2072 2073 // Make sure the request is on a cookie-able url scheme. 2074 for (size_t i = 0; i < cookieable_schemes_.size(); ++i) { 2075 // We matched a scheme. 2076 if (url.SchemeIs(cookieable_schemes_[i].c_str())) { 2077 // We've matched a supported scheme. 2078 return true; 2079 } 2080 } 2081 2082 // The scheme didn't match any in our whitelist. 2083 VLOG(kVlogPerCookieMonster) << "WARNING: Unsupported cookie scheme: " 2084 << url.scheme(); 2085 return false; 2086 } 2087 2088 // Test to see if stats should be recorded, and record them if so. 2089 // The goal here is to get sampling for the average browser-hour of 2090 // activity. We won't take samples when the web isn't being surfed, 2091 // and when the web is being surfed, we'll take samples about every 2092 // kRecordStatisticsIntervalSeconds. 2093 // last_statistic_record_time_ is initialized to Now() rather than null 2094 // in the constructor so that we won't take statistics right after 2095 // startup, to avoid bias from browsers that are started but not used. 2096 void CookieMonster::RecordPeriodicStats(const base::Time& current_time) { 2097 const base::TimeDelta kRecordStatisticsIntervalTime( 2098 base::TimeDelta::FromSeconds(kRecordStatisticsIntervalSeconds)); 2099 2100 // If we've taken statistics recently, return. 2101 if (current_time - last_statistic_record_time_ <= 2102 kRecordStatisticsIntervalTime) { 2103 return; 2104 } 2105 2106 // See InitializeHistograms() for details. 2107 histogram_count_->Add(cookies_.size()); 2108 2109 // More detailed statistics on cookie counts at different granularities. 2110 TimeTicks beginning_of_time(TimeTicks::Now()); 2111 2112 for (CookieMap::const_iterator it_key = cookies_.begin(); 2113 it_key != cookies_.end(); ) { 2114 const std::string& key(it_key->first); 2115 2116 int key_count = 0; 2117 typedef std::map<std::string, unsigned int> DomainMap; 2118 DomainMap domain_map; 2119 CookieMapItPair its_cookies = cookies_.equal_range(key); 2120 while (its_cookies.first != its_cookies.second) { 2121 key_count++; 2122 const std::string& cookie_domain(its_cookies.first->second->Domain()); 2123 domain_map[cookie_domain]++; 2124 2125 its_cookies.first++; 2126 } 2127 histogram_etldp1_count_->Add(key_count); 2128 histogram_domain_per_etldp1_count_->Add(domain_map.size()); 2129 for (DomainMap::const_iterator domain_map_it = domain_map.begin(); 2130 domain_map_it != domain_map.end(); domain_map_it++) 2131 histogram_domain_count_->Add(domain_map_it->second); 2132 2133 it_key = its_cookies.second; 2134 } 2135 2136 VLOG(kVlogPeriodic) 2137 << "Time for recording cookie stats (us): " 2138 << (TimeTicks::Now() - beginning_of_time).InMicroseconds(); 2139 2140 last_statistic_record_time_ = current_time; 2141 } 2142 2143 // Initialize all histogram counter variables used in this class. 2144 // 2145 // Normal histogram usage involves using the macros defined in 2146 // histogram.h, which automatically takes care of declaring these 2147 // variables (as statics), initializing them, and accumulating into 2148 // them, all from a single entry point. Unfortunately, that solution 2149 // doesn't work for the CookieMonster, as it's vulnerable to races between 2150 // separate threads executing the same functions and hence initializing the 2151 // same static variables. There isn't a race danger in the histogram 2152 // accumulation calls; they are written to be resilient to simultaneous 2153 // calls from multiple threads. 2154 // 2155 // The solution taken here is to have per-CookieMonster instance 2156 // variables that are constructed during CookieMonster construction. 2157 // Note that these variables refer to the same underlying histogram, 2158 // so we still race (but safely) with other CookieMonster instances 2159 // for accumulation. 2160 // 2161 // To do this we've expanded out the individual histogram macros calls, 2162 // with declarations of the variables in the class decl, initialization here 2163 // (done from the class constructor) and direct calls to the accumulation 2164 // methods where needed. The specific histogram macro calls on which the 2165 // initialization is based are included in comments below. 2166 void CookieMonster::InitializeHistograms() { 2167 // From UMA_HISTOGRAM_CUSTOM_COUNTS 2168 histogram_expiration_duration_minutes_ = base::Histogram::FactoryGet( 2169 "Cookie.ExpirationDurationMinutes", 2170 1, kMinutesInTenYears, 50, 2171 base::Histogram::kUmaTargetedHistogramFlag); 2172 histogram_between_access_interval_minutes_ = base::Histogram::FactoryGet( 2173 "Cookie.BetweenAccessIntervalMinutes", 2174 1, kMinutesInTenYears, 50, 2175 base::Histogram::kUmaTargetedHistogramFlag); 2176 histogram_evicted_last_access_minutes_ = base::Histogram::FactoryGet( 2177 "Cookie.EvictedLastAccessMinutes", 2178 1, kMinutesInTenYears, 50, 2179 base::Histogram::kUmaTargetedHistogramFlag); 2180 histogram_count_ = base::Histogram::FactoryGet( 2181 "Cookie.Count", 1, 4000, 50, 2182 base::Histogram::kUmaTargetedHistogramFlag); 2183 histogram_domain_count_ = base::Histogram::FactoryGet( 2184 "Cookie.DomainCount", 1, 4000, 50, 2185 base::Histogram::kUmaTargetedHistogramFlag); 2186 histogram_etldp1_count_ = base::Histogram::FactoryGet( 2187 "Cookie.Etldp1Count", 1, 4000, 50, 2188 base::Histogram::kUmaTargetedHistogramFlag); 2189 histogram_domain_per_etldp1_count_ = base::Histogram::FactoryGet( 2190 "Cookie.DomainPerEtldp1Count", 1, 4000, 50, 2191 base::Histogram::kUmaTargetedHistogramFlag); 2192 2193 // From UMA_HISTOGRAM_COUNTS_10000 & UMA_HISTOGRAM_CUSTOM_COUNTS 2194 histogram_number_duplicate_db_cookies_ = base::Histogram::FactoryGet( 2195 "Net.NumDuplicateCookiesInDb", 1, 10000, 50, 2196 base::Histogram::kUmaTargetedHistogramFlag); 2197 2198 // From UMA_HISTOGRAM_ENUMERATION 2199 histogram_cookie_deletion_cause_ = base::LinearHistogram::FactoryGet( 2200 "Cookie.DeletionCause", 1, 2201 DELETE_COOKIE_LAST_ENTRY - 1, DELETE_COOKIE_LAST_ENTRY, 2202 base::Histogram::kUmaTargetedHistogramFlag); 2203 2204 // From UMA_HISTOGRAM_{CUSTOM_,}TIMES 2205 histogram_time_get_ = base::Histogram::FactoryTimeGet("Cookie.TimeGet", 2206 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1), 2207 50, base::Histogram::kUmaTargetedHistogramFlag); 2208 histogram_time_blocked_on_load_ = base::Histogram::FactoryTimeGet( 2209 "Cookie.TimeBlockedOnLoad", 2210 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1), 2211 50, base::Histogram::kUmaTargetedHistogramFlag); 2212 } 2213 2214 2215 // The system resolution is not high enough, so we can have multiple 2216 // set cookies that result in the same system time. When this happens, we 2217 // increment by one Time unit. Let's hope computers don't get too fast. 2218 Time CookieMonster::CurrentTime() { 2219 return std::max(Time::Now(), 2220 Time::FromInternalValue(last_time_seen_.ToInternalValue() + 1)); 2221 } 2222 2223 } // namespace net 2224