| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 1059 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1070 | 1070 |
| 1071 if (!last_access_time.is_null()) | 1071 if (!last_access_time.is_null()) |
| 1072 cc->SetLastAccessDate(last_access_time); | 1072 cc->SetLastAccessDate(last_access_time); |
| 1073 | 1073 |
| 1074 CookieOptions options; | 1074 CookieOptions options; |
| 1075 options.set_include_httponly(); | 1075 options.set_include_httponly(); |
| 1076 options.set_same_site_cookie_mode( | 1076 options.set_same_site_cookie_mode( |
| 1077 CookieOptions::SameSiteCookieMode::INCLUDE_STRICT_AND_LAX); | 1077 CookieOptions::SameSiteCookieMode::INCLUDE_STRICT_AND_LAX); |
| 1078 if (enforce_strict_secure) | 1078 if (enforce_strict_secure) |
| 1079 options.set_enforce_strict_secure(); | 1079 options.set_enforce_strict_secure(); |
| 1080 return SetCanonicalCookie(std::move(cc), options); | 1080 return SetCanonicalCookie(std::move(cc), url, options); |
| 1081 } | 1081 } |
| 1082 | 1082 |
| 1083 CookieList CookieMonster::GetAllCookies() { | 1083 CookieList CookieMonster::GetAllCookies() { |
| 1084 DCHECK(thread_checker_.CalledOnValidThread()); | 1084 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1085 | 1085 |
| 1086 // This function is being called to scrape the cookie list for management UI | 1086 // This function is being called to scrape the cookie list for management UI |
| 1087 // or similar. We shouldn't show expired cookies in this list since it will | 1087 // or similar. We shouldn't show expired cookies in this list since it will |
| 1088 // just be confusing to users, and this function is called rarely enough (and | 1088 // just be confusing to users, and this function is called rarely enough (and |
| 1089 // is already slow enough) that it's OK to take the time to garbage collect | 1089 // is already slow enough) that it's OK to take the time to garbage collect |
| 1090 // the expired cookies now. | 1090 // the expired cookies now. |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1388 // Even if a key is expired, insert it so it can be garbage collected, | 1388 // Even if a key is expired, insert it so it can be garbage collected, |
| 1389 // removed, and sync'd. | 1389 // removed, and sync'd. |
| 1390 CookieItVector cookies_with_control_chars; | 1390 CookieItVector cookies_with_control_chars; |
| 1391 | 1391 |
| 1392 for (std::vector<CanonicalCookie*>::const_iterator it = cookies.begin(); | 1392 for (std::vector<CanonicalCookie*>::const_iterator it = cookies.begin(); |
| 1393 it != cookies.end(); ++it) { | 1393 it != cookies.end(); ++it) { |
| 1394 int64_t cookie_creation_time = (*it)->CreationDate().ToInternalValue(); | 1394 int64_t cookie_creation_time = (*it)->CreationDate().ToInternalValue(); |
| 1395 | 1395 |
| 1396 if (creation_times_.insert(cookie_creation_time).second) { | 1396 if (creation_times_.insert(cookie_creation_time).second) { |
| 1397 CookieMap::iterator inserted = | 1397 CookieMap::iterator inserted = |
| 1398 InternalInsertCookie(GetKey((*it)->Domain()), *it, false); | 1398 InternalInsertCookie(GetKey((*it)->Domain()), *it, GURL(), false); |
| 1399 const Time cookie_access_time((*it)->LastAccessDate()); | 1399 const Time cookie_access_time((*it)->LastAccessDate()); |
| 1400 if (earliest_access_time_.is_null() || | 1400 if (earliest_access_time_.is_null() || |
| 1401 cookie_access_time < earliest_access_time_) | 1401 cookie_access_time < earliest_access_time_) |
| 1402 earliest_access_time_ = cookie_access_time; | 1402 earliest_access_time_ = cookie_access_time; |
| 1403 | 1403 |
| 1404 if (ContainsControlCharacter((*it)->Name()) || | 1404 if (ContainsControlCharacter((*it)->Name()) || |
| 1405 ContainsControlCharacter((*it)->Value())) { | 1405 ContainsControlCharacter((*it)->Value())) { |
| 1406 cookies_with_control_chars.push_back(inserted); | 1406 cookies_with_control_chars.push_back(inserted); |
| 1407 } | 1407 } |
| 1408 } else { | 1408 } else { |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1605 // time if we've been requested to do so. | 1605 // time if we've been requested to do so. |
| 1606 if (options.update_access_time()) { | 1606 if (options.update_access_time()) { |
| 1607 InternalUpdateCookieAccessTime(cc, current); | 1607 InternalUpdateCookieAccessTime(cc, current); |
| 1608 } | 1608 } |
| 1609 cookies->push_back(cc); | 1609 cookies->push_back(cc); |
| 1610 } | 1610 } |
| 1611 } | 1611 } |
| 1612 | 1612 |
| 1613 bool CookieMonster::DeleteAnyEquivalentCookie(const std::string& key, | 1613 bool CookieMonster::DeleteAnyEquivalentCookie(const std::string& key, |
| 1614 const CanonicalCookie& ecc, | 1614 const CanonicalCookie& ecc, |
| 1615 const GURL& source_url, |
| 1615 bool skip_httponly, | 1616 bool skip_httponly, |
| 1616 bool already_expired, | 1617 bool already_expired, |
| 1617 bool enforce_strict_secure) { | 1618 bool enforce_strict_secure) { |
| 1618 DCHECK(thread_checker_.CalledOnValidThread()); | 1619 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1619 | 1620 |
| 1620 bool found_equivalent_cookie = false; | 1621 bool found_equivalent_cookie = false; |
| 1621 bool skipped_httponly = false; | 1622 bool skipped_httponly = false; |
| 1622 bool skipped_secure_cookie = false; | 1623 bool skipped_secure_cookie = false; |
| 1623 | 1624 |
| 1624 histogram_cookie_delete_equivalent_->Add(COOKIE_DELETE_EQUIVALENT_ATTEMPT); | 1625 histogram_cookie_delete_equivalent_->Add(COOKIE_DELETE_EQUIVALENT_ATTEMPT); |
| 1625 | 1626 |
| 1626 for (CookieMapItPair its = cookies_.equal_range(key); | 1627 for (CookieMapItPair its = cookies_.equal_range(key); |
| 1627 its.first != its.second;) { | 1628 its.first != its.second;) { |
| 1628 CookieMap::iterator curit = its.first; | 1629 CookieMap::iterator curit = its.first; |
| 1629 CanonicalCookie* cc = curit->second; | 1630 CanonicalCookie* cc = curit->second; |
| 1630 ++its.first; | 1631 ++its.first; |
| 1631 | 1632 |
| 1632 // If strict secure cookies is being enforced, then the equivalency | 1633 // If strict secure cookies is being enforced, then the equivalency |
| 1633 // requirements are looser. If the cookie is being set from an insecure | 1634 // requirements are looser. If the cookie is being set from an insecure |
| 1634 // scheme, then if a cookie already exists with the same name and it is | 1635 // scheme, then if a cookie already exists with the same name and it is |
| 1635 // Secure, then the cookie should *not* be updated if they domain-match and | 1636 // Secure, then the cookie should *not* be updated if they domain-match and |
| 1636 // ignoring the path attribute. | 1637 // ignoring the path attribute. |
| 1637 // | 1638 // |
| 1638 // See: https://tools.ietf.org/html/draft-west-leave-secure-cookies-alone | 1639 // See: https://tools.ietf.org/html/draft-west-leave-secure-cookies-alone |
| 1639 if (enforce_strict_secure && !ecc.Source().SchemeIsCryptographic() && | 1640 if (enforce_strict_secure && !source_url.SchemeIsCryptographic() && |
| 1640 ecc.IsEquivalentForSecureCookieMatching(*cc) && cc->IsSecure()) { | 1641 ecc.IsEquivalentForSecureCookieMatching(*cc) && cc->IsSecure()) { |
| 1641 skipped_secure_cookie = true; | 1642 skipped_secure_cookie = true; |
| 1642 histogram_cookie_delete_equivalent_->Add( | 1643 histogram_cookie_delete_equivalent_->Add( |
| 1643 COOKIE_DELETE_EQUIVALENT_SKIPPING_SECURE); | 1644 COOKIE_DELETE_EQUIVALENT_SKIPPING_SECURE); |
| 1644 // If the cookie is equivalent to the new cookie and wouldn't have been | 1645 // If the cookie is equivalent to the new cookie and wouldn't have been |
| 1645 // skipped for being HTTP-only, record that it is a skipped secure cookie | 1646 // skipped for being HTTP-only, record that it is a skipped secure cookie |
| 1646 // that would have been deleted otherwise. | 1647 // that would have been deleted otherwise. |
| 1647 if (ecc.IsEquivalent(*cc)) { | 1648 if (ecc.IsEquivalent(*cc)) { |
| 1648 found_equivalent_cookie = true; | 1649 found_equivalent_cookie = true; |
| 1649 | 1650 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1670 } | 1671 } |
| 1671 found_equivalent_cookie = true; | 1672 found_equivalent_cookie = true; |
| 1672 } | 1673 } |
| 1673 } | 1674 } |
| 1674 return skipped_httponly || skipped_secure_cookie; | 1675 return skipped_httponly || skipped_secure_cookie; |
| 1675 } | 1676 } |
| 1676 | 1677 |
| 1677 CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie( | 1678 CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie( |
| 1678 const std::string& key, | 1679 const std::string& key, |
| 1679 CanonicalCookie* cc, | 1680 CanonicalCookie* cc, |
| 1681 const GURL& source_url, |
| 1680 bool sync_to_store) { | 1682 bool sync_to_store) { |
| 1681 DCHECK(thread_checker_.CalledOnValidThread()); | 1683 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1682 | 1684 |
| 1683 // TODO(mkwst): Remove ScopedTracker below once crbug.com/456373 is fixed. | 1685 // TODO(mkwst): Remove ScopedTracker below once crbug.com/456373 is fixed. |
| 1684 tracked_objects::ScopedTracker tracking_profile( | 1686 tracked_objects::ScopedTracker tracking_profile( |
| 1685 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 1687 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| 1686 "456373 CookieMonster::InternalInsertCookie")); | 1688 "456373 CookieMonster::InternalInsertCookie")); |
| 1687 | 1689 |
| 1688 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get() && | 1690 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get() && |
| 1689 sync_to_store) | 1691 sync_to_store) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1701 : 0; | 1703 : 0; |
| 1702 type_sample |= cc->IsHttpOnly() ? 1 << COOKIE_TYPE_HTTPONLY : 0; | 1704 type_sample |= cc->IsHttpOnly() ? 1 << COOKIE_TYPE_HTTPONLY : 0; |
| 1703 type_sample |= cc->IsSecure() ? 1 << COOKIE_TYPE_SECURE : 0; | 1705 type_sample |= cc->IsSecure() ? 1 << COOKIE_TYPE_SECURE : 0; |
| 1704 histogram_cookie_type_->Add(type_sample); | 1706 histogram_cookie_type_->Add(type_sample); |
| 1705 | 1707 |
| 1706 // Histogram the type of scheme used on URLs that set cookies. This | 1708 // Histogram the type of scheme used on URLs that set cookies. This |
| 1707 // intentionally includes cookies that are set or overwritten by | 1709 // intentionally includes cookies that are set or overwritten by |
| 1708 // http:// URLs, but not cookies that are cleared by http:// URLs, to | 1710 // http:// URLs, but not cookies that are cleared by http:// URLs, to |
| 1709 // understand if the former behavior can be deprecated for Secure | 1711 // understand if the former behavior can be deprecated for Secure |
| 1710 // cookies. | 1712 // cookies. |
| 1711 if (!cc->Source().is_empty()) { | 1713 if (!source_url.is_empty()) { |
| 1712 CookieSource cookie_source_sample; | 1714 CookieSource cookie_source_sample; |
| 1713 if (cc->Source().SchemeIsCryptographic()) { | 1715 if (source_url.SchemeIsCryptographic()) { |
| 1714 cookie_source_sample = | 1716 cookie_source_sample = |
| 1715 cc->IsSecure() ? COOKIE_SOURCE_SECURE_COOKIE_CRYPTOGRAPHIC_SCHEME | 1717 cc->IsSecure() ? COOKIE_SOURCE_SECURE_COOKIE_CRYPTOGRAPHIC_SCHEME |
| 1716 : COOKIE_SOURCE_NONSECURE_COOKIE_CRYPTOGRAPHIC_SCHEME; | 1718 : COOKIE_SOURCE_NONSECURE_COOKIE_CRYPTOGRAPHIC_SCHEME; |
| 1717 } else { | 1719 } else { |
| 1718 cookie_source_sample = | 1720 cookie_source_sample = |
| 1719 cc->IsSecure() | 1721 cc->IsSecure() |
| 1720 ? COOKIE_SOURCE_SECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME | 1722 ? COOKIE_SOURCE_SECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME |
| 1721 : COOKIE_SOURCE_NONSECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME; | 1723 : COOKIE_SOURCE_NONSECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME; |
| 1722 } | 1724 } |
| 1723 histogram_cookie_source_scheme_->Add(cookie_source_sample); | 1725 histogram_cookie_source_scheme_->Add(cookie_source_sample); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1743 last_time_seen_ = creation_time; | 1745 last_time_seen_ = creation_time; |
| 1744 } | 1746 } |
| 1745 | 1747 |
| 1746 std::unique_ptr<CanonicalCookie> cc( | 1748 std::unique_ptr<CanonicalCookie> cc( |
| 1747 CanonicalCookie::Create(url, cookie_line, creation_time, options)); | 1749 CanonicalCookie::Create(url, cookie_line, creation_time, options)); |
| 1748 | 1750 |
| 1749 if (!cc.get()) { | 1751 if (!cc.get()) { |
| 1750 VLOG(kVlogSetCookies) << "WARNING: Failed to allocate CanonicalCookie"; | 1752 VLOG(kVlogSetCookies) << "WARNING: Failed to allocate CanonicalCookie"; |
| 1751 return false; | 1753 return false; |
| 1752 } | 1754 } |
| 1753 return SetCanonicalCookie(std::move(cc), options); | 1755 return SetCanonicalCookie(std::move(cc), url, options); |
| 1754 } | 1756 } |
| 1755 | 1757 |
| 1756 bool CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc, | 1758 bool CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc, |
| 1759 const GURL& source_url, |
| 1757 const CookieOptions& options) { | 1760 const CookieOptions& options) { |
| 1758 DCHECK(thread_checker_.CalledOnValidThread()); | 1761 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1759 | 1762 |
| 1760 Time creation_time = cc->CreationDate(); | 1763 Time creation_time = cc->CreationDate(); |
| 1761 const std::string key(GetKey(cc->Domain())); | 1764 const std::string key(GetKey(cc->Domain())); |
| 1762 bool already_expired = cc->IsExpired(creation_time); | 1765 bool already_expired = cc->IsExpired(creation_time); |
| 1763 | 1766 |
| 1764 if (DeleteAnyEquivalentCookie(key, *cc, options.exclude_httponly(), | 1767 if (DeleteAnyEquivalentCookie(key, *cc, source_url, |
| 1765 already_expired, | 1768 options.exclude_httponly(), already_expired, |
| 1766 options.enforce_strict_secure())) { | 1769 options.enforce_strict_secure())) { |
| 1767 std::string error; | 1770 std::string error; |
| 1768 if (options.enforce_strict_secure()) { | 1771 if (options.enforce_strict_secure()) { |
| 1769 error = | 1772 error = |
| 1770 "SetCookie() not clobbering httponly cookie or secure cookie for " | 1773 "SetCookie() not clobbering httponly cookie or secure cookie for " |
| 1771 "insecure scheme"; | 1774 "insecure scheme"; |
| 1772 } else { | 1775 } else { |
| 1773 error = "SetCookie() not clobbering httponly cookie"; | 1776 error = "SetCookie() not clobbering httponly cookie"; |
| 1774 } | 1777 } |
| 1775 | 1778 |
| 1776 VLOG(kVlogSetCookies) << error; | 1779 VLOG(kVlogSetCookies) << error; |
| 1777 return false; | 1780 return false; |
| 1778 } | 1781 } |
| 1779 | 1782 |
| 1780 VLOG(kVlogSetCookies) << "SetCookie() key: " << key | 1783 VLOG(kVlogSetCookies) << "SetCookie() key: " << key |
| 1781 << " cc: " << cc->DebugString(); | 1784 << " cc: " << cc->DebugString(); |
| 1782 | 1785 |
| 1783 // Realize that we might be setting an expired cookie, and the only point | 1786 // Realize that we might be setting an expired cookie, and the only point |
| 1784 // was to delete the cookie which we've already done. | 1787 // was to delete the cookie which we've already done. |
| 1785 if (!already_expired) { | 1788 if (!already_expired) { |
| 1786 // See InitializeHistograms() for details. | 1789 // See InitializeHistograms() for details. |
| 1787 if (cc->IsPersistent()) { | 1790 if (cc->IsPersistent()) { |
| 1788 histogram_expiration_duration_minutes_->Add( | 1791 histogram_expiration_duration_minutes_->Add( |
| 1789 (cc->ExpiryDate() - creation_time).InMinutes()); | 1792 (cc->ExpiryDate() - creation_time).InMinutes()); |
| 1790 } | 1793 } |
| 1791 | 1794 |
| 1792 InternalInsertCookie(key, cc.release(), true); | 1795 InternalInsertCookie(key, cc.release(), source_url, true); |
| 1793 } else { | 1796 } else { |
| 1794 VLOG(kVlogSetCookies) << "SetCookie() not storing already expired cookie."; | 1797 VLOG(kVlogSetCookies) << "SetCookie() not storing already expired cookie."; |
| 1795 } | 1798 } |
| 1796 | 1799 |
| 1797 // We assume that hopefully setting a cookie will be less common than | 1800 // We assume that hopefully setting a cookie will be less common than |
| 1798 // querying a cookie. Since setting a cookie can put us over our limits, | 1801 // querying a cookie. Since setting a cookie can put us over our limits, |
| 1799 // make sure that we garbage collect... We can also make the assumption that | 1802 // make sure that we garbage collect... We can also make the assumption that |
| 1800 // if a cookie was set, in the common case it will be used soon after, | 1803 // if a cookie was set, in the common case it will be used soon after, |
| 1801 // and we will purge the expired cookies in GetCookies(). | 1804 // and we will purge the expired cookies in GetCookies(). |
| 1802 GarbageCollect(creation_time, key, options.enforce_strict_secure()); | 1805 GarbageCollect(creation_time, key, options.enforce_strict_secure()); |
| 1803 | 1806 |
| 1804 return true; | 1807 return true; |
| 1805 } | 1808 } |
| 1806 | 1809 |
| 1807 bool CookieMonster::SetCanonicalCookies(const CookieList& list) { | 1810 bool CookieMonster::SetCanonicalCookies(const CookieList& list) { |
| 1808 DCHECK(thread_checker_.CalledOnValidThread()); | 1811 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1809 | 1812 |
| 1810 CookieOptions options; | 1813 CookieOptions options; |
| 1811 options.set_include_httponly(); | 1814 options.set_include_httponly(); |
| 1812 | 1815 |
| 1813 for (const auto& cookie : list) { | 1816 for (const auto& cookie : list) { |
| 1817 // Use an empty GURL. This method does not support setting secure cookies. |
| 1814 if (!SetCanonicalCookie(base::WrapUnique(new CanonicalCookie(cookie)), | 1818 if (!SetCanonicalCookie(base::WrapUnique(new CanonicalCookie(cookie)), |
| 1815 options)) { | 1819 GURL(), options)) { |
| 1816 return false; | 1820 return false; |
| 1817 } | 1821 } |
| 1818 } | 1822 } |
| 1819 | 1823 |
| 1820 return true; | 1824 return true; |
| 1821 } | 1825 } |
| 1822 | 1826 |
| 1823 void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc, | 1827 void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc, |
| 1824 const Time& current) { | 1828 const Time& current) { |
| 1825 DCHECK(thread_checker_.CalledOnValidThread()); | 1829 DCHECK(thread_checker_.CalledOnValidThread()); |
| (...skipping 568 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2394 it != hook_map_.end(); ++it) { | 2398 it != hook_map_.end(); ++it) { |
| 2395 std::pair<GURL, std::string> key = it->first; | 2399 std::pair<GURL, std::string> key = it->first; |
| 2396 if (cookie.IncludeForRequestURL(key.first, opts) && | 2400 if (cookie.IncludeForRequestURL(key.first, opts) && |
| 2397 cookie.Name() == key.second) { | 2401 cookie.Name() == key.second) { |
| 2398 it->second->Notify(cookie, removed); | 2402 it->second->Notify(cookie, removed); |
| 2399 } | 2403 } |
| 2400 } | 2404 } |
| 2401 } | 2405 } |
| 2402 | 2406 |
| 2403 } // namespace net | 2407 } // namespace net |
| OLD | NEW |