| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Portions of this code based on Mozilla: | 5 // Portions of this code based on Mozilla: |
| 6 // (netwerk/cookie/src/nsCookieService.cpp) | 6 // (netwerk/cookie/src/nsCookieService.cpp) |
| 7 /* ***** BEGIN LICENSE BLOCK ***** | 7 /* ***** BEGIN LICENSE BLOCK ***** |
| 8 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 | 8 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
| 9 * | 9 * |
| 10 * The contents of this file are subject to the Mozilla Public License Version | 10 * The contents of this file are subject to the Mozilla Public License Version |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 #define COOKIE_DLOG(severity) DLOG_IF(INFO, 1) | 61 #define COOKIE_DLOG(severity) DLOG_IF(INFO, 1) |
| 62 #else | 62 #else |
| 63 #define COOKIE_DLOG(severity) DLOG_IF(INFO, 0) | 63 #define COOKIE_DLOG(severity) DLOG_IF(INFO, 0) |
| 64 #endif | 64 #endif |
| 65 | 65 |
| 66 using base::Time; | 66 using base::Time; |
| 67 using base::TimeDelta; | 67 using base::TimeDelta; |
| 68 | 68 |
| 69 namespace net { | 69 namespace net { |
| 70 | 70 |
| 71 |
| 71 // Cookie garbage collection thresholds. Based off of the Mozilla defaults. | 72 // Cookie garbage collection thresholds. Based off of the Mozilla defaults. |
| 72 // It might seem scary to have a high purge value, but really it's not. You | 73 static const size_t kMaxCookiesPerHost = 50; |
| 73 // just make sure that you increase the max to cover the increase in purge, | 74 static const size_t kMaxCookiesTotal = 2000; |
| 74 // and we would have been purging the same amount of cookies. We're just | 75 static const int kMaxCookieAgeSeconds = 30 * 24 * 60 * 60; // 30 days |
| 75 // going through the garbage collection process less often. | 76 static const double kPurgeOverageFactor = 1.1; |
| 76 static const size_t kNumCookiesPerHost = 70; // ~50 cookies | |
| 77 static const size_t kNumCookiesPerHostPurge = 20; | |
| 78 static const size_t kNumCookiesTotal = 3300; // ~3000 cookies | |
| 79 static const size_t kNumCookiesTotalPurge = 300; | |
| 80 | 77 |
| 81 // Default minimum delay after updating a cookie's LastAccessDate before we | 78 // Default minimum delay after updating a cookie's LastAccessDate before we |
| 82 // will update it again. | 79 // will update it again. |
| 83 static const int kDefaultAccessUpdateThresholdSeconds = 60; | 80 static const int kDefaultAccessUpdateThresholdSeconds = 60; |
| 84 | 81 |
| 85 // static | 82 // static |
| 86 bool CookieMonster::enable_file_scheme_ = false; | 83 bool CookieMonster::enable_file_scheme_ = false; |
| 87 | 84 |
| 88 // static | 85 // static |
| 89 void CookieMonster::EnableFileScheme() { | 86 void CookieMonster::EnableFileScheme() { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 111 } | 108 } |
| 112 | 109 |
| 113 void CookieMonster::InitStore() { | 110 void CookieMonster::InitStore() { |
| 114 DCHECK(store_) << "Store must exist to initialize"; | 111 DCHECK(store_) << "Store must exist to initialize"; |
| 115 | 112 |
| 116 // Initialize the store and sync in any saved persistent cookies. We don't | 113 // Initialize the store and sync in any saved persistent cookies. We don't |
| 117 // care if it's expired, insert it so it can be garbage collected, removed, | 114 // care if it's expired, insert it so it can be garbage collected, removed, |
| 118 // and sync'd. | 115 // and sync'd. |
| 119 std::vector<KeyedCanonicalCookie> cookies; | 116 std::vector<KeyedCanonicalCookie> cookies; |
| 120 // Reserve space for the maximum amount of cookies a database should have. | 117 // Reserve space for the maximum amount of cookies a database should have. |
| 121 // This prevents multiple vector growth / copies as we append cookies. | 118 // This prevents multiple vector growth / copies as we append cookies. Note |
| 122 cookies.reserve(kNumCookiesTotal); | 119 // that if we have too many recent cookies, we'll still cross this limit; |
| 123 store_->Load(&cookies); | 120 // however, since std::vector<> grows by 50% when inserting a new element |
| 121 // into a full vector, we should have few of these additional resizes. |
| 122 cookies.reserve(static_cast<int>(kMaxCookiesTotal * kPurgeOverageFactor)); |
| 123 store_->Load(&cookies, &least_recent_access_); |
| 124 for (std::vector<KeyedCanonicalCookie>::const_iterator it = cookies.begin(); | 124 for (std::vector<KeyedCanonicalCookie>::const_iterator it = cookies.begin(); |
| 125 it != cookies.end(); ++it) { | 125 it != cookies.end(); ++it) { |
| 126 InternalInsertCookie(it->first, it->second, false); | 126 InternalInsertCookie(it->first, it->second, false); |
| 127 } | 127 } |
| 128 } | 128 } |
| 129 | 129 |
| 130 void CookieMonster::SetDefaultCookieableSchemes() { | 130 void CookieMonster::SetDefaultCookieableSchemes() { |
| 131 // Note: file must be the last scheme. | 131 // Note: file must be the last scheme. |
| 132 static const char* kDefaultCookieableSchemes[] = { "http", "https", "file" }; | 132 static const char* kDefaultCookieableSchemes[] = { "http", "https", "file" }; |
| 133 int num_schemes = enable_file_scheme_ ? 3 : 2; | 133 int num_schemes = enable_file_scheme_ ? 3 : 2; |
| (...skipping 375 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 509 iter != cookies.end(); ++iter) | 509 iter != cookies.end(); ++iter) |
| 510 SetCookieWithOptions(url, *iter, options); | 510 SetCookieWithOptions(url, *iter, options); |
| 511 } | 511 } |
| 512 | 512 |
| 513 void CookieMonster::InternalInsertCookie(const std::string& key, | 513 void CookieMonster::InternalInsertCookie(const std::string& key, |
| 514 CanonicalCookie* cc, | 514 CanonicalCookie* cc, |
| 515 bool sync_to_store) { | 515 bool sync_to_store) { |
| 516 if (cc->IsPersistent() && store_ && sync_to_store) | 516 if (cc->IsPersistent() && store_ && sync_to_store) |
| 517 store_->AddCookie(key, *cc); | 517 store_->AddCookie(key, *cc); |
| 518 cookies_.insert(CookieMap::value_type(key, cc)); | 518 cookies_.insert(CookieMap::value_type(key, cc)); |
| 519 const Time last_access = cc->LastAccessDate(); |
| 520 if (least_recent_access_.is_null() || (last_access < least_recent_access_)) |
| 521 least_recent_access_ = last_access; |
| 519 } | 522 } |
| 520 | 523 |
| 521 void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc) { | 524 void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc) { |
| 522 // Based off the Mozilla code. When a cookie has been accessed recently, | 525 // Based off the Mozilla code. When a cookie has been accessed recently, |
| 523 // don't bother updating its access time again. This reduces the number of | 526 // don't bother updating its access time again. This reduces the number of |
| 524 // updates we do during pageload, which in turn reduces the chance our storage | 527 // updates we do during pageload, which in turn reduces the chance our storage |
| 525 // backend will hit its batch thresholds and be forced to update. | 528 // backend will hit its batch thresholds and be forced to update. |
| 526 const Time current = Time::Now(); | 529 const Time current = Time::Now(); |
| 527 if ((current - cc->LastAccessDate()) < last_access_threshold_) | 530 if ((current - cc->LastAccessDate()) < last_access_threshold_) |
| 528 return; | 531 return; |
| 529 | 532 |
| 530 cc->SetLastAccessDate(current); | 533 cc->SetLastAccessDate(current); |
| 531 if (cc->IsPersistent() && store_) | 534 if (cc->IsPersistent() && store_) |
| 532 store_->UpdateCookieAccessTime(*cc); | 535 store_->UpdateCookieAccessTime(*cc); |
| 536 if (least_recent_access_.is_null() || (current < least_recent_access_)) |
| 537 least_recent_access_ = current; |
| 533 } | 538 } |
| 534 | 539 |
| 535 void CookieMonster::InternalDeleteCookie(CookieMap::iterator it, | 540 void CookieMonster::InternalDeleteCookie(CookieMap::iterator it, |
| 536 bool sync_to_store) { | 541 bool sync_to_store) { |
| 537 CanonicalCookie* cc = it->second; | 542 CanonicalCookie* cc = it->second; |
| 538 COOKIE_DLOG(INFO) << "InternalDeleteCookie() cc: " << cc->DebugString(); | 543 COOKIE_DLOG(INFO) << "InternalDeleteCookie() cc: " << cc->DebugString(); |
| 539 if (cc->IsPersistent() && store_ && sync_to_store) | 544 if (cc->IsPersistent() && store_ && sync_to_store) |
| 540 store_->DeleteCookie(*cc); | 545 store_->DeleteCookie(*cc); |
| 541 cookies_.erase(it); | 546 cookies_.erase(it); |
| 542 delete cc; | 547 delete cc; |
| (...skipping 29 matching lines...) Expand all Loading... |
| 572 } | 577 } |
| 573 } | 578 } |
| 574 return skipped_httponly; | 579 return skipped_httponly; |
| 575 } | 580 } |
| 576 | 581 |
| 577 int CookieMonster::GarbageCollect(const Time& current, | 582 int CookieMonster::GarbageCollect(const Time& current, |
| 578 const std::string& key) { | 583 const std::string& key) { |
| 579 int num_deleted = 0; | 584 int num_deleted = 0; |
| 580 | 585 |
| 581 // Collect garbage for this key. | 586 // Collect garbage for this key. |
| 582 if (cookies_.count(key) > kNumCookiesPerHost) { | 587 if (cookies_.count(key) >= (kMaxCookiesPerHost * kPurgeOverageFactor)) { |
| 583 COOKIE_DLOG(INFO) << "GarbageCollect() key: " << key; | 588 COOKIE_DLOG(INFO) << "GarbageCollect() key: " << key; |
| 584 num_deleted += GarbageCollectRange(current, cookies_.equal_range(key), | 589 num_deleted += GarbageCollectRange(current, cookies_.equal_range(key), |
| 585 kNumCookiesPerHost, kNumCookiesPerHostPurge); | 590 kMaxCookiesPerHost, TimeDelta()); |
| 586 } | 591 } |
| 587 | 592 |
| 588 // Collect garbage for everything. | 593 // Collect garbage for everything. |
| 589 if (cookies_.size() > kNumCookiesTotal) { | 594 if ((cookies_.size() >= (kMaxCookiesTotal * kPurgeOverageFactor)) && |
| 595 (least_recent_access_.is_null() || |
| 596 ((current - least_recent_access_) >= |
| 597 TimeDelta::FromSeconds(static_cast<int>(kMaxCookieAgeSeconds * |
| 598 kPurgeOverageFactor))))) { |
| 590 COOKIE_DLOG(INFO) << "GarbageCollect() everything"; | 599 COOKIE_DLOG(INFO) << "GarbageCollect() everything"; |
| 591 num_deleted += GarbageCollectRange(current, | 600 num_deleted += GarbageCollectRange(current, |
| 592 CookieMapItPair(cookies_.begin(), cookies_.end()), kNumCookiesTotal, | 601 CookieMapItPair(cookies_.begin(), cookies_.end()), kMaxCookiesTotal, |
| 593 kNumCookiesTotalPurge); | 602 TimeDelta::FromSeconds(kMaxCookieAgeSeconds)); |
| 594 } | 603 } |
| 595 | 604 |
| 596 return num_deleted; | 605 return num_deleted; |
| 597 } | 606 } |
| 598 | 607 |
| 599 static bool LRUCookieSorter(const CookieMonster::CookieMap::iterator& it1, | 608 static bool LRUCookieSorter(const CookieMonster::CookieMap::iterator& it1, |
| 600 const CookieMonster::CookieMap::iterator& it2) { | 609 const CookieMonster::CookieMap::iterator& it2) { |
| 601 // Cookies accessed less recently should be deleted first. | 610 // Cookies accessed less recently should be deleted first. |
| 602 if (it1->second->LastAccessDate() != it2->second->LastAccessDate()) | 611 if (it1->second->LastAccessDate() != it2->second->LastAccessDate()) |
| 603 return it1->second->LastAccessDate() < it2->second->LastAccessDate(); | 612 return it1->second->LastAccessDate() < it2->second->LastAccessDate(); |
| 604 | 613 |
| 605 // In rare cases we might have two cookies with identical last access times. | 614 // In rare cases we might have two cookies with identical last access times. |
| 606 // To preserve the stability of the sort, in these cases prefer to delete | 615 // To preserve the stability of the sort, in these cases prefer to delete |
| 607 // older cookies over newer ones. CreationDate() is guaranteed to be unique. | 616 // older cookies over newer ones. CreationDate() is guaranteed to be unique. |
| 608 return it1->second->CreationDate() < it2->second->CreationDate(); | 617 return it1->second->CreationDate() < it2->second->CreationDate(); |
| 609 } | 618 } |
| 610 | 619 |
| 611 int CookieMonster::GarbageCollectRange(const Time& current, | 620 int CookieMonster::GarbageCollectRange(const Time& current, |
| 612 const CookieMapItPair& itpair, | 621 const CookieMapItPair& itpair, |
| 613 size_t num_max, | 622 size_t max_cookies, |
| 614 size_t num_purge) { | 623 const TimeDelta& purge_age) { |
| 615 // First, delete anything that's expired. | 624 // First, delete anything that's expired. |
| 616 std::vector<CookieMap::iterator> cookie_its; | 625 std::vector<CookieMap::iterator> cookie_its; |
| 617 int num_deleted = GarbageCollectExpired(current, itpair, &cookie_its); | 626 int num_deleted = GarbageCollectExpired(current, itpair, &cookie_its); |
| 618 | 627 |
| 619 // If the range still has too many cookies, delete the least recently used. | 628 // If the range still has too many cookies, delete the least recently used. |
| 620 if (cookie_its.size() > num_max) { | 629 if (cookie_its.size() > max_cookies) { |
| 621 COOKIE_DLOG(INFO) << "GarbageCollectRange() Deep Garbage Collect."; | 630 COOKIE_DLOG(INFO) << "GarbageCollectRange() Deep Garbage Collect."; |
| 622 // Purge down to (|num_max| - |num_purge|) total cookies. | 631 // Purge down to |max_cookies| total cookies. |
| 623 DCHECK(num_purge <= num_max); | 632 size_t num_purge = cookie_its.size() - max_cookies; |
| 624 num_purge += cookie_its.size() - num_max; | |
| 625 | 633 |
| 626 std::partial_sort(cookie_its.begin(), cookie_its.begin() + num_purge, | 634 std::partial_sort(cookie_its.begin(), |
| 627 cookie_its.end(), LRUCookieSorter); | 635 cookie_its.begin() + std::min(cookie_its.size(), num_purge + 1), |
| 628 for (size_t i = 0; i < num_purge; ++i) | 636 cookie_its.end(), LRUCookieSorter); |
| 637 const bool only_purge_old_cookies = (purge_age != TimeDelta()); |
| 638 for (size_t i = 0; i < num_purge;) { |
| 639 // Stop purging once we've run out of cookies that are "old enough". |
| 640 if (only_purge_old_cookies && |
| 641 ((current - cookie_its[i]->second->LastAccessDate()) < purge_age)) |
| 642 return num_deleted + i; |
| 643 |
| 629 InternalDeleteCookie(cookie_its[i], true); | 644 InternalDeleteCookie(cookie_its[i], true); |
| 630 | 645 |
| 646 // Update least_recent_access_ now that we've deleted the LRU cookie. |
| 647 ++i; |
| 648 if (i < cookie_its.size()) |
| 649 least_recent_access_ = cookie_its[i]->second->LastAccessDate(); |
| 650 } |
| 651 |
| 631 num_deleted += num_purge; | 652 num_deleted += num_purge; |
| 632 } | 653 } |
| 633 | 654 |
| 634 return num_deleted; | 655 return num_deleted; |
| 635 } | 656 } |
| 636 | 657 |
| 637 int CookieMonster::GarbageCollectExpired( | 658 int CookieMonster::GarbageCollectExpired( |
| 638 const Time& current, | 659 const Time& current, |
| 639 const CookieMapItPair& itpair, | 660 const CookieMapItPair& itpair, |
| 640 std::vector<CookieMap::iterator>* cookie_its) { | 661 std::vector<CookieMap::iterator>* cookie_its) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 659 InitIfNecessary(); | 680 InitIfNecessary(); |
| 660 | 681 |
| 661 int num_deleted = 0; | 682 int num_deleted = 0; |
| 662 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) { | 683 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) { |
| 663 CookieMap::iterator curit = it; | 684 CookieMap::iterator curit = it; |
| 664 ++it; | 685 ++it; |
| 665 InternalDeleteCookie(curit, sync_to_store); | 686 InternalDeleteCookie(curit, sync_to_store); |
| 666 ++num_deleted; | 687 ++num_deleted; |
| 667 } | 688 } |
| 668 | 689 |
| 690 least_recent_access_ = Time(); |
| 691 |
| 669 return num_deleted; | 692 return num_deleted; |
| 670 } | 693 } |
| 671 | 694 |
| 672 int CookieMonster::DeleteAllCreatedBetween(const Time& delete_begin, | 695 int CookieMonster::DeleteAllCreatedBetween(const Time& delete_begin, |
| 673 const Time& delete_end, | 696 const Time& delete_end, |
| 674 bool sync_to_store) { | 697 bool sync_to_store) { |
| 675 AutoLock autolock(lock_); | 698 AutoLock autolock(lock_); |
| 676 InitIfNecessary(); | 699 InitIfNecessary(); |
| 677 | 700 |
| 678 int num_deleted = 0; | 701 int num_deleted = 0; |
| (...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1124 return true; | 1147 return true; |
| 1125 } | 1148 } |
| 1126 | 1149 |
| 1127 std::string CookieMonster::CanonicalCookie::DebugString() const { | 1150 std::string CookieMonster::CanonicalCookie::DebugString() const { |
| 1128 return StringPrintf("name: %s value: %s path: %s creation: %llu", | 1151 return StringPrintf("name: %s value: %s path: %s creation: %llu", |
| 1129 name_.c_str(), value_.c_str(), path_.c_str(), | 1152 name_.c_str(), value_.c_str(), path_.c_str(), |
| 1130 creation_date_.ToTimeT()); | 1153 creation_date_.ToTimeT()); |
| 1131 } | 1154 } |
| 1132 | 1155 |
| 1133 } // namespace | 1156 } // namespace |
| OLD | NEW |