0

Add partition_key to CanonicalCookie.

This CL adds an absl::optional<net::SchemefulSite> field to
CanonicalCookie which stores the cookie's partition key if the cookie
was set with the Partitioned attribute.

Any cookie that was set without the Partitioned attribute will have
absl::nullopt as a partition key.

This CL also adds methods to CanonicalCookie to return:
- IsPartitioned: if the cookie was set with the Partitioned attribute.
- PartitionKey: the cookie's partition key.

Bug: 1225444
Change-Id: I9c0fa52a28aeedaa631c438e2d1eb1ae7383bd57
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3012034
Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
Reviewed-by: Christian Dullweber <dullweber@chromium.org>
Reviewed-by: Mike West <mkwst@chromium.org>
Reviewed-by: David Roger <droger@chromium.org>
Reviewed-by: Sylvain Defresne <sdefresne@chromium.org>
Reviewed-by: Wez <wez@chromium.org>
Reviewed-by: Lily Chen <chlily@chromium.org>
Commit-Queue: Dylan Cutler <dylancutler@google.com>
Cr-Commit-Position: refs/heads/master@{#902527}
This commit is contained in:
Dylan Cutler
2021-07-16 18:01:35 +00:00
committed by Chromium LUCI CQ
parent 168f047097
commit 01ca8e3a0b
33 changed files with 431 additions and 129 deletions

@ -88,15 +88,16 @@ public class CanonicalCookieTest {
ArrayList<CanonicalCookie> cookies = new ArrayList<>();
cookies.add(new CanonicalCookie("name", "value", "domain", "path", 0 /* creation */,
1 /* expiration */, 0 /* lastAccess */, false /* secure */, true /* httpOnly */,
0 /* sameSite */, 0 /* priority */, false /* same_party */, 1 /* sourceScheme */,
72 /* sourcePort */));
0 /* sameSite */, 0 /* priority */, false /* same_party */, "" /* partition_key */,
1 /* sourceScheme */, 72 /* sourcePort */));
cookies.add(new CanonicalCookie("name2", "value2", ".domain2", "path2", 10 /* creation */,
20 /* expiration */, 15 /* lastAccess */, true /* secure */, false /* httpOnly */,
1 /* sameSite */, 1 /* priority */, true /* same_party */, 2 /* sourceScheme */,
445 /* sourcePort */));
1 /* sameSite */, 1 /* priority */, true /* same_party */, "" /* partition_key */,
2 /* sourceScheme */, 445 /* sourcePort */));
cookies.add(new CanonicalCookie("name3", "value3", "domain3", "path3", 10 /* creation */,
20 /* expiration */, 15 /* lastAccess */, true /* secure */, false /* httpOnly */,
2 /* sameSite */, 2 /* priority */, false /* same_party */, 2 /* sourceScheme */,
2 /* sameSite */, 2 /* priority */, false /* same_party */,
"https://toplevelsite.com" /* partition_key */, 2 /* sourceScheme */,
-1 /* sourcePort */));
doSaveRestoreCookiesListTest(cookies);

@ -50,8 +50,12 @@ void OnCookiesFetchFinished(const net::CookieList& cookies) {
i->ExpiryDate().ToDeltaSinceWindowsEpoch().InMicroseconds(),
i->LastAccessDate().ToDeltaSinceWindowsEpoch().InMicroseconds(),
i->IsSecure(), i->IsHttpOnly(), static_cast<int>(i->SameSite()),
i->Priority(), i->IsSameParty(), static_cast<int>(i->SourceScheme()),
i->SourcePort());
i->Priority(), i->IsSameParty(),
// TODO(crbug.com/1225444) Use serialized partition key instead of
// constant.
base::android::ConvertUTF8ToJavaString(env,
net::kEmptyCookiePartitionKey),
static_cast<int>(i->SourceScheme()), i->SourcePort());
env->SetObjectArrayElement(joa.obj(), index++, java_cookie.obj());
}
@ -91,6 +95,7 @@ static void JNI_CookiesFetcher_RestoreCookies(
jint same_site,
jint priority,
jboolean same_party,
const JavaParamRef<jstring>& partition_key,
jint source_scheme,
jint source_port) {
if (!ProfileManager::GetPrimaryUserProfile()->HasPrimaryOTRProfile())
@ -112,7 +117,9 @@ static void JNI_CookiesFetcher_RestoreCookies(
base::TimeDelta::FromMicroseconds(last_access)),
secure, httponly, static_cast<net::CookieSameSite>(same_site),
static_cast<net::CookiePriority>(priority), same_party,
static_cast<net::CookieSourceScheme>(source_scheme), source_port);
// TODO(crbug.com/1225444) Deserialize partition key argument.
absl::nullopt, static_cast<net::CookieSourceScheme>(source_scheme),
source_port);
if (!cookie)
return;

@ -231,7 +231,7 @@ void ProfileAuthDataTest::PopulateBrowserContext(
kSAMLIdPCookieDomainWithWildcard, std::string(), base::Time(),
base::Time(), base::Time(), true, false,
net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_DEFAULT,
false),
false, absl::nullopt),
GURL(kSAMLIdPCookieURL), options, base::DoNothing());
cookies->SetCanonicalCookie(
@ -239,7 +239,7 @@ void ProfileAuthDataTest::PopulateBrowserContext(
GURL(kSAMLIdPCookieURL), kCookieName, cookie_value, std::string(),
std::string(), base::Time(), base::Time(), base::Time(), true, false,
net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_DEFAULT,
false),
false, absl::nullopt),
GURL(kSAMLIdPCookieURL), options, base::DoNothing());
cookies->SetCanonicalCookie(
@ -247,7 +247,7 @@ void ProfileAuthDataTest::PopulateBrowserContext(
GURL(kGAIACookieURL), kCookieName, cookie_value, std::string(),
std::string(), base::Time(), base::Time(), base::Time(), true, false,
net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_DEFAULT,
false),
false, absl::nullopt),
GURL(kGAIACookieURL), options, base::DoNothing());
}

@ -61,7 +61,7 @@ class SiteDataCountingHelperTest : public testing::Test {
url, "name", "A=1", url.host(), url.path(), creation_time,
base::Time(), creation_time, url.SchemeIsCryptographic(), false,
net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_DEFAULT,
false);
false, absl::nullopt);
net::CookieOptions options;
options.set_include_httponly();
cookie_manager->SetCanonicalCookie(

@ -109,7 +109,7 @@ void AndroidSmsAppSetupControllerImpl::SetUpApp(const GURL& app_url,
base::Time::Now() /* last_access_time */,
!net::IsLocalhost(app_url) /* secure */, false /* http_only */,
net::CookieSameSite::STRICT_MODE, net::COOKIE_PRIORITY_DEFAULT,
false /* same_party */);
false /* same_party */, absl::nullopt /* partition_key */);
// TODO(crbug.com/1069974): The cookie source url must be faked here because
// otherwise, this would fail to set a secure cookie if |app_url| is insecure.
// Consider instead to use url::Replacements to force the scheme to be https.
@ -328,7 +328,7 @@ void AndroidSmsAppSetupControllerImpl::SetMigrationCookie(
base::Time::Now() /* last_access_time */,
!net::IsLocalhost(app_url) /* secure */, false /* http_only */,
net::CookieSameSite::STRICT_MODE, net::COOKIE_PRIORITY_DEFAULT,
false /* same_party */);
false /* same_party */, absl::nullopt /* partition_key */);
// TODO(crbug.com/1069974): The cookie source url must be faked here because
// otherwise, this would fail to set a secure cookie if |app_url| is insecure.
// Consider instead to use url::Replacements to force the scheme to be https.

@ -434,7 +434,8 @@ ExtensionFunction::ResponseAction CookiesSetFunction::Run() {
false,
same_site,
net::COOKIE_PRIORITY_DEFAULT,
/*same_party=*/false));
/*same_party=*/false,
/*partition_key=*/absl::nullopt));
// clang-format on
if (!cc) {
// Return error through callbacks so that the proper error message

@ -28,13 +28,15 @@ class CanonicalCookie {
private final int mSameSite;
private final int mPriority;
private final boolean mSameParty;
private final String mPartitionKey;
private final int mSourceScheme;
private final int mSourcePort;
/** Constructs a CanonicalCookie */
CanonicalCookie(String name, String value, String domain, String path, long creation,
long expiration, long lastAccess, boolean secure, boolean httpOnly, int sameSite,
int priority, boolean sameParty, int sourceScheme, int sourcePort) {
int priority, boolean sameParty, String partitionKey, int sourceScheme,
int sourcePort) {
mName = name;
mValue = value;
mDomain = domain;
@ -47,6 +49,7 @@ class CanonicalCookie {
mSameSite = sameSite;
mPriority = priority;
mSameParty = sameParty;
mPartitionKey = partitionKey;
mSourceScheme = sourceScheme;
mSourcePort = sourcePort;
}
@ -111,6 +114,11 @@ class CanonicalCookie {
return mValue;
}
/** @return Cookie partition key. */
String getPartitionKey() {
return mPartitionKey;
}
/** @return Source scheme of the cookie. */
int sourceScheme() {
return mSourceScheme;
@ -124,7 +132,7 @@ class CanonicalCookie {
// Note incognito state cannot persist across app installs since the encryption key is stored
// in the activity state bundle. So the version here is more of a guard than a real version
// used for format migrations.
private static final int SERIALIZATION_VERSION = 20201111;
private static final int SERIALIZATION_VERSION = 20210712;
static void saveListToStream(DataOutputStream out, CanonicalCookie[] cookies)
throws IOException {
@ -190,6 +198,7 @@ class CanonicalCookie {
out.writeInt(mSameSite);
out.writeInt(mPriority);
out.writeBoolean(mSameParty);
out.writeUTF(mPartitionKey);
out.writeInt(mSourceScheme);
out.writeInt(mSourcePort);
}
@ -207,6 +216,7 @@ class CanonicalCookie {
in.readInt(), // samesite
in.readInt(), // priority
in.readBoolean(), // sameparty
in.readUTF(), // partition key
in.readInt(), // source scheme
in.readInt()); // source port
}

@ -131,8 +131,8 @@ public class CookiesFetcher {
cookie.getDomain(), cookie.getPath(), cookie.getCreationDate(),
cookie.getExpirationDate(), cookie.getLastAccessDate(),
cookie.isSecure(), cookie.isHttpOnly(), cookie.getSameSite(),
cookie.getPriority(), cookie.isSameParty(), cookie.sourceScheme(),
cookie.sourcePort());
cookie.getPriority(), cookie.isSameParty(), cookie.getPartitionKey(),
cookie.sourceScheme(), cookie.sourcePort());
}
}
}.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
@ -175,10 +175,11 @@ public class CookiesFetcher {
@CalledByNative
private static CanonicalCookie createCookie(String name, String value, String domain,
String path, long creation, long expiration, long lastAccess, boolean secure,
boolean httpOnly, int sameSite, int priority, boolean sameParty, int sourceScheme,
int sourcePort) {
boolean httpOnly, int sameSite, int priority, boolean sameParty, String partitionKey,
int sourceScheme, int sourcePort) {
return new CanonicalCookie(name, value, domain, path, creation, expiration, lastAccess,
secure, httpOnly, sameSite, priority, sameParty, sourceScheme, sourcePort);
secure, httpOnly, sameSite, priority, sameParty, partitionKey, sourceScheme,
sourcePort);
}
@CalledByNative
@ -234,6 +235,7 @@ public class CookiesFetcher {
void persistCookies();
void restoreCookies(String name, String value, String domain, String path, long creation,
long expiration, long lastAccess, boolean secure, boolean httpOnly, int sameSite,
int priority, boolean sameParty, int sourceScheme, int sourcePort);
int priority, boolean sameParty, String partitionKey, int sourceScheme,
int sourcePort);
}
}

@ -606,7 +606,7 @@ void GaiaCookieManagerService::ForceOnCookieChangeProcessing() {
"." + google_url.host(), "/", base::Time(), base::Time(),
base::Time(), true /* secure */, false /* httponly */,
net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_DEFAULT,
false /* same_party */);
false /* same_party */, absl::nullopt /* partition_key */);
OnCookieChange(
net::CookieChangeInfo(*cookie, net::CookieAccessResult(),
net::CookieChangeCause::UNKNOWN_DELETION));

@ -452,7 +452,8 @@ void AccountConsistencyService::SetChromeConnectedCookieWithUrl(
/*last_access_time=*/base::Time(),
/*secure=*/true,
/*httponly=*/false, net::CookieSameSite::LAX_MODE,
net::COOKIE_PRIORITY_DEFAULT, /*same_party=*/false);
net::COOKIE_PRIORITY_DEFAULT, /*same_party=*/false,
/*partition_key=*/absl::nullopt);
net::CookieOptions options;
options.set_include_httponly();
options.set_same_site_cookie_context(

@ -371,11 +371,12 @@ MakeCookieFromProtocolValues(const std::string& name,
else if (priority == Network::CookiePriorityEnum::Low)
cp = net::CookiePriority::COOKIE_PRIORITY_LOW;
// TODO(crbug.com/1225444) Add Partitioned to DevTools cookie structures.
std::unique_ptr<net::CanonicalCookie> cookie =
net::CanonicalCookie::CreateSanitizedCookie(
url, name, value, normalized_domain, path, base::Time(),
expiration_date, base::Time(), secure, http_only, css, cp,
same_party);
expiration_date, base::Time(), secure, http_only, css, cp, same_party,
absl::nullopt);
if (!cookie)
return Response::InvalidParams("Sanitizing cookie failed");

@ -45,7 +45,8 @@ std::unique_ptr<net::CanonicalCookie> CreateCookie(base::StringPiece name,
/*expiration_time=*/base::Time(), /*last_access_time=*/base::Time(),
/*secure=*/true,
/*httponly*/ false, net::CookieSameSite::NO_RESTRICTION,
net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false);
net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false,
/*partition_key=*/absl::nullopt);
}
class CookieManagerImplTest : public testing::Test {

@ -408,7 +408,8 @@ bool OAuth2MintTokenFlow::ParseRemoteConsentResponse(
time_now, expiration_time, time_now, is_secure ? *is_secure : false,
is_http_only ? *is_http_only : false,
net::StringToCookieSameSite(same_site ? *same_site : ""),
net::COOKIE_PRIORITY_DEFAULT, /* same_party */ false);
net::COOKIE_PRIORITY_DEFAULT, /* same_party */ false,
/* partition_key */ absl::nullopt);
cookies.push_back(*cookie);
}

@ -108,13 +108,14 @@ static RemoteConsentResolutionData CreateRemoteConsentResolutionData() {
*net::CanonicalCookie::CreateSanitizedCookie(
resolution_data.url, "test_name", "test_value", "test.com", "/",
base::Time(), base::Time(), base::Time(), false, true,
net::CookieSameSite::LAX_MODE, net::COOKIE_PRIORITY_DEFAULT, false));
net::CookieSameSite::LAX_MODE, net::COOKIE_PRIORITY_DEFAULT, false,
absl::nullopt));
resolution_data.cookies.push_back(
*net::CanonicalCookie::CreateSanitizedCookie(
resolution_data.url, "test_name2", "test_value2", "test.com", "/",
base::Time(), base::Time(), base::Time(), false, false,
net::CookieSameSite::UNSPECIFIED, net::COOKIE_PRIORITY_DEFAULT,
false));
net::CookieSameSite::UNSPECIFIED, net::COOKIE_PRIORITY_DEFAULT, false,
absl::nullopt));
return resolution_data;
}

@ -128,8 +128,8 @@ void OAuthMultiloginResult::TryParseCookiesFromValue(base::Value* json_value) {
/*last_access=*/base::Time::Now(), is_secure.value_or(true),
is_http_only.value_or(true), samesite_mode,
net::StringToCookiePriority(priority ? *priority : "medium"),
/*same_party=*/false, net::CookieSourceScheme::kUnset,
url::PORT_UNSPECIFIED);
/*same_party=*/false, /*partition_key=*/absl::nullopt,
net::CookieSourceScheme::kUnset, url::PORT_UNSPECIFIED);
// If the unique_ptr is null, it means the cookie was not canonical.
if (new_cookie) {
cookies_.push_back(std::move(*new_cookie));

@ -60,7 +60,8 @@ std::unique_ptr<net::CanonicalCookie> CanonicalCookieFromSystemCookie(
// When iOS begins to support 'Priority' and 'SameParty' attributes, pass
// them through here.
net::COOKIE_PRIORITY_DEFAULT, false /* SameParty */,
net::CookieSourceScheme::kUnset, url::PORT_UNSPECIFIED);
absl::nullopt /* partition_key */, net::CookieSourceScheme::kUnset,
url::PORT_UNSPECIFIED);
}
void ReportGetCookiesForURLResult(SystemCookieStoreType store_type,

@ -319,6 +319,7 @@ CanonicalCookie::CanonicalCookie(std::string name,
CookieSameSite same_site,
CookiePriority priority,
bool same_party,
absl::optional<SchemefulSite> partition_key,
CookieSourceScheme source_scheme,
int source_port)
: name_(std::move(name)),
@ -333,6 +334,7 @@ CanonicalCookie::CanonicalCookie(std::string name,
same_site_(same_site),
priority_(priority),
same_party_(same_party),
partition_key_(std::move(partition_key)),
source_scheme_(source_scheme) {
SetSourcePort(source_port);
}
@ -475,6 +477,13 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::Create(
if (parsed_cookie.IsSameParty())
base::UmaHistogramBoolean("Cookie.IsSamePartyValid", is_same_party_valid);
if (!IsCookiePartitionedValid(parsed_cookie)) {
status->AddExclusionReason(
CookieInclusionStatus::EXCLUDE_INVALID_PARTITIONED);
}
// TODO(crbug.com/1225444) Log histogram metric for seeing how often
// Partitioned attribute is used correctly.
if (!status->IsInclude())
return nullptr;
@ -487,11 +496,13 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::Create(
// Get the port, this will get a default value if a port isn't provided.
int source_port = url.EffectiveIntPort();
// TODO(crbug.com/987177) Add partition key if Partitioned is present in the
// cookie line.
std::unique_ptr<CanonicalCookie> cc = base::WrapUnique(new CanonicalCookie(
parsed_cookie.Name(), parsed_cookie.Value(), cookie_domain, cookie_path,
creation_time, cookie_expires, creation_time, parsed_cookie.IsSecure(),
parsed_cookie.IsHttpOnly(), samesite, parsed_cookie.Priority(),
parsed_cookie.IsSameParty(), source_scheme, source_port));
parsed_cookie.IsSameParty(), absl::nullopt, source_scheme, source_port));
// TODO(chlily): Log metrics.
if (!cc->IsCanonical()) {
@ -524,6 +535,7 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::CreateSanitizedCookie(
CookieSameSite same_site,
CookiePriority priority,
bool same_party,
absl::optional<SchemefulSite> partition_key,
CookieInclusionStatus* status) {
// Put a pointer on the stack so the rest of the function can assign to it if
// the default nullptr is passed in.
@ -588,8 +600,8 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::CreateSanitizedCookie(
net::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE);
}
if (!IsCookiePrefixValid(GetCookiePrefix(name), url, secure, domain,
cookie_path)) {
CookiePrefix prefix = GetCookiePrefix(name);
if (!IsCookiePrefixValid(prefix, url, secure, domain, cookie_path)) {
status->AddExclusionReason(
net::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX);
}
@ -598,6 +610,11 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::CreateSanitizedCookie(
status->AddExclusionReason(
net::CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY);
}
if (!IsCookiePartitionedValid(partition_key.has_value(), prefix,
same_party)) {
status->AddExclusionReason(
net::CookieInclusionStatus::EXCLUDE_INVALID_PARTITIONED);
}
if (!last_access_time.is_null() && creation_time.is_null()) {
status->AddExclusionReason(
@ -619,7 +636,7 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::CreateSanitizedCookie(
std::unique_ptr<CanonicalCookie> cc = base::WrapUnique(new CanonicalCookie(
name, value, cookie_domain, cookie_path, creation_time, expiration_time,
last_access_time, secure, http_only, same_site, priority, same_party,
source_scheme, source_port));
partition_key, source_scheme, source_port));
DCHECK(cc->IsCanonical());
return cc;
@ -639,12 +656,13 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::FromStorage(
CookieSameSite same_site,
CookiePriority priority,
bool same_party,
absl::optional<SchemefulSite> partition_key,
CookieSourceScheme source_scheme,
int source_port) {
std::unique_ptr<CanonicalCookie> cc = base::WrapUnique(new CanonicalCookie(
std::move(name), std::move(value), std::move(domain), std::move(path),
creation, expiration, last_access, secure, httponly, same_site, priority,
same_party, source_scheme, source_port));
same_party, partition_key, source_scheme, source_port));
if (!cc->IsCanonical())
return nullptr;
return cc;
@ -664,11 +682,13 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::CreateUnsafeCookieForTesting(
CookieSameSite same_site,
CookiePriority priority,
bool same_party,
absl::optional<SchemefulSite> partition_key,
CookieSourceScheme source_scheme,
int source_port) {
return base::WrapUnique(new CanonicalCookie(
name, value, domain, path, creation, expiration, last_access, secure,
httponly, same_site, priority, same_party, source_scheme, source_port));
httponly, same_site, priority, same_party, partition_key, source_scheme,
source_port));
}
std::string CanonicalCookie::DomainWithoutDot() const {
@ -1220,7 +1240,8 @@ bool CanonicalCookie::IsCanonical() const {
if (path_.empty() || path_[0] != '/')
return false;
switch (GetCookiePrefix(name_)) {
CookiePrefix prefix = GetCookiePrefix(name_);
switch (prefix) {
case COOKIE_PREFIX_HOST:
if (!secure_ || path_ != "/" || domain_.empty() || domain_[0] == '.')
return false;
@ -1233,7 +1254,10 @@ bool CanonicalCookie::IsCanonical() const {
break;
}
return IsCookieSamePartyValid(same_party_, secure_, same_site_);
if (!IsCookieSamePartyValid(same_party_, secure_, same_site_))
return false;
return IsCookiePartitionedValid(IsPartitioned(), prefix, same_party_);
}
bool CanonicalCookie::IsEffectivelySameSiteNone(
@ -1381,6 +1405,24 @@ bool CanonicalCookie::IsCookieSamePartyValid(bool is_same_party,
return is_secure && (same_site != CookieSameSite::STRICT_MODE);
}
// static
bool CanonicalCookie::IsCookiePartitionedValid(
const ParsedCookie& parsed_cookie) {
return IsCookiePartitionedValid(parsed_cookie.IsPartitioned(),
GetCookiePrefix(parsed_cookie.Name()),
parsed_cookie.IsSameParty());
}
// static
bool CanonicalCookie::IsCookiePartitionedValid(
bool is_partitioned,
CanonicalCookie::CookiePrefix prefix,
bool is_same_party) {
if (!is_partitioned)
return true;
return prefix == CookiePrefix::COOKIE_PREFIX_HOST && !is_same_party;
}
CookieAndLineWithAccessResult::CookieAndLineWithAccessResult() = default;
CookieAndLineWithAccessResult::CookieAndLineWithAccessResult(

@ -13,6 +13,7 @@
#include "base/gtest_prod_util.h"
#include "base/time/time.h"
#include "net/base/net_export.h"
#include "net/base/schemeful_site.h"
#include "net/cookies/cookie_access_result.h"
#include "net/cookies/cookie_constants.h"
#include "net/cookies/cookie_inclusion_status.h"
@ -106,6 +107,7 @@ class NET_EXPORT CanonicalCookie {
CookieSameSite same_site,
CookiePriority priority,
bool same_party,
absl::optional<SchemefulSite> partition_key,
CookieInclusionStatus* status = nullptr);
// FromStorage is a factory method which is meant for creating a new
@ -128,6 +130,7 @@ class NET_EXPORT CanonicalCookie {
CookieSameSite same_site,
CookiePriority priority,
bool same_party,
absl::optional<SchemefulSite> partition_key,
CookieSourceScheme source_scheme,
int source_port);
@ -146,6 +149,7 @@ class NET_EXPORT CanonicalCookie {
CookieSameSite same_site,
CookiePriority priority,
bool same_party,
absl::optional<SchemefulSite> partition_key = absl::nullopt,
CookieSourceScheme scheme_secure = CookieSourceScheme::kUnset,
int source_port = url::PORT_UNSPECIFIED);
@ -166,6 +170,13 @@ class NET_EXPORT CanonicalCookie {
CookieSameSite SameSite() const { return same_site_; }
CookiePriority Priority() const { return priority_; }
bool IsSameParty() const { return same_party_; }
bool IsPartitioned() const { return partition_key_.has_value(); }
const absl::optional<SchemefulSite>& PartitionKey() const {
return partition_key_;
}
// TODO(crbug.com/1225444) Methods to serialize and deserialize partition
// keys.
// Returns an enum indicating the scheme of the origin that
// set this cookie. This is not part of the cookie spec but is being used to
@ -370,6 +381,7 @@ class NET_EXPORT CanonicalCookie {
CookieSameSite same_site,
CookiePriority priority,
bool same_party,
absl::optional<SchemefulSite> partition_key,
CookieSourceScheme scheme_secure = CookieSourceScheme::kUnset,
int source_port = url::PORT_UNSPECIFIED);
@ -425,6 +437,15 @@ class NET_EXPORT CanonicalCookie {
bool is_secure,
CookieSameSite same_site);
// Returns false iff the cookie is a partitioned cookie that violates the
// semantics of the Partitioned attribute:
// - Cannot be SameParty
// - Must have a __Host- prefix
static bool IsCookiePartitionedValid(const ParsedCookie& parsed_cookie);
static bool IsCookiePartitionedValid(bool is_partitioned,
CookiePrefix prefix,
bool is_same_party);
// Keep defaults here in sync with
// services/network/public/interfaces/cookie_manager.mojom.
std::string name_;
@ -439,6 +460,12 @@ class NET_EXPORT CanonicalCookie {
CookieSameSite same_site_{CookieSameSite::NO_RESTRICTION};
CookiePriority priority_{COOKIE_PRIORITY_MEDIUM};
bool same_party_{false};
// This will be absl::nullopt for all cookies not set with the Partitioned
// attribute. If the value is non-null, then the cookie will only be delivered
// when the top-frame site matches the partition key.
// If the partition key is non-null and opaque, this means the Partitioned
// cookie was created on an opaque origin.
absl::optional<SchemefulSite> partition_key_;
CookieSourceScheme source_scheme_{CookieSourceScheme::kUnset};
// This can be [0,65535], PORT_UNSPECIFIED, or PORT_INVALID.
// PORT_UNSPECIFIED is used for cookies which already existed in the cookie

@ -53,12 +53,15 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
CookiePriority::COOKIE_PRIORITY_HIGH,
});
auto partition_key = absl::make_optional<net::SchemefulSite>(
net::SchemefulSite(GURL(data_provider.ConsumeRandomLengthString(800))));
const std::unique_ptr<const CanonicalCookie> sanitized_cookie =
CanonicalCookie::CreateSanitizedCookie(
url, name, value, domain, path, creation, expiration, last_access,
data_provider.ConsumeBool() /* secure */,
data_provider.ConsumeBool() /* httponly */, same_site, priority,
data_provider.ConsumeBool() /* same_party */);
data_provider.ConsumeBool() /* same_party */, partition_key);
if (sanitized_cookie) {
CHECK(sanitized_cookie->IsCanonical());

@ -50,7 +50,8 @@ TEST(CanonicalCookieTest, Constructor) {
auto cookie1 = CanonicalCookie::CreateUnsafeCookieForTesting(
"A", "2", "www.example.com", "/test", current_time, base::Time(),
base::Time(), false, false, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false, CookieSourceScheme::kSecure, 443);
COOKIE_PRIORITY_DEFAULT, false, absl::nullopt,
CookieSourceScheme::kSecure, 443);
EXPECT_EQ("A", cookie1->Name());
EXPECT_EQ("2", cookie1->Value());
EXPECT_EQ("www.example.com", cookie1->Domain());
@ -60,13 +61,16 @@ TEST(CanonicalCookieTest, Constructor) {
EXPECT_EQ(CookieSameSite::NO_RESTRICTION, cookie1->SameSite());
EXPECT_EQ(CookiePriority::COOKIE_PRIORITY_DEFAULT, cookie1->Priority());
EXPECT_FALSE(cookie1->IsSameParty());
EXPECT_FALSE(cookie1->IsPartitioned());
EXPECT_EQ(cookie1->SourceScheme(), CookieSourceScheme::kSecure);
EXPECT_EQ(cookie1->SourcePort(), 443);
auto cookie2 = CanonicalCookie::CreateUnsafeCookieForTesting(
"A", "2", ".www.example.com", "/", current_time, base::Time(),
base::Time(), false, false, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, true, CookieSourceScheme::kNonSecure, 65536);
COOKIE_PRIORITY_DEFAULT, true,
absl::make_optional(net::SchemefulSite::Deserialize("https://foo.com")),
CookieSourceScheme::kNonSecure, 65536);
EXPECT_EQ("A", cookie2->Name());
EXPECT_EQ("2", cookie2->Value());
EXPECT_EQ(".www.example.com", cookie2->Domain());
@ -76,6 +80,7 @@ TEST(CanonicalCookieTest, Constructor) {
EXPECT_EQ(CookieSameSite::NO_RESTRICTION, cookie2->SameSite());
EXPECT_EQ(CookiePriority::COOKIE_PRIORITY_DEFAULT, cookie2->Priority());
EXPECT_TRUE(cookie2->IsSameParty());
EXPECT_TRUE(cookie2->IsPartitioned());
EXPECT_EQ(cookie2->SourceScheme(), CookieSourceScheme::kNonSecure);
// Because the port can be set explicitly in the constructor its value can be
// independent of the other parameters. In this case, test that an invalid
@ -103,6 +108,7 @@ TEST(CanonicalCookieTest, Constructor) {
EXPECT_FALSE(cookie4->IsHttpOnly());
EXPECT_EQ(CookieSameSite::NO_RESTRICTION, cookie4->SameSite());
EXPECT_FALSE(cookie4->IsSameParty());
EXPECT_FALSE(cookie4->IsPartitioned());
EXPECT_EQ(cookie4->SourceScheme(), CookieSourceScheme::kUnset);
EXPECT_EQ(cookie4->SourcePort(), url::PORT_UNSPECIFIED);
@ -110,7 +116,7 @@ TEST(CanonicalCookieTest, Constructor) {
auto cookie5 = CanonicalCookie::CreateUnsafeCookieForTesting(
"A", "2", ".www.example.com", "/", current_time, base::Time(),
base::Time(), true /* secure */, false, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false, CookieSourceScheme::kUnset,
COOKIE_PRIORITY_DEFAULT, false, absl::nullopt, CookieSourceScheme::kUnset,
url::PORT_UNSPECIFIED);
EXPECT_EQ(cookie5->SourcePort(), url::PORT_UNSPECIFIED);
@ -118,7 +124,7 @@ TEST(CanonicalCookieTest, Constructor) {
auto cookie6 = CanonicalCookie::CreateUnsafeCookieForTesting(
"A", "2", ".www.example.com", "/", current_time, base::Time(),
base::Time(), true /* secure */, false, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false, CookieSourceScheme::kUnset,
COOKIE_PRIORITY_DEFAULT, false, absl::nullopt, CookieSourceScheme::kUnset,
url::PORT_INVALID);
EXPECT_EQ(cookie6->SourcePort(), url::PORT_INVALID);
}
@ -396,6 +402,41 @@ TEST(CanonicalCookieTest, CreateSameParty) {
{CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY}));
}
TEST(CanonicalCookieTest, CreateWithPartitioned) {
GURL url("https://www.example.com/test/foo.html");
base::Time creation_time = base::Time::Now();
absl::optional<base::Time> server_time = absl::nullopt;
CookieInclusionStatus status;
// Valid Partitioned attribute
std::unique_ptr<CanonicalCookie> cookie =
CanonicalCookie::Create(url, "__Host-A=2; Partitioned; Path=/; Secure",
creation_time, server_time, &status);
ASSERT_TRUE(cookie.get());
EXPECT_TRUE(status.IsInclude());
EXPECT_TRUE(cookie->IsSecure());
// TODO(crbug.com/1225444) Uncomment line below.
// EXPECT_TRUE(cookie->IsPartitioned());
EXPECT_EQ(CookieSameSite::UNSPECIFIED, cookie->SameSite());
// Invalid Partitioned attribute: no __Host- prefix.
status = CookieInclusionStatus();
cookie = CanonicalCookie::Create(url, "A=2; Partitioned; Path=/; Secure",
creation_time, server_time, &status);
EXPECT_FALSE(cookie.get());
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_INVALID_PARTITIONED}));
// Invalid Partitioned attribute: SameParty cookie.
status = CookieInclusionStatus();
cookie = CanonicalCookie::Create(
url, "A=2; Partitioned; Path=/; Secure; SameParty", creation_time,
server_time, &status);
EXPECT_FALSE(cookie.get());
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_INVALID_PARTITIONED}));
}
TEST(CanonicalCookieTest, CreateWithMaxAge) {
GURL url("http://www.example.com/test/foo.html");
base::Time creation_time = base::Time::Now();
@ -2291,6 +2332,33 @@ TEST(CanonicalCookieTest, IsCanonical) {
base::Time(), true, false, CookieSameSite::STRICT_MODE,
COOKIE_PRIORITY_LOW, true)
->IsCanonical());
// Partitioned attribute used correctly (__Host- prefix, no SameParty).
EXPECT_TRUE(CanonicalCookie::CreateUnsafeCookieForTesting(
"__Host-A", "B", "x.y", "/", base::Time(), base::Time(),
base::Time(), true, false, CookieSameSite::UNSPECIFIED,
COOKIE_PRIORITY_LOW, false,
absl::make_optional(
net::SchemefulSite(GURL("https://toplevelsite.com"))))
->IsCanonical());
// Partitioned attribute invalid, no __Host- prefix.
EXPECT_FALSE(CanonicalCookie::CreateUnsafeCookieForTesting(
"A", "B", "x.y", "/", base::Time(), base::Time(),
base::Time(), true, false, CookieSameSite::UNSPECIFIED,
COOKIE_PRIORITY_LOW, false,
absl::make_optional(
net::SchemefulSite(GURL("https://toplevelsite.com"))))
->IsCanonical());
// Partitioned attribute invalid, SameParty attribute also included.
EXPECT_FALSE(CanonicalCookie::CreateUnsafeCookieForTesting(
"__Host-A", "B", "x.y", "/", base::Time(), base::Time(),
base::Time(), true, false, CookieSameSite::UNSPECIFIED,
COOKIE_PRIORITY_LOW, true,
absl::make_optional(
net::SchemefulSite(GURL("https://toplevelsite.com"))))
->IsCanonical());
}
TEST(CanonicalCookieTest, TestSetCreationDate) {
@ -2392,7 +2460,8 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Inputs) {
GURL("https://www.foo.com"), "A", "B", std::string(), "/foo",
base::Time(), base::Time(), base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status);
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status);
EXPECT_TRUE(cc);
EXPECT_EQ("A", cc->Name());
EXPECT_EQ("B", cc->Value());
@ -2406,6 +2475,7 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Inputs) {
EXPECT_EQ(CookieSameSite::NO_RESTRICTION, cc->SameSite());
EXPECT_EQ(COOKIE_PRIORITY_MEDIUM, cc->Priority());
EXPECT_FALSE(cc->IsSameParty());
EXPECT_FALSE(cc->IsPartitioned());
EXPECT_FALSE(cc->IsDomainCookie());
EXPECT_TRUE(status.IsInclude());
@ -2414,7 +2484,8 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Inputs) {
GURL("https://www.foo.com"), "A", "B", std::string(), "/foo",
two_hours_ago, base::Time(), base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status);
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status);
EXPECT_TRUE(cc);
EXPECT_EQ(two_hours_ago, cc->CreationDate());
EXPECT_TRUE(status.IsInclude());
@ -2424,7 +2495,8 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Inputs) {
GURL("https://www.foo.com"), "A", "B", std::string(), "/foo",
two_hours_ago, base::Time(), one_hour_ago, false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status);
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status);
EXPECT_TRUE(cc);
EXPECT_EQ(one_hour_ago, cc->LastAccessDate());
EXPECT_TRUE(status.IsInclude());
@ -2434,7 +2506,8 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Inputs) {
GURL("https://www.foo.com"), "A", "B", std::string(), "/foo",
base::Time(), one_hour_from_now, base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status);
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status);
EXPECT_TRUE(cc);
EXPECT_EQ(one_hour_from_now, cc->ExpiryDate());
EXPECT_TRUE(status.IsInclude());
@ -2444,7 +2517,8 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Inputs) {
GURL("https://www.foo.com"), "A", "B", std::string(), "/foo",
base::Time(), base::Time(), base::Time(), true /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status);
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status);
EXPECT_TRUE(cc);
EXPECT_TRUE(cc->IsSecure());
EXPECT_TRUE(status.IsInclude());
@ -2454,7 +2528,8 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Inputs) {
GURL("https://www.foo.com"), "A", "B", std::string(), "/foo",
base::Time(), base::Time(), base::Time(), false /*secure*/,
true /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status);
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status);
EXPECT_TRUE(cc);
EXPECT_TRUE(cc->IsHttpOnly());
EXPECT_TRUE(status.IsInclude());
@ -2464,7 +2539,7 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Inputs) {
GURL("https://www.foo.com"), "A", "B", std::string(), "/foo",
base::Time(), base::Time(), base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::LAX_MODE, COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status);
false /*same_party*/, absl::nullopt /*partition_key*/, &status);
EXPECT_TRUE(cc);
EXPECT_EQ(CookieSameSite::LAX_MODE, cc->SameSite());
EXPECT_TRUE(status.IsInclude());
@ -2474,7 +2549,7 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Inputs) {
GURL("https://www.foo.com"), "A", "B", std::string(), "/foo",
base::Time(), base::Time(), base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW,
false /*same_party*/, &status);
false /*same_party*/, absl::nullopt /*partition_key*/, &status);
EXPECT_TRUE(cc);
EXPECT_EQ(COOKIE_PRIORITY_LOW, cc->Priority());
EXPECT_TRUE(status.IsInclude());
@ -2484,7 +2559,8 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Inputs) {
GURL("https://www.foo.com"), "A", "B", "www.foo.com", "/foo",
base::Time(), base::Time(), base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status);
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status);
EXPECT_TRUE(cc);
EXPECT_TRUE(cc->IsDomainCookie());
EXPECT_TRUE(status.IsInclude());
@ -2494,10 +2570,22 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Inputs) {
GURL("https://www.foo.com"), "A", "B", std::string(), "/foo",
base::Time(), base::Time(), base::Time(), true /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW,
true /*same_party*/, &status);
true /*same_party*/, absl::nullopt /*partition_key*/, &status);
EXPECT_TRUE(cc);
EXPECT_TRUE(cc->IsSameParty());
EXPECT_TRUE(status.IsInclude());
// Partitioned
cc = CanonicalCookie::CreateSanitizedCookie(
GURL("https://www.foo.com"), "__Host-A", "B", std::string(), "/",
base::Time(), base::Time(), base::Time(), true /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW,
false /*same_party*/,
absl::make_optional(net::SchemefulSite(GURL("https://toplevelsite.com"))),
&status);
EXPECT_TRUE(cc);
EXPECT_TRUE(cc->IsPartitioned());
EXPECT_TRUE(status.IsInclude());
}
// Make sure sanitization and blocking of cookies works correctly.
@ -2513,19 +2601,22 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("http://www.foo.com/foo"), "A", "B", std::string(), "/foo",
one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status));
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.IsInclude());
EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie(
GURL("http://www.foo.com/bar"), "C", "D", "www.foo.com", "/",
two_hours_ago, base::Time(), one_hour_ago, false /*secure*/,
true /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status));
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.IsInclude());
EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie(
GURL("https://www.foo.com"), "E", "F", std::string(), std::string(),
base::Time(), base::Time(), base::Time(), true /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status));
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.IsInclude());
// Test the file:// protocol.
@ -2533,19 +2624,20 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("file:///"), "A", "B", std::string(), "/foo", one_hour_ago,
one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/,
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.IsInclude());
EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie(
GURL("file:///home/user/foo.txt"), "A", "B", std::string(), "/foo",
one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status));
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.IsInclude());
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("file:///home/user/foo.txt"), "A", "B", "home", "/foo", one_hour_ago,
one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/,
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN}));
@ -2554,77 +2646,88 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("http://www.foo.com/foo"), " A", "B", std::string(), "/foo",
base::Time(), base::Time(), base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status));
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE}));
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("http://www.foo.com/foo"), "A;", "B", std::string(), "/foo",
base::Time(), base::Time(), base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status));
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE}));
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("http://www.foo.com/foo"), "A=", "B", std::string(), "/foo",
base::Time(), base::Time(), base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status));
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE}));
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("http://www.foo.com/foo"), "A\x07", "B", std::string(), "/foo",
one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status));
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE}));
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("http://www.foo.com"), "A", " B", std::string(), "/foo",
base::Time(), base::Time(), base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status));
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE}));
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("http://www.foo.com"), "A", "\x0fZ", std::string(), "/foo",
base::Time(), base::Time(), base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status));
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE}));
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("http://www.foo.com"), "A", "B", "www.foo.com ", "/foo",
base::Time(), base::Time(), base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status));
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN}));
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("http://www.foo.com/foo"), "A", "B", "foo.ozzzzzzle", "/foo",
base::Time(), base::Time(), base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status));
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN}));
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("http://www.foo.com/foo"), "A", "B", std::string(), "foo",
base::Time(), base::Time(), base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status));
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE}));
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("http://www.foo.com"), "A", "B", std::string(), "/foo ",
base::Time(), base::Time(), base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status));
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE}));
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("http://www.foo.com/foo"), "A", "B", "%2Efoo.com", "/foo",
one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status));
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN}));
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
@ -2632,7 +2735,7 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
"domaintest.%E3%81%BF%E3%82%93%E3%81%AA", "/foo", base::Time(),
base::Time(), base::Time(), false /*secure*/, false /*httponly*/,
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN}));
@ -2644,7 +2747,8 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("http://www.foo.com/foo"), "A", "B", "www.foo.com", "/foo",
one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status);
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status);
ASSERT_TRUE(cc);
EXPECT_TRUE(cc->IsDomainCookie());
EXPECT_EQ(".www.foo.com", cc->Domain());
@ -2654,7 +2758,8 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("http://www.foo.com/foo"), "A", "B", ".www.foo.com", "/foo",
one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status);
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status);
ASSERT_TRUE(cc);
EXPECT_TRUE(cc->IsDomainCookie());
EXPECT_EQ(".www.foo.com", cc->Domain());
@ -2664,7 +2769,8 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("http://www.foo.com/foo"), "A", "B", ".foo.com", "/foo",
one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status);
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status);
ASSERT_TRUE(cc);
EXPECT_TRUE(cc->IsDomainCookie());
EXPECT_EQ(".foo.com", cc->Domain());
@ -2674,7 +2780,8 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("http://www.foo.com/foo"), "A", "B", ".www2.www.foo.com", "/foo",
one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status);
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status);
EXPECT_FALSE(cc);
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN}));
@ -2684,7 +2791,8 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("http://www.foo.com"), "A", "B", std::string(), "/foo ",
base::Time(), base::Time(), base::Time(), true /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status));
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE}));
@ -2693,7 +2801,7 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("http://www.foo.com"), "A", "B", std::string(), "/foo", base::Time(),
base::Time(), base::Time::Now(), false /*secure*/, false /*httponly*/,
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE}));
@ -2702,7 +2810,7 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("http://www.foo.com"), "A", "B", "www.bar.com", "/", base::Time(),
base::Time(), base::Time(), false /*secure*/, false /*httponly*/,
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN}));
@ -2711,7 +2819,8 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("http://www.foo.com"), "A", "B", std::string(), "/foo",
base::Time(), base::Time(), base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status);
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status);
ASSERT_TRUE(cc);
EXPECT_EQ("/foo%7F", cc->Path());
EXPECT_TRUE(status.IsInclude());
@ -2721,7 +2830,7 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("http://www.foo.com"), "", "", std::string(), "/", base::Time(),
base::Time(), base::Time(), false /*secure*/, false /*httponly*/,
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE}));
@ -2730,13 +2839,13 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("https://www.foo.com"), "__Secure-A", "B", ".www.foo.com", "/",
two_hours_ago, one_hour_from_now, one_hour_ago, true, false,
CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.IsInclude());
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("https://www.foo.com"), "__Secure-A", "B", ".www.foo.com", "/",
two_hours_ago, one_hour_from_now, one_hour_ago, false, false,
CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_INVALID_PREFIX}));
@ -2745,13 +2854,13 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("https://www.foo.com"), "__Host-A", "B", std::string(), "/",
two_hours_ago, one_hour_from_now, one_hour_ago, true, false,
CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.IsInclude());
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("https://www.foo.com"), "__Host-A", "B", std::string(), "/",
two_hours_ago, one_hour_from_now, one_hour_ago, false, false,
CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_INVALID_PREFIX}));
@ -2760,13 +2869,13 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("https://www.foo.com"), "__Host-A", "B", std::string(), "/",
two_hours_ago, one_hour_from_now, one_hour_ago, true, false,
CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.IsInclude());
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("https://www.foo.com"), "__Host-A", "B", std::string(), "/foo",
two_hours_ago, one_hour_from_now, one_hour_ago, true, false,
CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_INVALID_PREFIX}));
@ -2775,13 +2884,13 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("https://www.foo.com"), "__Host-A", "B", std::string(), "/",
two_hours_ago, one_hour_from_now, one_hour_ago, true, false,
CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.IsInclude());
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("https://www.foo.com"), "__Host-A", "B", ".www.foo.com", "/",
two_hours_ago, one_hour_from_now, one_hour_ago, true, false,
CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_INVALID_PREFIX}));
@ -2791,7 +2900,7 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("https://www.foo.com"), "A", "B", std::string(), "/", two_hours_ago,
one_hour_from_now, one_hour_ago, true, false,
CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.IsInclude());
// Without __Host- prefix, this is a valid domain (not host) cookie.
@ -2799,7 +2908,7 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("https://www.foo.com"), "A", "B", ".www.foo.com", "/", two_hours_ago,
one_hour_from_now, one_hour_ago, true, false,
CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.IsInclude());
// The __Host- prefix should not prevent otherwise-valid host cookies from
@ -2808,13 +2917,13 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("https://127.0.0.1"), "A", "B", std::string(), "/", two_hours_ago,
one_hour_from_now, one_hour_ago, true, false,
CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.IsInclude());
EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie(
GURL("https://127.0.0.1"), "__Host-A", "B", std::string(), "/",
two_hours_ago, one_hour_from_now, one_hour_ago, true, false,
CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.IsInclude());
// Host cookies should not specify domain unless it is an IP address that
@ -2823,13 +2932,13 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("https://127.0.0.1"), "A", "B", "127.0.0.1", "/", two_hours_ago,
one_hour_from_now, one_hour_ago, true, false,
CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.IsInclude());
EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie(
GURL("https://127.0.0.1"), "__Host-A", "B", "127.0.0.1", "/",
two_hours_ago, one_hour_from_now, one_hour_ago, true, false,
CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.IsInclude());
// SameParty attribute requires Secure and forbids SameSite=Strict.
@ -2837,30 +2946,66 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("https://www.foo.com"), "A", "B", ".www.foo.com", "/", two_hours_ago,
one_hour_from_now, one_hour_ago, true /*secure*/, false,
CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
true /*same_party*/));
true /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.IsInclude());
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("https://www.foo.com"), "A", "B", ".www.foo.com", "/", two_hours_ago,
one_hour_from_now, one_hour_ago, false /*secure*/, false,
CookieSameSite::LAX_MODE, CookiePriority::COOKIE_PRIORITY_DEFAULT,
true /*same_party*/, &status));
true /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY}));
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("https://www.foo.com"), "A", "B", ".www.foo.com", "/", two_hours_ago,
one_hour_from_now, one_hour_ago, true /*secure*/, false,
CookieSameSite::STRICT_MODE, CookiePriority::COOKIE_PRIORITY_DEFAULT,
true /*same_party*/, &status));
true /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY}));
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("https://www.foo.com"), "A", "B", ".www.foo.com", "/", two_hours_ago,
one_hour_from_now, one_hour_ago, false /*secure*/, false,
CookieSameSite::STRICT_MODE, CookiePriority::COOKIE_PRIORITY_DEFAULT,
true /*same_party*/, &status));
true /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY}));
// Partitioned attribute requires __Host- and forbids SameParty.
status = CookieInclusionStatus();
EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie(
GURL("https://www.foo.com"), "__Host-A", "B", std::string(), "/",
two_hours_ago, one_hour_from_now, one_hour_ago, true /*secure*/, false,
CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
false /*same_party*/,
absl::optional<net::SchemefulSite>(
net::SchemefulSite(GURL("https://toplevelsite.com"))),
&status));
EXPECT_TRUE(status.IsInclude());
// Invalid: no __Host- prefix
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("https://www.foo.com"), "A", "B", std::string(), "/", two_hours_ago,
one_hour_from_now, one_hour_ago, true /*secure*/, false,
CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
false /*same_party*/,
absl::optional<net::SchemefulSite>(
net::SchemefulSite(GURL("https://toplevelsite.com"))),
&status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_INVALID_PARTITIONED}));
status = CookieInclusionStatus();
// Invalid: SameParty attribute present.
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("https://www.foo.com"), "__Host-A", "B", std::string(), "/",
two_hours_ago, one_hour_from_now, one_hour_ago, true /*secure*/, false,
CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
true /*same_party*/,
absl::optional<net::SchemefulSite>(
net::SchemefulSite(GURL("https://toplevelsite.com"))),
&status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_INVALID_PARTITIONED}));
status = CookieInclusionStatus();
// Check that CreateSanitizedCookie can gracefully fail on inputs that would
// crash cookie_util::GetCookieDomainWithString due to failing
// DCHECKs. Specifically, GetCookieDomainWithString requires that if the
@ -2870,21 +3015,22 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("http://..."), "A", "B", "...", "/", base::Time(), base::Time(),
base::Time(), false /*secure*/, false /*httponly*/,
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN}));
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("http://."), "A", "B", std::string(), "/", base::Time(),
base::Time(), base::Time(), false /*secure*/, false /*httponly*/,
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN}));
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL("http://.chromium.org"), "A", "B", ".chromium.org", "/",
base::Time(), base::Time(), base::Time(), false /*secure*/,
false /*httponly*/, CookieSameSite::NO_RESTRICTION,
COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status));
COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN}));
@ -2894,7 +3040,7 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("file://[A::]"), "A", "B", "[A::]", "", base::Time(), base::Time(),
base::Time(), false /*secure*/, false /*httponly*/,
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status));
false /*same_party*/, absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.IsInclude());
// On Windows, URLs beginning with two backslashes are considered file
@ -2903,7 +3049,7 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
GURL("\\\\[A::]"), "A", "B", "[A::]", "", base::Time(), base::Time(),
base::Time(), false /*secure*/, false /*httponly*/,
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, &status);
false /*same_party*/, absl::nullopt /*partition_key*/, &status);
#if defined(OS_WIN)
EXPECT_TRUE(double_backslash_ipv6_cookie);
EXPECT_TRUE(double_backslash_ipv6_cookie->IsCanonical());
@ -2918,7 +3064,8 @@ TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) {
EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
GURL(""), "", "", "", "", base::Time(), base::Time(), base::Time::Now(),
true /*secure*/, true /*httponly*/, CookieSameSite::STRICT_MODE,
COOKIE_PRIORITY_DEFAULT, true /*same_party*/, &status));
COOKIE_PRIORITY_DEFAULT, true /*same_party*/,
absl::nullopt /*partition_key*/, &status));
EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
{CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE,
CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN,
@ -2935,7 +3082,8 @@ TEST(CanonicalCookieTest, FromStorage) {
"A", "B", "www.foo.com", "/bar", two_hours_ago, one_hour_from_now,
one_hour_ago, false /*secure*/, false /*httponly*/,
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, CookieSourceScheme::kSecure, 87);
false /*same_party*/, absl::nullopt /*partition_key*/,
CookieSourceScheme::kSecure, 87);
EXPECT_TRUE(cc);
EXPECT_EQ("A", cc->Name());
EXPECT_EQ("B", cc->Value());
@ -2959,7 +3107,8 @@ TEST(CanonicalCookieTest, FromStorage) {
"A\n", "B", "www.foo.com", "/bar", two_hours_ago, one_hour_from_now,
one_hour_ago, false /*secure*/, false /*httponly*/,
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, CookieSourceScheme::kSecure, 80));
false /*same_party*/, absl::nullopt /*partition_key*/,
CookieSourceScheme::kSecure, 80));
// If the port information gets corrupted out of the valid range
// FromStorage() should result in a PORT_INVALID.
@ -2967,7 +3116,8 @@ TEST(CanonicalCookieTest, FromStorage) {
"A", "B", "www.foo.com", "/bar", two_hours_ago, one_hour_from_now,
one_hour_ago, false /*secure*/, false /*httponly*/,
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, CookieSourceScheme::kSecure, 80000);
false /*same_party*/, absl::nullopt /*partition_key*/,
CookieSourceScheme::kSecure, 80000);
EXPECT_EQ(cc2->SourcePort(), url::PORT_INVALID);
@ -2976,7 +3126,8 @@ TEST(CanonicalCookieTest, FromStorage) {
"A", "B", "www.foo.com", "/bar", two_hours_ago, one_hour_from_now,
one_hour_ago, false /*secure*/, false /*httponly*/,
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, CookieSourceScheme::kSecure, url::PORT_UNSPECIFIED);
false /*same_party*/, absl::nullopt /*partition_key*/,
CookieSourceScheme::kSecure, url::PORT_UNSPECIFIED);
EXPECT_EQ(cc3->SourcePort(), url::PORT_UNSPECIFIED);
// Test port edge cases: invalid.
@ -2984,7 +3135,8 @@ TEST(CanonicalCookieTest, FromStorage) {
"A", "B", "www.foo.com", "/bar", two_hours_ago, one_hour_from_now,
one_hour_ago, false /*secure*/, false /*httponly*/,
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
false /*same_party*/, CookieSourceScheme::kSecure, url::PORT_INVALID);
false /*same_party*/, absl::nullopt /*partition_key*/,
CookieSourceScheme::kSecure, url::PORT_INVALID);
EXPECT_EQ(cc4->SourcePort(), url::PORT_INVALID);
}

@ -349,4 +349,6 @@ CookieSourceSchemeName GetSchemeNameEnum(const GURL& url) {
return CookieSourceSchemeName::kOther;
}
const char kEmptyCookiePartitionKey[] = "";
} // namespace net

@ -328,6 +328,13 @@ NET_EXPORT CookiePort ReducePortRangeForCookieHistogram(const int port);
// Returns the appropriate enum value for the scheme of the given GURL.
CookieSourceSchemeName GetSchemeNameEnum(const GURL& url);
// This string is used to as a placeholder for the partition_key column in
// the SQLite database. All cookies except those set with Partitioned will
// have this value in their column.
//
// Empty string was chosen because it is the smallest, non-null value.
NET_EXPORT extern const char kEmptyCookiePartitionKey[];
} // namespace net
#endif // NET_COOKIES_COOKIE_CONSTANTS_H_

@ -226,6 +226,7 @@ std::string CookieInclusionStatus::GetDebugString() const {
{EXCLUDE_INVALID_DOMAIN, "EXCLUDE_INVALID_DOMAIN"},
{EXCLUDE_INVALID_PREFIX, "EXCLUDE_INVALID_PREFIX"},
{EXCLUDE_INVALID_SAMEPARTY, "EXCLUDE_INVALID_SAMEPARTY"},
{EXCLUDE_INVALID_PARTITIONED, "EXCLUDE_INVALID_PARTITIONED"},
}) {
if (HasExclusionReason(reason.first))
base::StrAppend(&out, {reason.second, ", "});

@ -80,6 +80,10 @@ class NET_EXPORT CookieInclusionStatus {
// other attributes. (SameParty is invalid if Secure is not present, or if
// SameSite=Strict is present.)
EXCLUDE_INVALID_SAMEPARTY = 17,
/// Cookie was set with an invalid Partitioned attribute, which is only
// valid if the cookie has a __Host- prefix and does not have the SameParty
// attribute.
EXCLUDE_INVALID_PARTITIONED = 18,
// This should be kept last.
NUM_EXCLUSION_REASONS

@ -439,7 +439,8 @@ TYPED_TEST_P(CookieStoreTest, FilterTest) {
std::unique_ptr<CanonicalCookie> cc(CanonicalCookie::CreateSanitizedCookie(
this->www_foo_foo_.url(), "A", "B", std::string(), "/foo", one_hour_ago,
one_hour_from_now, base::Time(), false, false,
CookieSameSite::STRICT_MODE, COOKIE_PRIORITY_DEFAULT, false));
CookieSameSite::STRICT_MODE, COOKIE_PRIORITY_DEFAULT, false,
absl::nullopt));
ASSERT_TRUE(cc);
EXPECT_TRUE(this->SetCanonicalCookie(
cs, std::move(cc), this->www_foo_foo_.url(), true /*modify_httponly*/));
@ -449,7 +450,8 @@ TYPED_TEST_P(CookieStoreTest, FilterTest) {
cc = CanonicalCookie::CreateSanitizedCookie(
this->www_foo_bar_.url(), "C", "D", this->www_foo_bar_.domain(), "/bar",
two_hours_ago, base::Time(), one_hour_ago, false, true,
CookieSameSite::STRICT_MODE, COOKIE_PRIORITY_DEFAULT, false);
CookieSameSite::STRICT_MODE, COOKIE_PRIORITY_DEFAULT, false,
absl::nullopt);
ASSERT_TRUE(cc);
EXPECT_TRUE(this->SetCanonicalCookie(
cs, std::move(cc), this->www_foo_bar_.url(), true /*modify_httponly*/));
@ -461,7 +463,8 @@ TYPED_TEST_P(CookieStoreTest, FilterTest) {
cc = CanonicalCookie::CreateSanitizedCookie(
this->http_www_foo_.url(), "E", "F", std::string(), std::string(),
base::Time(), base::Time(), base::Time(), true, false,
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, false);
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, false,
absl::nullopt);
ASSERT_TRUE(cc);
EXPECT_FALSE(this->SetCanonicalCookie(
cs, std::move(cc), this->http_www_foo_.url(), true /*modify_httponly*/));
@ -469,7 +472,8 @@ TYPED_TEST_P(CookieStoreTest, FilterTest) {
cc = CanonicalCookie::CreateSanitizedCookie(
this->https_www_foo_.url(), "E", "F", std::string(), std::string(),
base::Time(), base::Time(), base::Time(), true, false,
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, false);
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, false,
absl::nullopt);
ASSERT_TRUE(cc);
EXPECT_TRUE(this->SetCanonicalCookie(
cs, std::move(cc), this->https_www_foo_.url(), true /*modify_httponly*/));

@ -950,8 +950,10 @@ bool SQLitePersistentCookieStore::Backend::MakeCookiesFromSQLStatement(
DBCookiePriorityToCookiePriority(
static_cast<DBCookiePriority>(smt.ColumnInt(11))), // priority
smt.ColumnBool(16), // is_same_party
DBToCookieSourceScheme(smt.ColumnInt(14)), // source_scheme
smt.ColumnInt(15)); // source_port
// TODO(crbug.com/1225444) Ingest partition_key from the cookies table.
absl::nullopt, // partition_key
DBToCookieSourceScheme(smt.ColumnInt(14)), // source_scheme
smt.ColumnInt(15)); // source_port
if (cc) {
DLOG_IF(WARNING, cc->CreationDate() > Time::Now())
<< L"CreationDate too recent";

@ -929,6 +929,7 @@ TEST_F(SQLitePersistentCookieStoreTest, SourcePortIsPersistent) {
/*secure=*/true, false, CookieSameSite::LAX_MODE,
COOKIE_PRIORITY_DEFAULT,
/*same_party=*/false,
/*partition_key=*/absl::nullopt,
CookieSourceScheme::kUnset /* Doesn't matter for this test. */,
input.port));
}

@ -444,6 +444,10 @@ bool StructTraits<
if (!cookie.ReadPriority(&priority))
return false;
absl::optional<net::SchemefulSite> partition_key;
if (!cookie.ReadPartitionKey(&partition_key))
return false;
net::CookieSourceScheme source_scheme;
if (!cookie.ReadSourceScheme(&source_scheme))
return false;
@ -452,8 +456,8 @@ bool StructTraits<
std::move(name), std::move(value), std::move(domain), std::move(path),
std::move(creation_time), std::move(expiry_time),
std::move(last_access_time), cookie.secure(), cookie.httponly(),
site_restrictions, priority, cookie.same_party(), source_scheme,
cookie.source_port());
site_restrictions, priority, cookie.same_party(), partition_key,
source_scheme, cookie.source_port());
if (!cc)
return false;
*out = *cc;

@ -198,6 +198,10 @@ struct StructTraits<network::mojom::CanonicalCookieDataView,
static bool same_party(const net::CanonicalCookie& c) {
return c.IsSameParty();
}
static absl::optional<net::SchemefulSite> partition_key(
const net::CanonicalCookie& c) {
return c.PartitionKey();
}
static int source_port(const net::CanonicalCookie& c) {
return c.SourcePort();
}

@ -22,7 +22,7 @@ TEST(CookieManagerTraitsTest, Roundtrips_CanonicalCookie) {
auto original = net::CanonicalCookie::CreateUnsafeCookieForTesting(
"A", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(), false,
false, net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_LOW,
false, net::CookieSourceScheme::kSecure, 8433);
false, absl::nullopt, net::CookieSourceScheme::kSecure, 8433);
net::CanonicalCookie copied;
@ -41,6 +41,7 @@ TEST(CookieManagerTraitsTest, Roundtrips_CanonicalCookie) {
EXPECT_EQ(original->SameSite(), copied.SameSite());
EXPECT_EQ(original->Priority(), copied.Priority());
EXPECT_EQ(original->IsSameParty(), copied.IsSameParty());
EXPECT_EQ(absl::nullopt, copied.PartitionKey());
EXPECT_EQ(original->SourceScheme(), copied.SourceScheme());
EXPECT_EQ(original->SourcePort(), copied.SourcePort());
@ -49,8 +50,8 @@ TEST(CookieManagerTraitsTest, Roundtrips_CanonicalCookie) {
net::CanonicalCookie::CreateUnsafeCookieForTesting(
"A", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(),
false, false, net::CookieSameSite::NO_RESTRICTION,
net::COOKIE_PRIORITY_LOW, false, net::CookieSourceScheme::kSecure,
url::PORT_UNSPECIFIED);
net::COOKIE_PRIORITY_LOW, false, absl::nullopt,
net::CookieSourceScheme::kSecure, url::PORT_UNSPECIFIED);
net::CanonicalCookie copied_unspecified;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CanonicalCookie>(
@ -63,7 +64,8 @@ TEST(CookieManagerTraitsTest, Roundtrips_CanonicalCookie) {
auto original_invalid = net::CanonicalCookie::CreateUnsafeCookieForTesting(
"A", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(), false,
false, net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_LOW,
false, net::CookieSourceScheme::kSecure, url::PORT_INVALID);
false, absl::nullopt, net::CookieSourceScheme::kSecure,
url::PORT_INVALID);
net::CanonicalCookie copied_invalid;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CanonicalCookie>(
@ -326,6 +328,22 @@ TEST(CookieManagerTraitsTest, Roundtrips_SamePartyCookieContextType) {
}
}
TEST(CookieManagerTraitsTest, Roundtrips_PartitionKey) {
auto original = net::CanonicalCookie::CreateUnsafeCookieForTesting(
"__Host-A", "B", "x.y", "/", base::Time(), base::Time(), base::Time(),
true, false, net::CookieSameSite::NO_RESTRICTION,
net::COOKIE_PRIORITY_LOW, false,
absl::make_optional(
net::SchemefulSite::Deserialize("https://toplevelsite.com")),
net::CookieSourceScheme::kSecure, 8433);
net::CanonicalCookie copied;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CanonicalCookie>(
*original, copied));
EXPECT_EQ(original->PartitionKey(), copied.PartitionKey());
}
TEST(CookieManagerTraitsTest, Roundtrips_CookieOptions) {
{
net::CookieOptions least_trusted, copy;

@ -6,6 +6,7 @@ module network.mojom;
import "components/content_settings/core/common/content_settings.mojom";
import "mojo/public/mojom/base/time.mojom";
import "services/network/public/mojom/schemeful_site.mojom";
import "url/mojom/url.mojom";
// Parameters for constructing a cookie manager.
@ -157,6 +158,7 @@ struct CanonicalCookie {
CookiePriority priority = MEDIUM;
CookieSourceScheme source_scheme = kUnset;
bool same_party = false;
SchemefulSite? partition_key;
// -1 because of url::PORT_UNSPECIFIED
// url/third_party/mozilla/url_parse.h
int32 source_port = -1;

@ -443,8 +443,8 @@ void RestrictedCookieManager::SetCanonicalCookie(
auto sanitized_cookie = net::CanonicalCookie::FromStorage(
cookie.Name(), cookie.Value(), cookie.Domain(), cookie.Path(), now,
cookie.ExpiryDate(), now, cookie.IsSecure(), cookie.IsHttpOnly(),
cookie.SameSite(), cookie.Priority(), cookie.IsSameParty(), source_scheme,
origin_.port());
cookie.SameSite(), cookie.Priority(), cookie.IsSameParty(),
cookie.PartitionKey(), source_scheme, origin_.port());
DCHECK(sanitized_cookie);
net::CanonicalCookie cookie_copy = *sanitized_cookie;

@ -152,11 +152,13 @@ std::unique_ptr<net::CanonicalCookie> ToCanonicalCookie(
}
// TODO(crbug.com/1144187): Add support for SameParty attribute.
// TODO(crbug.com/1225444): Add support for Partitioned attrbute.
return net::CanonicalCookie::CreateSanitizedCookie(
cookie_url, name.Utf8(), value.Utf8(), domain.Utf8(), path.Utf8(),
base::Time() /*creation*/, expires, base::Time() /*last_access*/,
true /*secure*/, false /*http_only*/, same_site,
net::CookiePriority::COOKIE_PRIORITY_DEFAULT, false /*same_party*/);
net::CookiePriority::COOKIE_PRIORITY_DEFAULT, false /*same_party*/,
absl::nullopt /*partition_key*/);
}
const KURL DefaultCookieURL(ExecutionContext* execution_context) {