Skip to content

Commit 8be3384

Browse files
DCtheTallChromium LUCI CQ
authored and
Chromium LUCI CQ
committed
Use bytes instead of no. of partitioned cookies for per-domain limit
After the discussion on privacycg/CHIPS#48 we have decided to change the way we limit domains' partitioned cookies in a single partition. Prior to this change, we restricted domains to 10 cookies per partition. After this change, domains' cookies' names and values may only occupy 10 kilobytes and we impose an additional 180 cookie limit. Bug: 1373515 Change-Id: Id3169404ea8d62dea71999ad702ca89d0ad10577 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3946918 Commit-Queue: Dylan Cutler <[email protected]> Reviewed-by: Chris Fredrickson <[email protected]> Reviewed-by: Maks Orlovich <[email protected]> Cr-Commit-Position: refs/heads/main@{#1060253}
1 parent f69bca2 commit 8be3384

File tree

3 files changed

+96
-37
lines changed

3 files changed

+96
-37
lines changed

net/cookies/cookie_monster.cc

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -162,13 +162,33 @@ bool IncludeUnpartitionedCookies(
162162
return false;
163163
}
164164

165-
size_t NameValueSizeBytes(const std::string& name, const std::string& value) {
166-
base::CheckedNumeric<size_t> name_value_pair_size = name.size();
167-
name_value_pair_size += value.size();
165+
size_t NameValueSizeBytes(const net::CanonicalCookie& cc) {
166+
base::CheckedNumeric<size_t> name_value_pair_size = cc.Name().size();
167+
name_value_pair_size += cc.Value().size();
168168
DCHECK(name_value_pair_size.IsValid());
169169
return name_value_pair_size.ValueOrDie();
170170
}
171171

172+
size_t NumBytesInCookieMapForKey(
173+
const net::CookieMonster::CookieMap& cookie_map,
174+
const std::string& key) {
175+
size_t result = 0;
176+
auto range = cookie_map.equal_range(key);
177+
for (auto it = range.first; it != range.second; ++it) {
178+
result += NameValueSizeBytes(*it->second);
179+
}
180+
return result;
181+
}
182+
183+
size_t NumBytesInCookieItVector(
184+
const net::CookieMonster::CookieItVector& cookie_its) {
185+
size_t result = 0;
186+
for (const auto& it : cookie_its) {
187+
result += NameValueSizeBytes(*it->second);
188+
}
189+
return result;
190+
}
191+
172192
} // namespace
173193

174194
namespace net {
@@ -182,7 +202,8 @@ const size_t CookieMonster::kPurgeCookies = 300;
182202

183203
const size_t CookieMonster::kMaxDomainPurgedKeys = 100;
184204

185-
const size_t CookieMonster::kPerPartitionDomainMaxCookies = 10;
205+
const size_t CookieMonster::kPerPartitionDomainMaxCookieBytes = 10240;
206+
const size_t CookieMonster::kPerPartitionDomainMaxCookies = 180;
186207

187208
const size_t CookieMonster::kDomainCookiesQuotaLow = 30;
188209
const size_t CookieMonster::kDomainCookiesQuotaMedium = 50;
@@ -1560,7 +1581,7 @@ void CookieMonster::SetCanonicalCookie(
15601581

15611582
if (cc->IsEffectivelySameSiteNone()) {
15621583
UMA_HISTOGRAM_COUNTS_10000("Cookie.SameSiteNoneSizeBytes",
1563-
NameValueSizeBytes(cc->Name(), cc->Value()));
1584+
NameValueSizeBytes(*cc));
15641585
}
15651586

15661587
bool is_partitioned_cookie = cc->IsPartitioned();
@@ -1981,26 +2002,30 @@ size_t CookieMonster::GarbageCollectPartitionedCookies(
19812002
if (cookie_partition_it == partitioned_cookies_.end())
19822003
return num_deleted;
19832004

1984-
if (cookie_partition_it->second->count(key) > kPerPartitionDomainMaxCookies) {
2005+
if (NumBytesInCookieMapForKey(*cookie_partition_it->second.get(), key) >
2006+
kPerPartitionDomainMaxCookieBytes ||
2007+
cookie_partition_it->second->count(key) > kPerPartitionDomainMaxCookies) {
19852008
// TODO(crbug.com/1225444): Log garbage collection for partitioned cookies.
19862009

19872010
CookieItVector non_expired_cookie_its;
19882011
num_deleted += GarbageCollectExpiredPartitionedCookies(
19892012
current, cookie_partition_it,
19902013
cookie_partition_it->second->equal_range(key), &non_expired_cookie_its);
19912014

1992-
if (non_expired_cookie_its.size() > kPerPartitionDomainMaxCookies) {
2015+
size_t bytes_used = NumBytesInCookieItVector(non_expired_cookie_its);
2016+
2017+
if (bytes_used > kPerPartitionDomainMaxCookieBytes ||
2018+
non_expired_cookie_its.size() > kPerPartitionDomainMaxCookies) {
19932019
// TODO(crbug.com/1225444): Log deep garbage collection for partitioned
19942020
// cookies.
1995-
1996-
// For now, just delete the least recently accessed partition cookies
1997-
// until we are under the per-partition domain limit. All partitioned
1998-
// cookies are Secure since they require the __Host- prefix.
19992021
std::sort(non_expired_cookie_its.begin(), non_expired_cookie_its.end(),
20002022
LRACookieSorter);
2023+
20012024
for (size_t i = 0;
2002-
i < (non_expired_cookie_its.size() - kPerPartitionDomainMaxCookies);
2025+
bytes_used > kPerPartitionDomainMaxCookieBytes ||
2026+
non_expired_cookie_its.size() - i > kPerPartitionDomainMaxCookies;
20032027
++i) {
2028+
bytes_used -= NameValueSizeBytes(*non_expired_cookie_its[i]->second);
20042029
InternalDeletePartitionedCookie(
20052030
cookie_partition_it, non_expired_cookie_its[i], true,
20062031
DELETE_COOKIE_EVICTED_PER_PARTITION_DOMAIN);

net/cookies/cookie_monster.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ class NET_EXPORT CookieMonster : public CookieStore {
139139
static const size_t kMaxDomainPurgedKeys;
140140

141141
// Partitioned cookie garbage collection thresholds.
142+
static const size_t kPerPartitionDomainMaxCookieBytes;
142143
static const size_t kPerPartitionDomainMaxCookies;
143144
// TODO(crbug.com/1225444): Add global limit to number of partitioned cookies.
144145

net/cookies/cookie_monster_unittest.cc

Lines changed: 58 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -923,29 +923,6 @@ class CookieMonsterTestBase : public CookieStoreTest<T> {
923923
70U);
924924
}
925925

926-
// Test enforcement of the per-partition domain limit on partitioned cookies.
927-
void TestPartitionedCookiesGarbageCollectionHelper() {
928-
DCHECK_EQ(10u, CookieMonster::kPerPartitionDomainMaxCookies);
929-
int max_cookies = CookieMonster::kPerPartitionDomainMaxCookies;
930-
auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
931-
932-
auto cookie_partition_key =
933-
CookiePartitionKey::FromURLForTesting(GURL("https://toplevelsite.com"));
934-
for (int i = 0; i < max_cookies + 5; ++i) {
935-
std::string cookie = base::StringPrintf("__Host-a%02d=b", i);
936-
EXPECT_TRUE(SetCookie(cm.get(), https_www_foo_.url(),
937-
cookie + "; secure; path=/; partitioned",
938-
cookie_partition_key));
939-
std::string cookies =
940-
this->GetCookies(cm.get(), https_www_foo_.url(),
941-
CookiePartitionKeyCollection(cookie_partition_key));
942-
EXPECT_NE(cookies.find(cookie), std::string::npos);
943-
EXPECT_LE(CountInString(cookies, '='), max_cookies);
944-
}
945-
// TODO(crbug.com/1225444): Test recording stats for deleting partitioned
946-
// cookies.
947-
}
948-
949926
// Function for creating a CM with a number of cookies in it,
950927
// no store (and hence no ability to affect access time).
951928
std::unique_ptr<CookieMonster> CreateMonsterForGC(int num_cookies) {
@@ -1780,8 +1757,64 @@ TEST_F(CookieMonsterTest, TestPriorityAwareGarbageCollectionMixed) {
17801757
TestPriorityAwareGarbageCollectHelperMixed();
17811758
}
17821759

1783-
TEST_F(CookieMonsterTest, TestPartitionedCookiesGarbageCollection) {
1784-
TestPartitionedCookiesGarbageCollectionHelper();
1760+
TEST_F(CookieMonsterTest, TestPartitionedCookiesGarbageCollection_Memory) {
1761+
// Limit should be 10 KB.
1762+
DCHECK_EQ(1024u * 10u, CookieMonster::kPerPartitionDomainMaxCookieBytes);
1763+
1764+
auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
1765+
auto cookie_partition_key =
1766+
CookiePartitionKey::FromURLForTesting(GURL("https://toplevelsite1.com"));
1767+
1768+
for (size_t i = 0; i < 41; ++i) {
1769+
std::string cookie_value((10240 / 40) - (i < 10 ? 1 : 2), '0');
1770+
std::string cookie =
1771+
base::StrCat({base::NumberToString(i), "=", cookie_value});
1772+
EXPECT_TRUE(SetCookie(cm.get(), https_www_foo_.url(),
1773+
cookie + "; secure; path=/; partitioned",
1774+
cookie_partition_key))
1775+
<< "Failed to set cookie " << i;
1776+
}
1777+
1778+
std::string cookies =
1779+
this->GetCookies(cm.get(), https_www_foo_.url(),
1780+
CookiePartitionKeyCollection(cookie_partition_key));
1781+
1782+
EXPECT_THAT(cookies, CookieStringIs(
1783+
testing::Not(testing::Contains(testing::Key("0")))));
1784+
for (size_t i = 1; i < 41; ++i) {
1785+
EXPECT_THAT(cookies, CookieStringIs(testing::Contains(
1786+
testing::Key(base::NumberToString(i)))))
1787+
<< "Failed to find cookie " << i;
1788+
}
1789+
}
1790+
1791+
TEST_F(CookieMonsterTest, TestPartitionedCookiesGarbageCollection_MaxCookies) {
1792+
// Partitioned cookies also limit domains to 180 cookies per partition.
1793+
DCHECK_EQ(180u, CookieMonster::kPerPartitionDomainMaxCookies);
1794+
1795+
auto cm = std::make_unique<CookieMonster>(nullptr, net::NetLog::Get());
1796+
auto cookie_partition_key =
1797+
CookiePartitionKey::FromURLForTesting(GURL("https://toplevelsite.com"));
1798+
1799+
for (size_t i = 0; i < 181; ++i) {
1800+
std::string cookie = base::StrCat({base::NumberToString(i), "=0"});
1801+
EXPECT_TRUE(SetCookie(cm.get(), https_www_foo_.url(),
1802+
cookie + "; secure; path=/; partitioned",
1803+
cookie_partition_key))
1804+
<< "Failed to set cookie " << i;
1805+
}
1806+
1807+
std::string cookies =
1808+
this->GetCookies(cm.get(), https_www_foo_.url(),
1809+
CookiePartitionKeyCollection(cookie_partition_key));
1810+
EXPECT_THAT(cookies, CookieStringIs(
1811+
testing::Not(testing::Contains(testing::Key("0")))));
1812+
for (size_t i = 1; i < 181; ++i) {
1813+
std::string cookie = base::StrCat({base::NumberToString(i), "=0"});
1814+
EXPECT_THAT(cookies, CookieStringIs(testing::Contains(
1815+
testing::Key(base::NumberToString(i)))))
1816+
<< "Failed to find cookie " << i;
1817+
}
17851818
}
17861819

17871820
TEST_F(CookieMonsterTest, SetCookieableSchemes) {

0 commit comments

Comments
 (0)