Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 178 DCHECK(store_) << "Store must exist to initialize"; | 178 DCHECK(store_) << "Store must exist to initialize"; |
| 179 | 179 |
| 180 // Initialize the store and sync in any saved persistent cookies. We don't | 180 // Initialize the store and sync in any saved persistent cookies. We don't |
| 181 // care if it's expired, insert it so it can be garbage collected, removed, | 181 // care if it's expired, insert it so it can be garbage collected, removed, |
| 182 // and sync'd. | 182 // and sync'd. |
| 183 std::vector<KeyedCanonicalCookie> cookies; | 183 std::vector<KeyedCanonicalCookie> cookies; |
| 184 // Reserve space for the maximum amount of cookies a database should have. | 184 // Reserve space for the maximum amount of cookies a database should have. |
| 185 // This prevents multiple vector growth / copies as we append cookies. | 185 // This prevents multiple vector growth / copies as we append cookies. |
| 186 cookies.reserve(kNumCookiesTotal); | 186 cookies.reserve(kNumCookiesTotal); |
| 187 store_->Load(&cookies); | 187 store_->Load(&cookies); |
| 188 | |
| 189 // Avoid ever letting cookies with duplicate creation times into the store; | |
| 190 // that way we don't have to worry about what sections of code are safe | |
| 191 // to call while it's in that state. | |
| 192 std::set<int64> creation_times; | |
| 188 for (std::vector<KeyedCanonicalCookie>::const_iterator it = cookies.begin(); | 193 for (std::vector<KeyedCanonicalCookie>::const_iterator it = cookies.begin(); |
| 189 it != cookies.end(); ++it) { | 194 it != cookies.end(); ++it) { |
| 190 InternalInsertCookie(it->first, it->second, false); | 195 int64 cookie_creation_time = it->second->CreationDate().ToInternalValue(); |
| 196 | |
| 197 if (creation_times.insert(cookie_creation_time).second) { | |
| 198 InternalInsertCookie(it->first, it->second, false); | |
| 199 } else { | |
| 200 LOG(ERROR) << StringPrintf("Found cookies with duplicate creation " | |
| 201 "times in backing store: " | |
| 202 "{name='%s', domain='%s', path='%s'}", | |
| 203 it->second->Name().c_str(), | |
| 204 it->first.c_str(), | |
| 205 it->second->Path().c_str()); | |
| 206 } | |
| 191 } | 207 } |
| 192 | 208 |
| 193 // After importing cookies from the PersistentCookieStore, verify that | 209 // After importing cookies from the PersistentCookieStore, verify that |
| 194 // none of our constraints are violated. | 210 // none of our other constraints are violated. |
| 195 // | 211 // |
| 196 // In particular, the backing store might have given us duplicate cookies. | 212 // In particular, the backing store might have given us duplicate cookies. |
| 197 EnsureCookiesMapIsValid(); | 213 EnsureCookiesMapIsValid(); |
| 198 } | 214 } |
| 199 | 215 |
| 200 void CookieMonster::EnsureCookiesMapIsValid() { | 216 void CookieMonster::EnsureCookiesMapIsValid() { |
| 201 lock_.AssertAcquired(); | 217 lock_.AssertAcquired(); |
| 202 | 218 |
| 203 int num_duplicates_trimmed = 0; | 219 int num_duplicates_trimmed = 0; |
| 204 | 220 |
| 205 // Iterate through all the of the cookies, grouped by host. | 221 // Iterate through all the of the cookies, grouped by host. |
| 206 CookieMap::iterator prev_range_end = cookies_.begin(); | 222 CookieMap::iterator prev_range_end = cookies_.begin(); |
| 207 while (prev_range_end != cookies_.end()) { | 223 while (prev_range_end != cookies_.end()) { |
| 208 CookieMap::iterator cur_range_begin = prev_range_end; | 224 CookieMap::iterator cur_range_begin = prev_range_end; |
| 209 const std::string key = cur_range_begin->first; // Keep a copy. | 225 const std::string key = cur_range_begin->first; // Keep a copy. |
| 210 CookieMap::iterator cur_range_end = cookies_.upper_bound(key); | 226 CookieMap::iterator cur_range_end = cookies_.upper_bound(key); |
| 211 prev_range_end = cur_range_end; | 227 prev_range_end = cur_range_end; |
| 212 | 228 |
| 213 // Ensure no equivalent cookies for this host. | 229 // Ensure no equivalent cookies for this host. |
| 214 num_duplicates_trimmed += | 230 num_duplicates_trimmed += |
| 215 TrimDuplicateCookiesForHost(key, cur_range_begin, cur_range_end); | 231 TrimDuplicateCookiesForHost(key, cur_range_begin, cur_range_end); |
| 216 } | 232 } |
| 217 | 233 |
| 218 // Record how many duplicates were found in the database. | 234 // Record how many duplicates were found in the database. |
| 219 // See InitializeHistograms() for details. | 235 // See InitializeHistograms() for details. |
| 220 histogram_cookie_deletion_cause_->Add(num_duplicates_trimmed); | 236 histogram_cookie_deletion_cause_->Add(num_duplicates_trimmed); |
| 221 | |
| 222 // TODO(eroman): Should also verify that there are no cookies with the same | |
| 223 // creation time, since that is assumed to be unique by the rest of the code. | |
| 224 } | 237 } |
| 225 | 238 |
| 226 // Our strategy to find duplicates is: | 239 // Our strategy to find duplicates is: |
| 227 // (1) Build a map from (cookiename, cookiepath) to | 240 // (1) Build a map from (cookiename, cookiepath) to |
| 228 // {list of cookies with this signature, sorted by creation time}. | 241 // {list of cookies with this signature, sorted by creation time}. |
| 229 // (2) For each list with more than 1 entry, keep the cookie having the | 242 // (2) For each list with more than 1 entry, keep the cookie having the |
| 230 // most recent creation time, and delete the others. | 243 // most recent creation time, and delete the others. |
| 231 namespace { | 244 namespace { |
| 232 // Two cookies are considered equivalent if they have the same domain, | 245 // Two cookies are considered equivalent if they have the same domain, |
| 233 // name, and path. | 246 // name, and path. |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 287 CookieSignature signature(cookie->Name(), cookie->Domain(), | 300 CookieSignature signature(cookie->Name(), cookie->Domain(), |
| 288 cookie->Path()); | 301 cookie->Path()); |
| 289 CookieSet& list = equivalent_cookies[signature]; | 302 CookieSet& list = equivalent_cookies[signature]; |
| 290 | 303 |
| 291 // We found a duplicate! | 304 // We found a duplicate! |
| 292 if (!list.empty()) | 305 if (!list.empty()) |
| 293 num_duplicates++; | 306 num_duplicates++; |
| 294 | 307 |
| 295 // We save the iterator into |cookies_| rather than the actual cookie | 308 // We save the iterator into |cookies_| rather than the actual cookie |
| 296 // pointer, since we may need to delete it later. | 309 // pointer, since we may need to delete it later. |
| 297 list.insert(it); | 310 bool insert_success = list.insert(it).second; |
| 311 DCHECK(insert_success) << | |
| 312 "Duplicate creation times found in duplicate cookie name scan."; | |
| 298 } | 313 } |
| 299 | 314 |
| 300 // If there were no duplicates, we are done! | 315 // If there were no duplicates, we are done! |
| 301 if (num_duplicates == 0) | 316 if (num_duplicates == 0) |
| 302 return 0; | 317 return 0; |
| 303 | 318 |
| 319 // Make sure we find everything below that we did above. | |
| 320 int num_duplicates_found = 0; | |
| 321 | |
| 304 // Otherwise, delete all the duplicate cookies, both from our in-memory store | 322 // Otherwise, delete all the duplicate cookies, both from our in-memory store |
| 305 // and from the backing store. | 323 // and from the backing store. |
| 306 for (EquivalenceMap::iterator it = equivalent_cookies.begin(); | 324 for (EquivalenceMap::iterator it = equivalent_cookies.begin(); |
| 307 it != equivalent_cookies.end(); | 325 it != equivalent_cookies.end(); |
| 308 ++it) { | 326 ++it) { |
| 309 const CookieSignature& signature = it->first; | 327 const CookieSignature& signature = it->first; |
| 310 CookieSet& dupes = it->second; | 328 CookieSet& dupes = it->second; |
| 311 | 329 |
| 312 if (dupes.size() <= 1) | 330 if (dupes.size() <= 1) |
| 313 continue; // This cookiename/path has no duplicates. | 331 continue; // This cookiename/path has no duplicates. |
| 332 num_duplicates_found += dupes.size() - 1; | |
| 314 | 333 |
| 315 // Since |dups| is sorted by creation time (descending), the first cookie | 334 // Since |dups| is sorted by creation time (descending), the first cookie |
| 316 // is the most recent one, so we will keep it. The rest are duplicates. | 335 // is the most recent one, so we will keep it. The rest are duplicates. |
| 317 dupes.erase(dupes.begin()); | 336 dupes.erase(dupes.begin()); |
| 318 | 337 |
| 319 LOG(ERROR) << StringPrintf("Found %d duplicate cookies for host='%s', " | 338 LOG(ERROR) << StringPrintf("Found %d duplicate cookies for host='%s', " |
| 320 "with {name='%s', domain='%s', path='%s'}", | 339 "with {name='%s', domain='%s', path='%s'}", |
| 321 static_cast<int>(dupes.size()), | 340 static_cast<int>(dupes.size()), |
| 322 key.c_str(), | 341 key.c_str(), |
| 323 signature.name.c_str(), | 342 signature.name.c_str(), |
| 324 signature.domain.c_str(), | 343 signature.domain.c_str(), |
| 325 signature.path.c_str()); | 344 signature.path.c_str()); |
| 326 | 345 |
| 327 // Remove all the cookies identified by |dupes|. It is valid to delete our | 346 // Remove all the cookies identified by |dupes|. It is valid to delete our |
| 328 // list of iterators one at a time, since |cookies_| is a multimap (they | 347 // list of iterators one at a time, since |cookies_| is a multimap (they |
| 329 // don't invalidate existing iterators following deletion). | 348 // don't invalidate existing iterators following deletion). |
| 330 for (CookieSet::iterator dupes_it = dupes.begin(); | 349 for (CookieSet::iterator dupes_it = dupes.begin(); |
| 331 dupes_it != dupes.end(); | 350 dupes_it != dupes.end(); |
| 332 ++dupes_it) { | 351 ++dupes_it) { |
| 333 InternalDeleteCookie(*dupes_it, true /*sync_to_store*/, | 352 InternalDeleteCookie(*dupes_it, true /*sync_to_store*/, |
| 334 DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE); | 353 DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE); |
| 335 } | 354 } |
| 336 } | 355 } |
| 356 DCHECK_EQ(num_duplicates, num_duplicates_found); | |
| 337 | 357 |
| 338 return num_duplicates; | 358 return num_duplicates; |
| 339 } | 359 } |
| 340 | 360 |
| 341 void CookieMonster::SetDefaultCookieableSchemes() { | 361 void CookieMonster::SetDefaultCookieableSchemes() { |
| 342 // Note: file must be the last scheme. | 362 // Note: file must be the last scheme. |
| 343 static const char* kDefaultCookieableSchemes[] = { "http", "https", "file" }; | 363 static const char* kDefaultCookieableSchemes[] = { "http", "https", "file" }; |
| 344 int num_schemes = enable_file_scheme_ ? 3 : 2; | 364 int num_schemes = enable_file_scheme_ ? 3 : 2; |
| 345 SetCookieableSchemes(kDefaultCookieableSchemes, num_schemes); | 365 SetCookieableSchemes(kDefaultCookieableSchemes, num_schemes); |
| 346 } | 366 } |
| (...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 647 cookieable_schemes_.clear(); | 667 cookieable_schemes_.clear(); |
| 648 cookieable_schemes_.insert(cookieable_schemes_.end(), | 668 cookieable_schemes_.insert(cookieable_schemes_.end(), |
| 649 schemes, schemes + num_schemes); | 669 schemes, schemes + num_schemes); |
| 650 } | 670 } |
| 651 | 671 |
| 652 bool CookieMonster::SetCookieWithCreationTimeAndOptions( | 672 bool CookieMonster::SetCookieWithCreationTimeAndOptions( |
| 653 const GURL& url, | 673 const GURL& url, |
| 654 const std::string& cookie_line, | 674 const std::string& cookie_line, |
| 655 const Time& creation_time_or_null, | 675 const Time& creation_time_or_null, |
| 656 const CookieOptions& options) { | 676 const CookieOptions& options) { |
| 657 AutoLock autolock(lock_); | 677 lock_.AssertAcquired(); |
| 658 | |
| 659 if (!HasCookieableScheme(url)) { | |
| 660 return false; | |
| 661 } | |
| 662 | |
| 663 InitIfNecessary(); | |
| 664 | 678 |
| 665 COOKIE_DLOG(INFO) << "SetCookie() line: " << cookie_line; | 679 COOKIE_DLOG(INFO) << "SetCookie() line: " << cookie_line; |
| 666 | 680 |
| 667 Time creation_time = creation_time_or_null; | 681 Time creation_time = creation_time_or_null; |
| 668 if (creation_time.is_null()) { | 682 if (creation_time.is_null()) { |
| 669 creation_time = CurrentTime(); | 683 creation_time = CurrentTime(); |
| 670 last_time_seen_ = creation_time; | 684 last_time_seen_ = creation_time; |
| 671 } | 685 } |
| 672 | 686 |
| 673 // Parse the cookie. | 687 // Parse the cookie. |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 699 creation_time, creation_time, | 713 creation_time, creation_time, |
| 700 !cookie_expires.is_null(), cookie_expires)); | 714 !cookie_expires.is_null(), cookie_expires)); |
| 701 | 715 |
| 702 if (!cc.get()) { | 716 if (!cc.get()) { |
| 703 COOKIE_DLOG(WARNING) << "Failed to allocate CanonicalCookie"; | 717 COOKIE_DLOG(WARNING) << "Failed to allocate CanonicalCookie"; |
| 704 return false; | 718 return false; |
| 705 } | 719 } |
| 706 return SetCanonicalCookie(&cc, creation_time, options); | 720 return SetCanonicalCookie(&cc, creation_time, options); |
| 707 } | 721 } |
| 708 | 722 |
| 723 bool CookieMonster::SetCookieWithCreationTime(const GURL& url, | |
| 724 const std::string& cookie_line, | |
| 725 const base::Time& creation_time) { | |
| 726 AutoLock autolock(lock_); | |
| 727 | |
| 728 if (!HasCookieableScheme(url)) { | |
| 729 return false; | |
| 730 } | |
| 731 | |
| 732 InitIfNecessary(); | |
| 733 return SetCookieWithCreationTimeAndOptions(url, cookie_line, creation_time, | |
| 734 CookieOptions()); | |
| 735 } | |
| 736 | |
| 709 bool CookieMonster::SetCookieWithDetails( | 737 bool CookieMonster::SetCookieWithDetails( |
| 710 const GURL& url, const std::string& name, const std::string& value, | 738 const GURL& url, const std::string& name, const std::string& value, |
| 711 const std::string& domain, const std::string& path, | 739 const std::string& domain, const std::string& path, |
| 712 const base::Time& expiration_time, bool secure, bool http_only) { | 740 const base::Time& expiration_time, bool secure, bool http_only) { |
| 713 | 741 |
| 714 AutoLock autolock(lock_); | 742 AutoLock autolock(lock_); |
| 715 | 743 |
| 716 if (!HasCookieableScheme(url)) | 744 if (!HasCookieableScheme(url)) |
| 717 return false; | 745 return false; |
| 718 | 746 |
| (...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1023 static bool CookieSorter(CookieMonster::CanonicalCookie* cc1, | 1051 static bool CookieSorter(CookieMonster::CanonicalCookie* cc1, |
| 1024 CookieMonster::CanonicalCookie* cc2) { | 1052 CookieMonster::CanonicalCookie* cc2) { |
| 1025 if (cc1->Path().length() == cc2->Path().length()) | 1053 if (cc1->Path().length() == cc2->Path().length()) |
| 1026 return cc1->CreationDate() < cc2->CreationDate(); | 1054 return cc1->CreationDate() < cc2->CreationDate(); |
| 1027 return cc1->Path().length() > cc2->Path().length(); | 1055 return cc1->Path().length() > cc2->Path().length(); |
| 1028 } | 1056 } |
| 1029 | 1057 |
| 1030 bool CookieMonster::SetCookieWithOptions(const GURL& url, | 1058 bool CookieMonster::SetCookieWithOptions(const GURL& url, |
| 1031 const std::string& cookie_line, | 1059 const std::string& cookie_line, |
| 1032 const CookieOptions& options) { | 1060 const CookieOptions& options) { |
| 1061 AutoLock autolock(lock_); | |
|
ahendrickson
2010/07/27 19:15:37
I'm curious about why you moved this section (and
Randy Smith (Not in Mondays)
2010/07/27 20:11:47
Historically, all of the functions that took the C
| |
| 1062 | |
| 1063 if (!HasCookieableScheme(url)) { | |
| 1064 return false; | |
| 1065 } | |
| 1066 | |
| 1067 InitIfNecessary(); | |
| 1068 | |
| 1033 return SetCookieWithCreationTimeAndOptions(url, cookie_line, Time(), options); | 1069 return SetCookieWithCreationTimeAndOptions(url, cookie_line, Time(), options); |
| 1034 } | 1070 } |
| 1035 | 1071 |
| 1036 // Currently our cookie datastructure is based on Mozilla's approach. We have a | 1072 // Currently our cookie datastructure is based on Mozilla's approach. We have a |
| 1037 // hash keyed on the cookie's domain, and for any query we walk down the domain | 1073 // hash keyed on the cookie's domain, and for any query we walk down the domain |
| 1038 // components and probe for cookies until we reach the TLD, where we stop. | 1074 // components and probe for cookies until we reach the TLD, where we stop. |
| 1039 // For example, a.b.blah.com, we would probe | 1075 // For example, a.b.blah.com, we would probe |
| 1040 // - a.b.blah.com | 1076 // - a.b.blah.com |
| 1041 // - .a.b.blah.com (TODO should we check this first or second?) | 1077 // - .a.b.blah.com (TODO should we check this first or second?) |
| 1042 // - .b.blah.com | 1078 // - .b.blah.com |
| (...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1639 std::string CookieMonster::CanonicalCookie::DebugString() const { | 1675 std::string CookieMonster::CanonicalCookie::DebugString() const { |
| 1640 return StringPrintf("name: %s value: %s domain: %s path: %s creation: %" | 1676 return StringPrintf("name: %s value: %s domain: %s path: %s creation: %" |
| 1641 PRId64, | 1677 PRId64, |
| 1642 name_.c_str(), value_.c_str(), | 1678 name_.c_str(), value_.c_str(), |
| 1643 domain_.c_str(), path_.c_str(), | 1679 domain_.c_str(), path_.c_str(), |
| 1644 static_cast<int64>(creation_date_.ToTimeT())); | 1680 static_cast<int64>(creation_date_.ToTimeT())); |
| 1645 } | 1681 } |
| 1646 | 1682 |
| 1647 } // namespace | 1683 } // namespace |
| 1648 | 1684 |
| OLD | NEW |