electron/patches/chromium/revert_same_party_cookie_at...

6098 lines
278 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Keeley Hammond <khammond@slack-corp.com>
Date: Tue, 27 Feb 2024 22:34:57 -0800
Subject: feat: revert sameparty cookie attribute removal
The SameParty cookie attribute, which is used for same-party, cross-site
contexts with First Party Sets, has been removed upstream by Chrome, but is
depended on by some Electron consumers. This patch is meant to restore the
removed SameParty cookie origin trail functionality and supported methods, while
Chrome completes other API options to use in place of SameParty cookies.
This patch can be removed when Storage Access API cookie support or
equivalent support is completed upstream.
Revert "[RWS] Rewrite FPSParser to return net::GlobalFirstPartySets" | This reverts commit 3d65d32b9dbfa822c8883a11ea7b3f1cb3aacd00.
Revert "[RWS] Remove enum from parser's public API" | This reverts commit e0404fe08b2823ca2546bd2665e986595ebf43b2.
5146347: [RWS] Introduce a wrapper type to hold RWSOverrides policy data | https://chromium-review.googlesource.com/c/chromium/src/+/5146347
Revert "[RWS] Introduce SetsMutation type to uphold invariants" | This reverts commit 7d1bad4a311e8532a56e65eb68557f51e7c1c35e.
Revert "[RWS] Store local-set-aliases separately; detect shadowing properly" | This reverts commit d4176432c1cf25b3eb6de159ec3aa0e9a1c1eec0.
Revert "[RWS] Rewrite LocalSetDeclaration ctor to accept aliases separately" | This reverts commit 60fa94a5216486f0a64550661db375c909a710d4.
Revert "[RWS] Move switch-parsing code to FPSParser; move LocalSetDecl to net/" | This reverts commit bd490b71bd1ce505f0ec9f1749ae4d1079e008b7.
Revert "[RWS] Remove CanonicalCookie::IsSameParty method" | This reverts commit 009417ac633095bcd3d0b8eca6b00b5189c1ca1f.
Revert "[RWS] Remove unused same_party ctor parameter" | This reverts commit 23703ad3a827df582cff2b9844c8179f15281a5d.
Revert "[RWS] Remove SameParty state from CanonicalCookie and ParsedCookie" | This reverts commit 2f9574c931607cbb64d17b66a6e28f7408ef7457.
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index de3be2eec25ccf745d1b8d11e7125803ca16167d..e37c9dcf44feaaff89084914165abc19f648e104 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -8666,6 +8666,10 @@ const FeatureEntry kFeatureEntries[] = {
flag_descriptions::kChromeRefresh2023TopChromeFontDescription, kOsDesktop,
FEATURE_VALUE_TYPE(features::kChromeRefresh2023TopChromeFont)},
+ {"enable-first-party-sets", flag_descriptions::kEnableFirstPartySetsName,
+ flag_descriptions::kEnableFirstPartySetsDescription, kOsAll,
+ FEATURE_VALUE_TYPE(features::kFirstPartySets)},
+
#if BUILDFLAG(IS_ANDROID)
{"autofill-enable-offers-in-clank-keyboard-accessory",
flag_descriptions::kAutofillEnableOffersInClankKeyboardAccessoryName,
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 8ac74856217e4840b89d2e60e5ffeef160e46d6d..a5d6da17287c22e8a3c095d56be97c87f6ef6f96 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -1168,10 +1168,6 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
std::string GetChildProcessSuffix(int child_flags) override;
#endif // BUILDFLAG(IS_MAC)
- // Tracks whether the browser was started in "minimal" mode (as opposed to
- // full browser mode), where most subsystems are not initialized.
- bool is_minimal_mode_ = false;
-
base::WeakPtrFactory<ChromeContentBrowserClient> weak_factory_{this};
};
diff --git a/chrome/browser/component_updater/first_party_sets_component_installer.cc b/chrome/browser/component_updater/first_party_sets_component_installer.cc
index ed00b8e7e9dcd36e0347290172892e3b58b8cb3d..a63fdb27bbf9c6c3d9c5c5d4b4976453a3103564 100644
--- a/chrome/browser/component_updater/first_party_sets_component_installer.cc
+++ b/chrome/browser/component_updater/first_party_sets_component_installer.cc
@@ -42,7 +42,7 @@ constexpr uint8_t kFirstPartySetsPublicKeySHA256[32] = {
0xff, 0x1c, 0x65, 0x66, 0x14, 0xa8, 0x46, 0x37, 0xe6, 0xeb, 0x80,
0x8b, 0x8f, 0xb0, 0xb6, 0x18, 0xa7, 0xcd, 0x3d, 0xbb, 0xfb};
-constexpr char kFirstPartySetsManifestName[] = "Related Website Sets";
+constexpr char kFirstPartySetsManifestName[] = "First-Party Sets";
constexpr base::FilePath::CharType kFirstPartySetsRelativeInstallDir[] =
FILE_PATH_LITERAL("FirstPartySetsPreloaded");
@@ -157,8 +157,8 @@ void FirstPartySetsComponentInstallerPolicy::ComponentReady(
return;
}
- VLOG(1) << "Related Website Sets Component ready, version "
- << version.GetString() << " in " << install_dir.value();
+ VLOG(1) << "First-Party Sets Component ready, version " << version.GetString()
+ << " in " << install_dir.value();
GetConfigPathInstance() =
std::make_pair(GetInstalledPath(install_dir), version);
@@ -202,12 +202,12 @@ void FirstPartySetsComponentInstallerPolicy::ResetForTesting() {
}
void RegisterFirstPartySetsComponent(ComponentUpdateService* cus) {
- VLOG(1) << "Registering Related Website Sets component.";
+ VLOG(1) << "Registering First-Party Sets component.";
auto policy = std::make_unique<FirstPartySetsComponentInstallerPolicy>(
/*on_sets_ready=*/base::BindOnce([](base::Version version,
base::File sets_file) {
- VLOG(1) << "Received Related Website Sets";
+ VLOG(1) << "Received First-Party Sets";
content::FirstPartySetsHandler::GetInstance()->SetPublicFirstPartySets(
version, std::move(sets_file));
}));
diff --git a/chrome/browser/extensions/api/cookies/cookies_api.cc b/chrome/browser/extensions/api/cookies/cookies_api.cc
index 37704856cf800a479cf20774047f6694e2374405..4eda7e676a6ac67b7673b5306e531426bb335d9c 100644
--- a/chrome/browser/extensions/api/cookies/cookies_api.cc
+++ b/chrome/browser/extensions/api/cookies/cookies_api.cc
@@ -487,6 +487,7 @@ ExtensionFunction::ResponseAction CookiesSetFunction::Run() {
break;
}
+ // TODO(crbug.com/1144181): Add support for SameParty attribute.
std::unique_ptr<net::CanonicalCookie> cc(
net::CanonicalCookie::CreateSanitizedCookie(
url_, //
@@ -501,6 +502,7 @@ ExtensionFunction::ResponseAction CookiesSetFunction::Run() {
parsed_args_->details.http_only.value_or(false), //
same_site, //
net::COOKIE_PRIORITY_DEFAULT, //
+ /*same_party=*/false, //
partition_key));
if (!cc) {
// Return error through callbacks so that the proper error message
diff --git a/chrome/browser/first_party_sets/first_party_sets_policy_service.cc b/chrome/browser/first_party_sets/first_party_sets_policy_service.cc
index 0509dabf8f42123851e5eea62d0f8f9575784f7c..c873b3d2881dd0cccc93658b2f6cabb97b64d287 100644
--- a/chrome/browser/first_party_sets/first_party_sets_policy_service.cc
+++ b/chrome/browser/first_party_sets/first_party_sets_policy_service.cc
@@ -132,6 +132,7 @@ void FirstPartySetsPolicyService::Init() {
void FirstPartySetsPolicyService::ComputeFirstPartySetMetadata(
const net::SchemefulSite& site,
const net::SchemefulSite* top_frame_site,
+ const std::set<net::SchemefulSite>& party_context,
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!is_enabled()) {
@@ -143,17 +144,18 @@ void FirstPartySetsPolicyService::ComputeFirstPartySetMetadata(
on_ready_callbacks_.push_back(base::BindOnce(
&FirstPartySetsPolicyService::ComputeFirstPartySetMetadataInternal,
weak_factory_.GetWeakPtr(), site, base::OptionalFromPtr(top_frame_site),
- std::move(callback)));
+ party_context, std::move(callback)));
return;
}
content::FirstPartySetsHandler::GetInstance()->ComputeFirstPartySetMetadata(
- site, top_frame_site, *config_, std::move(callback));
+ site, top_frame_site, party_context, *config_, std::move(callback));
}
void FirstPartySetsPolicyService::ComputeFirstPartySetMetadataInternal(
const net::SchemefulSite& site,
- const std::optional<net::SchemefulSite>& top_frame_site,
+ const absl::optional<net::SchemefulSite>& top_frame_site,
+ const std::set<net::SchemefulSite>& party_context,
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(config_.has_value());
@@ -164,7 +166,8 @@ void FirstPartySetsPolicyService::ComputeFirstPartySetMetadataInternal(
}
content::FirstPartySetsHandler::GetInstance()->ComputeFirstPartySetMetadata(
- site, base::OptionalToPtr(top_frame_site), *config_, std::move(callback));
+ site, base::OptionalToPtr(top_frame_site), party_context, *config_,
+ std::move(callback));
}
void FirstPartySetsPolicyService::AddRemoteAccessDelegate(
diff --git a/chrome/browser/first_party_sets/first_party_sets_policy_service.h b/chrome/browser/first_party_sets/first_party_sets_policy_service.h
index 3c41142b75ecc46dc3027287f67a667f091d6286..4489926000ec04ca5b854404d0c573a551a64b06 100644
--- a/chrome/browser/first_party_sets/first_party_sets_policy_service.h
+++ b/chrome/browser/first_party_sets/first_party_sets_policy_service.h
@@ -63,6 +63,7 @@ class FirstPartySetsPolicyService : public KeyedService {
void ComputeFirstPartySetMetadata(
const net::SchemefulSite& site,
const net::SchemefulSite* top_frame_site,
+ const std::set<net::SchemefulSite>& party_context,
base::OnceCallback<void(net::FirstPartySetMetadata)> callback);
// Stores `access_delegate` in a RemoteSet for later IPC calls on it when this
@@ -191,7 +192,8 @@ class FirstPartySetsPolicyService : public KeyedService {
// callback. Must not be called before `config_` has been received.
void ComputeFirstPartySetMetadataInternal(
const net::SchemefulSite& site,
- const std::optional<net::SchemefulSite>& top_frame_site,
+ const absl::optional<net::SchemefulSite>& top_frame_site,
+ const std::set<net::SchemefulSite>& party_context,
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const;
// Clears the content settings associated with `profile` that were
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index d70932e1ad965a3f59014d93e227bc11aadece40..30ba3aaa758327ecad2d205eaca5f1b633c9185b 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2813,6 +2813,11 @@
"owners": [ "chromeos-dlp@google.com", "accorsi@chromium.org" ],
"expiry_milestone": 130
},
+ {
+ "name": "enable-first-party-sets",
+ "owners": [ "chrome-first-party-sets@chromium.org" ],
+ "expiry_milestone": 120
+ },
{
"name": "enable-follow-IPH-exp-params",
"owners": [ "sczs@chromium.org", "tinazwang@chromium.org" ],
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 8385c597f050e421cd6735fc4286389c94f12b5a..09189e029a958477938b56981c9929246f1ec886 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -424,6 +424,11 @@ const char kUseDnsHttpsSvcbAlpnDescription[] =
"When enabled, Chrome may try QUIC on the first connection using the ALPN"
" information in the DNS HTTPS record.";
+const char kEnableFirstPartySetsName[] = "Enable First-Party Sets";
+const char kEnableFirstPartySetsDescription[] =
+ "When enabled, Chrome will enable First-Party Sets and the Storage Access "
+ "API.";
+
const char kIsolatedSandboxedIframesName[] = "Isolated sandboxed iframes";
const char kIsolatedSandboxedIframesDescription[] =
"When enabled, applies process isolation to iframes with the 'sandbox' "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index a023e473a3c31dca19d214555e67af3dfb1a0b42..e4b5eb3fa6fb872fb0977eb50a48a95e14d6072b 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -526,6 +526,9 @@ extern const char kUseDnsHttpsSvcbAlpnDescription[];
extern const char kEditContextName[];
extern const char kEditContextDescription[];
+extern const char kEnableFirstPartySetsName[];
+extern const char kEnableFirstPartySetsDescription[];
+
extern const char kIsolatedSandboxedIframesName[];
extern const char kIsolatedSandboxedIframesDescription[];
diff --git a/chrome/browser/storage_access_api/storage_access_grant_permission_context.cc b/chrome/browser/storage_access_api/storage_access_grant_permission_context.cc
index e968e807e13c12525f8d19ee6347e39fa9e11c6c..ddfbc69538d435a15b12e0a006a8acaca73af673 100644
--- a/chrome/browser/storage_access_api/storage_access_grant_permission_context.cc
+++ b/chrome/browser/storage_access_api/storage_access_grant_permission_context.cc
@@ -292,7 +292,8 @@ void StorageAccessGrantPermissionContext::DecidePermission(
first_party_sets::FirstPartySetsPolicyServiceFactory::GetForBrowserContext(
browser_context())
->ComputeFirstPartySetMetadata(
- requesting_site, &embedding_site,
+ net::SchemefulSite(requesting_origin), &embedding_site,
+ /*party_context=*/{},
base::BindOnce(&StorageAccessGrantPermissionContext::
CheckForAutoGrantOrAutoDenial,
weak_factory_.GetWeakPtr(), std::move(request_data),
diff --git a/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context.cc b/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context.cc
index 796307897e89b979689398db639bd95e89e13dc2..c52cff9c19a250e411db3b0deb0f614cb48129ae 100644
--- a/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context.cc
+++ b/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context.cc
@@ -84,7 +84,8 @@ void TopLevelStorageAccessPermissionContext::DecidePermission(
first_party_sets::FirstPartySetsPolicyServiceFactory::GetForBrowserContext(
browser_context())
->ComputeFirstPartySetMetadata(
- requesting_site, &embedding_site,
+ net::SchemefulSite(requesting_origin), &embedding_site,
+ /*party_context=*/{},
base::BindOnce(&TopLevelStorageAccessPermissionContext::
CheckForAutoGrantOrAutoDenial,
weak_factory_.GetWeakPtr(), std::move(request_data),
diff --git a/components/signin/core/browser/consistency_cookie_manager.cc b/components/signin/core/browser/consistency_cookie_manager.cc
index f4308054e070b4468ef2f22da88a25132ce92ca9..421f9ab6edf717128b255019bb3da7831df879a4 100644
--- a/components/signin/core/browser/consistency_cookie_manager.cc
+++ b/components/signin/core/browser/consistency_cookie_manager.cc
@@ -115,7 +115,7 @@ ConsistencyCookieManager::CreateConsistencyCookie(const std::string& value) {
/*path=*/"/", /*creation=*/now, /*expiration=*/expiry,
/*last_access=*/now, /*secure=*/true, /*httponly=*/false,
net::CookieSameSite::STRICT_MODE, net::COOKIE_PRIORITY_DEFAULT,
- /*partition_key=*/absl::nullopt);
+ /*same_party=*/false, /*partition_key=*/absl::nullopt);
}
// static
diff --git a/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc b/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc
index 2e8e994bd86df365d15255d7214becc5d5db798c..db330455e9e22ca27e9a2602ba5bdc206dba6b7b 100644
--- a/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc
+++ b/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc
@@ -569,7 +569,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,
- absl::nullopt /* cookie_partition_key */);
+ false /* same_party */, absl::nullopt /* cookie_partition_key */);
OnCookieChange(
net::CookieChangeInfo(*cookie, net::CookieAccessResult(),
net::CookieChangeCause::UNKNOWN_DELETION));
diff --git a/components/signin/ios/browser/account_consistency_service.mm b/components/signin/ios/browser/account_consistency_service.mm
index 592a2dc9a34ac8edb9de34f9429c8a20eca9cfe0..2798cc7eec57d2c6b2d843343c1b575d3abbe283 100644
--- a/components/signin/ios/browser/account_consistency_service.mm
+++ b/components/signin/ios/browser/account_consistency_service.mm
@@ -490,7 +490,7 @@ void ShouldAllowResponse(
/*last_access_time=*/base::Time(),
/*secure=*/true,
/*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_DEFAULT,
+ net::COOKIE_PRIORITY_DEFAULT, /*same_party=*/false,
/*partition_key=*/absl::nullopt);
net::CookieOptions options;
options.set_include_httponly();
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc
index 48f1cdd0a7763242b81c7a54cad72700c8a42af1..3aba25d150732df04798606f732ceee06eea8c6e 100644
--- a/content/app/content_main_runner_impl.cc
+++ b/content/app/content_main_runner_impl.cc
@@ -60,7 +60,6 @@
#include "content/browser/browser_main.h"
#include "content/browser/browser_process_io_thread.h"
#include "content/browser/browser_thread_impl.h"
-#include "content/browser/first_party_sets/first_party_sets_handler_impl.h"
#include "content/browser/gpu/gpu_main_thread_factory.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/scheduler/browser_task_executor.h"
@@ -104,7 +103,6 @@
#include "mojo/public/cpp/system/dynamic_library_support.h"
#include "mojo/public/cpp/system/invitation.h"
#include "mojo/public/cpp/system/message_pipe.h"
-#include "net/first_party_sets/local_set_declaration.h"
#include "ppapi/buildflags/buildflags.h"
#include "sandbox/policy/sandbox.h"
#include "sandbox/policy/sandbox_type.h"
@@ -1253,14 +1251,8 @@ int ContentMainRunnerImpl::RunBrowser(MainFunctionParams main_params,
AndroidBatteryMetrics::CreateInstance();
#endif
- GetContentClient()->browser()->SetIsMinimalMode(start_minimal_browser);
- if (start_minimal_browser) {
+ if (start_minimal_browser)
ForceInProcessNetworkService();
- // Minimal browser mode doesn't initialize First-Party Sets the "usual"
- // way, so we do it manually.
- content::FirstPartySetsHandlerImpl::GetInstance()->Init(
- base::FilePath(), net::LocalSetDeclaration());
- }
discardable_shared_memory_manager_ =
std::make_unique<discardable_memory::DiscardableSharedMemoryManager>();
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 143c98e3294fb07b08c1d8e97013034f8453e074..d88619297a9e3507bb2132b3713e2ead65e6168b 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1021,15 +1021,16 @@ source_set("browser") {
"first_party_sets/first_party_set_parser.h",
"first_party_sets/first_party_sets_handler_database_helper.cc",
"first_party_sets/first_party_sets_handler_database_helper.h",
+ "first_party_sets/first_party_sets_handler_impl.cc",
"first_party_sets/first_party_sets_handler_impl.h",
- "first_party_sets/first_party_sets_handler_impl_instance.cc",
- "first_party_sets/first_party_sets_handler_impl_instance.h",
"first_party_sets/first_party_sets_loader.cc",
"first_party_sets/first_party_sets_loader.h",
"first_party_sets/first_party_sets_overrides_policy.cc",
"first_party_sets/first_party_sets_overrides_policy.h",
"first_party_sets/first_party_sets_site_data_remover.cc",
"first_party_sets/first_party_sets_site_data_remover.h",
+ "first_party_sets/local_set_declaration.cc",
+ "first_party_sets/local_set_declaration.h",
"font_access/font_access_manager.cc",
"font_access/font_access_manager.h",
"font_access/font_enumeration_cache.cc",
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 8c144725c6e54172d01b90e1d1196679a53f4b78..6f3661179225e322b2343e6ff4600073966a682d 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -70,8 +70,8 @@
#include "content/browser/compositor/viz_process_transport_factory.h"
#include "content/browser/download/save_file_manager.h"
#include "content/browser/field_trial_synchronizer.h"
-#include "content/browser/first_party_sets/first_party_set_parser.h"
#include "content/browser/first_party_sets/first_party_sets_handler_impl.h"
+#include "content/browser/first_party_sets/local_set_declaration.h"
#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
#include "content/browser/gpu/browser_gpu_client_delegate.h"
#include "content/browser/gpu/compositor_util.h"
@@ -1009,8 +1009,7 @@ int BrowserMainLoop::PreMainMessageLoopRun() {
if (result_code_ == RESULT_CODE_NORMAL_EXIT) {
FirstPartySetsHandlerImpl::GetInstance()->Init(
GetContentClient()->browser()->GetFirstPartySetsDirectory(),
- FirstPartySetParser::ParseFromCommandLine(
- GetRelatedWebsiteSetSwitch()));
+ LocalSetDeclaration(GetRelatedWebsiteSetSwitch()));
}
variations::MaybeScheduleFakeCrash();
diff --git a/content/browser/cookie_store/cookie_change_subscription.cc b/content/browser/cookie_store/cookie_change_subscription.cc
index dbe3c5b8a6c83c5e8d26b109f24e77b4ab2e604e..fd51ab0f749b63fda2a7848594bb616fe6a48730 100644
--- a/content/browser/cookie_store/cookie_change_subscription.cc
+++ b/content/browser/cookie_store/cookie_change_subscription.cc
@@ -9,8 +9,10 @@
#include "content/browser/cookie_store/cookie_change_subscriptions.pb.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/content_client.h"
+#include "net/base/features.h"
#include "net/cookies/cookie_constants.h"
#include "net/cookies/cookie_util.h"
+#include "net/first_party_sets/same_party_context.h"
#include "services/network/public/cpp/is_potentially_trustworthy.h"
namespace content {
@@ -169,17 +171,26 @@ bool CookieChangeSubscription::ShouldObserveChangeTo(
break;
}
- // We assume that this is a same-site context.
+ // We assume that this is a same-site, same-party context.
net::CookieOptions net_options;
net_options.set_same_site_cookie_context(
net::CookieOptions::SameSiteCookieContext::MakeInclusive());
+ net_options.set_same_party_context(net::SamePartyContext::MakeInclusive());
+ // It doesn't matter which we choose here, since both SameParty and SameSite
+ // semantics should allow this access. But we make a choice to be explicit.
+ net_options.set_is_in_nontrivial_first_party_set(true);
return cookie
- .IncludeForRequestURL(url_, net_options,
- net::CookieAccessParams{
- access_semantics,
- network::IsUrlPotentiallyTrustworthy(url_),
- })
+ .IncludeForRequestURL(
+ url_, net_options,
+ net::CookieAccessParams{
+ access_semantics,
+ network::IsUrlPotentiallyTrustworthy(url_),
+ net::cookie_util::GetSamePartyStatus(
+ cookie, net_options,
+ base::FeatureList::IsEnabled(
+ net::features::kSamePartyAttributeEnabled)),
+ })
.status.IsInclude();
}
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc
index 2bbc46fd4748246b7fa3e6a8cfe38b43684bf8d7..452b5ee7f29d8778326880f7a92bac996e97245a 100644
--- a/content/browser/devtools/protocol/network_handler.cc
+++ b/content/browser/devtools/protocol/network_handler.cc
@@ -186,7 +186,7 @@ std::unique_ptr<Network::Cookie> BuildCookie(
.SetSecure(cookie.IsSecure())
.SetSession(!cookie.IsPersistent())
.SetPriority(BuildCookiePriority(cookie.Priority()))
- .SetSameParty(false)
+ .SetSameParty(cookie.IsSameParty())
.SetSourceScheme(BuildCookieSourceScheme(cookie.SourceScheme()))
.SetSourcePort(cookie.SourcePort())
.Build();
@@ -349,6 +349,7 @@ MakeCookieFromProtocolValues(const std::string& name,
const std::string& same_site,
double expires,
const std::string& priority,
+ bool same_party,
const Maybe<std::string>& source_scheme,
const Maybe<int>& source_port,
const Maybe<std::string>& partition_key) {
@@ -423,7 +424,7 @@ MakeCookieFromProtocolValues(const std::string& name,
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,
+ expiration_date, base::Time(), secure, http_only, css, cp, same_party,
deserialized_partition_key);
if (!cookie)
@@ -1567,8 +1568,8 @@ void NetworkHandler::SetCookie(const std::string& name,
auto cookie_or_error = MakeCookieFromProtocolValues(
name, value, url.value_or(""), domain.value_or(""), path.value_or(""),
secure.value_or(false), http_only.value_or(false), same_site.value_or(""),
- expires.value_or(-1), priority.value_or(""), source_scheme, source_port,
- partition_key);
+ expires.value_or(-1), priority.value_or(""), same_party.value_or(false),
+ source_scheme, source_port, partition_key);
if (absl::holds_alternative<Response>(cookie_or_error)) {
callback->sendFailure(absl::get<Response>(std::move(cookie_or_error)));
@@ -1616,8 +1617,8 @@ void NetworkHandler::SetCookies(
cookie->GetName(), cookie->GetValue(), cookie->GetUrl(""),
cookie->GetDomain(""), cookie->GetPath(""), cookie->GetSecure(false),
cookie->GetHttpOnly(false), cookie->GetSameSite(""),
- cookie->GetExpires(-1), cookie->GetPriority(""), source_scheme,
- source_port, partition_key);
+ cookie->GetExpires(-1), cookie->GetPriority(""),
+ cookie->GetSameParty(false), source_scheme, source_port, partition_key);
if (absl::holds_alternative<Response>(net_cookie_or_error)) {
// TODO: Investiage whether we can report the error as a protocol error
// (this might be a breaking CDP change).
diff --git a/content/browser/first_party_sets/first_party_set_parser.cc b/content/browser/first_party_sets/first_party_set_parser.cc
index 5465b7801280a76017e4cb0552d01a4d179b7dc7..af422c4a8c7221048c5f061344ffbfc71b8f548d 100644
--- a/content/browser/first_party_sets/first_party_set_parser.cc
+++ b/content/browser/first_party_sets/first_party_set_parser.cc
@@ -29,9 +29,7 @@
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/base/schemeful_site.h"
#include "net/first_party_sets/first_party_set_entry.h"
-#include "net/first_party_sets/global_first_party_sets.h"
-#include "net/first_party_sets/local_set_declaration.h"
-#include "net/first_party_sets/sets_mutation.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -43,10 +41,9 @@ using ParseErrorType = FirstPartySetsHandler::ParseErrorType;
using ParseWarningType = FirstPartySetsHandler::ParseWarningType;
using ParseError = FirstPartySetsHandler::ParseError;
using ParseWarning = FirstPartySetsHandler::ParseWarning;
-using SetsMap = base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>;
-using Aliases = base::flat_map<net::SchemefulSite, net::SchemefulSite>;
-using SetsAndAliases = std::pair<SetsMap, Aliases>;
-using SingleSet = base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>;
+using Aliases = FirstPartySetParser::Aliases;
+using SetsAndAliases = FirstPartySetParser::SetsAndAliases;
+using SetsMap = FirstPartySetParser::SetsMap;
constexpr char kFirstPartySetPrimaryField[] = "primary";
constexpr char kFirstPartySetAssociatedSitesField[] = "associatedSites";
@@ -57,13 +54,11 @@ constexpr char kFirstPartySetPolicyAdditionsField[] = "additions";
constexpr int kFirstPartySetsMaxAssociatedSites = 5;
-enum class PolicySetType { kReplacement, kAddition };
-
-const char* SetTypeToString(PolicySetType set_type) {
+const char* SetTypeToString(FirstPartySetParser::PolicySetType set_type) {
switch (set_type) {
- case PolicySetType::kReplacement:
+ case FirstPartySetParser::PolicySetType::kReplacement:
return kFirstPartySetPolicyReplacementsField;
- case PolicySetType::kAddition:
+ case FirstPartySetParser::PolicySetType::kAddition:
return kFirstPartySetPolicyAdditionsField;
}
}
@@ -154,11 +149,6 @@ std::optional<std::string> RemoveTldFromSite(const net::SchemefulSite& site) {
return serialized.substr(0, serialized.size() - tld_length);
}
-struct ParsedPolicySetLists {
- std::vector<SingleSet> replacements;
- std::vector<SingleSet> additions;
-};
-
class ParseContext {
public:
ParseContext(bool emit_errors, bool exempt_from_limits)
@@ -273,18 +263,18 @@ class ParseContext {
{kFirstPartySetAssociatedSitesField}));
}
- return std::make_pair(SingleSet(set_entries), aliases);
+ return std::make_pair(FirstPartySetParser::SingleSet(set_entries), aliases);
}
// Returns the parsed sets if successful; otherwise returns the first error.
- base::expected<std::vector<SingleSet>, ParseError> GetPolicySetsFromList(
- const base::Value::List* policy_sets,
- PolicySetType set_type) {
+ base::expected<std::vector<FirstPartySetParser::SingleSet>, ParseError>
+ GetPolicySetsFromList(const base::Value::List* policy_sets,
+ FirstPartySetParser::PolicySetType set_type) {
if (!policy_sets) {
return {};
}
- std::vector<SingleSet> parsed_sets;
+ std::vector<FirstPartySetParser::SingleSet> parsed_sets;
size_t previous_size = warnings_.size();
for (int i = 0; i < static_cast<int>(policy_sets->size()); i++) {
base::expected<SetsAndAliases, ParseError> parsed =
@@ -339,20 +329,13 @@ class ParseContext {
// Removes invalid site entries and aliases, and fixes up any lingering
// singletons. Modifies the data in-place.
void PostProcessSets(std::vector<SetsMap::value_type>& sets,
- std::vector<Aliases::value_type>& aliases) {
+ std::vector<Aliases::value_type>& aliases) const {
if (invalid_keys_.empty()) {
return;
}
base::flat_set<net::SchemefulSite> possible_singletons;
- // Erase invalid members/primaries, and collect primary sites that might
- // become singletons.
- base::EraseIf(
- sets,
- [&](const std::pair<net::SchemefulSite, net::FirstPartySetEntry>& pair)
- -> bool { return IsInvalidEntry(pair, &possible_singletons); });
-
// Erase invalid aliases, and collect canonical sites that are primaries and
// might become singletons.
base::EraseIf(
@@ -362,6 +345,13 @@ class ParseContext {
return IsInvalidAlias(pair, possible_singletons, sets);
});
+ // Erase invalid members/primaries, and collect primary sites that might
+ // become singletons.
+ base::EraseIf(
+ sets,
+ [&](const std::pair<net::SchemefulSite, net::FirstPartySetEntry>& pair)
+ -> bool { return IsInvalidEntry(pair, &possible_singletons); });
+
if (possible_singletons.empty()) {
return;
}
@@ -399,13 +389,13 @@ class ParseContext {
// Removes invalid site entries and fixes up any lingering singletons.
// Modifies the lists in-place.
void PostProcessSetLists(
- base::expected<ParsedPolicySetLists, FirstPartySetsHandler::ParseError>&
- lists_or_error) {
+ base::expected<FirstPartySetParser::ParsedPolicySetLists,
+ FirstPartySetsHandler::ParseError>& lists_or_error) const {
if (!lists_or_error.has_value() || invalid_keys_.empty()) {
return;
}
- ParsedPolicySetLists& lists = lists_or_error.value();
+ FirstPartySetParser::ParsedPolicySetLists& lists = lists_or_error.value();
// Erase invalid members/primaries.
const auto is_invalid_entry =
@@ -422,7 +412,7 @@ class ParseContext {
// Since we just removed some keys, we have to double-check that there are
// no singleton sets.
- const auto is_singleton = [](const SingleSet& set) {
+ const auto is_singleton = [](const FirstPartySetParser::SingleSet& set) {
return set.size() <= 1;
};
base::EraseIf(lists.additions, is_singleton);
@@ -604,27 +594,20 @@ class ParseContext {
// set.
bool IsInvalidEntry(
const std::pair<net::SchemefulSite, net::FirstPartySetEntry> pair,
- base::flat_set<net::SchemefulSite>* possible_singletons) {
+ base::flat_set<net::SchemefulSite>* possible_singletons) const {
const net::SchemefulSite& key = pair.first;
const net::FirstPartySetEntry& entry = pair.second;
return base::ranges::any_of(
invalid_keys_, [&](const net::SchemefulSite& invalid_key) -> bool {
- if (invalid_key == entry.primary()) {
- // The primary is invalid, so we have to kill the whole set. So this
- // non-primary site must also be considered invalid in the future.
- invalid_keys_.insert(pair.first);
- return true;
- }
- if (invalid_key == key) {
+ const bool key_matches = invalid_key == key;
+ const bool primary_matches = invalid_key == entry.primary();
+ if (key_matches && !primary_matches && possible_singletons) {
// This is a member whose primary might end up being a
// singleton, since it's losing at least one member (and it
// itself isn't invalid).
- if (possible_singletons) {
- possible_singletons->insert(entry.primary());
- }
- return true;
+ possible_singletons->insert(entry.primary());
}
- return false;
+ return key_matches || primary_matches;
});
}
@@ -673,9 +656,43 @@ class ParseContext {
mutable base::flat_set<SetsMap::key_type> invalid_keys_;
};
-SetsAndAliases ParseSetsFromStreamInternal(std::istream& input,
- bool emit_errors,
- bool emit_metrics) {
+} // namespace
+
+FirstPartySetParser::ParsedPolicySetLists::ParsedPolicySetLists(
+ std::vector<FirstPartySetParser::SingleSet> replacement_list,
+ std::vector<FirstPartySetParser::SingleSet> addition_list)
+ : replacements(std::move(replacement_list)),
+ additions(std::move(addition_list)) {}
+
+FirstPartySetParser::ParsedPolicySetLists::ParsedPolicySetLists() = default;
+FirstPartySetParser::ParsedPolicySetLists::ParsedPolicySetLists(
+ FirstPartySetParser::ParsedPolicySetLists&&) = default;
+FirstPartySetParser::ParsedPolicySetLists::ParsedPolicySetLists(
+ const FirstPartySetParser::ParsedPolicySetLists&) = default;
+FirstPartySetParser::ParsedPolicySetLists::~ParsedPolicySetLists() = default;
+
+bool FirstPartySetParser::ParsedPolicySetLists::operator==(
+ const FirstPartySetParser::ParsedPolicySetLists& other) const {
+ return std::tie(replacements, additions) ==
+ std::tie(other.replacements, other.additions);
+}
+
+absl::optional<net::SchemefulSite>
+FirstPartySetParser::CanonicalizeRegisteredDomain(
+ const base::StringPiece origin_string,
+ bool emit_errors) {
+ ValidateSiteResult result =
+ ParseContext(emit_errors, /*exempt_from_limits=*/false)
+ .Canonicalize(origin_string);
+ if (result.has_error()) {
+ return absl::nullopt;
+ }
+ return result.site();
+}
+
+SetsAndAliases FirstPartySetParser::ParseSetsFromStream(std::istream& input,
+ bool emit_errors,
+ bool emit_metrics) {
std::vector<SetsMap::value_type> sets;
std::vector<Aliases::value_type> aliases;
ParseContext context(emit_errors, /*exempt_from_limits=*/false);
@@ -728,35 +745,7 @@ SetsAndAliases ParseSetsFromStreamInternal(std::istream& input,
base::UmaHistogramCounts1000(
"Cookie.FirstPartySets.ComponentSetsNonfatalErrors", nonfatal_errors);
}
-
- return std::make_pair(std::move(sets), std::move(aliases));
-}
-
-} // namespace
-
-std::optional<net::SchemefulSite>
-FirstPartySetParser::CanonicalizeRegisteredDomain(
- const base::StringPiece origin_string,
- bool emit_errors) {
- ValidateSiteResult result =
- ParseContext(emit_errors, /*exempt_from_limits=*/false)
- .Canonicalize(origin_string);
- if (result.has_error()) {
- return std::nullopt;
- }
- return result.site();
-}
-
-net::GlobalFirstPartySets FirstPartySetParser::ParseSetsFromStream(
- std::istream& input,
- base::Version version,
- bool emit_errors,
- bool emit_metrics) {
- SetsAndAliases sets_and_aliases =
- ParseSetsFromStreamInternal(input, emit_errors, emit_metrics);
- return net::GlobalFirstPartySets(std::move(version),
- std::move(sets_and_aliases.first),
- std::move(sets_and_aliases.second));
+ return std::make_pair(sets, aliases);
}
FirstPartySetParser::PolicyParseResult
@@ -778,43 +767,27 @@ FirstPartySetParser::ParseSetsFromEnterprisePolicy(
context.PostProcessSetLists(set_lists);
- return FirstPartySetParser::PolicyParseResult(
- std::move(set_lists).transform([](ParsedPolicySetLists lists) {
- return FirstPartySetsOverridesPolicy(net::SetsMutation(
- std::move(lists.replacements), std::move(lists.additions)));
- }),
- context.warnings());
+ return FirstPartySetParser::PolicyParseResult(std::move(set_lists),
+ context.warnings());
}
-// static
-net::LocalSetDeclaration FirstPartySetParser::ParseFromCommandLine(
- const std::string& switch_value) {
- std::istringstream stream(switch_value);
-
- SetsAndAliases parsed =
- ParseSetsFromStreamInternal(stream, /*emit_errors=*/true,
- /*emit_metrics*/ false);
-
- SetsMap entries = std::move(parsed.first);
- Aliases aliases = std::move(parsed.second);
-
- if (entries.empty()) {
- return net::LocalSetDeclaration();
+std::ostream& operator<<(
+ std::ostream& os,
+ const FirstPartySetParser::ParsedPolicySetLists& lists) {
+ os << "additions: {";
+ for (const auto& set : lists.additions) {
+ for (const auto& pair : set) {
+ os << pair.first << " -> " << pair.second << ", ";
+ }
}
-
- const net::SchemefulSite& primary = entries.begin()->second.primary();
-
- if (base::ranges::any_of(entries,
- [&primary](const SetsMap::value_type& pair) {
- return pair.second.primary() != primary;
- })) {
- // More than one set was provided. That is (currently) unsupported.
- LOG(ERROR) << "Ignoring use-related-website-set switch due to multiple set "
- "declarations.";
- return net::LocalSetDeclaration();
+ os << "}, replacements: {";
+ for (const auto& set : lists.replacements) {
+ for (const auto& pair : set) {
+ os << pair.first << " -> " << pair.second << ", ";
+ }
}
-
- return net::LocalSetDeclaration(std::move(entries), std::move(aliases));
+ os << "}";
+ return os;
}
} // namespace content
diff --git a/content/browser/first_party_sets/first_party_set_parser.h b/content/browser/first_party_sets/first_party_set_parser.h
index 47c07a209a9afafc696f3aabbef97422727f5195..d91cd5d119b1da6247d04bb28dd8c529c65deb85 100644
--- a/content/browser/first_party_sets/first_party_set_parser.h
+++ b/content/browser/first_party_sets/first_party_set_parser.h
@@ -18,18 +18,39 @@
#include "content/public/browser/first_party_sets_handler.h"
#include "net/base/schemeful_site.h"
#include "net/first_party_sets/first_party_set_entry.h"
-#include "net/first_party_sets/global_first_party_sets.h"
-#include "net/first_party_sets/local_set_declaration.h"
-#include "net/first_party_sets/sets_mutation.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace content {
class CONTENT_EXPORT FirstPartySetParser {
public:
- using PolicyParseResult =
- std::pair<base::expected<FirstPartySetsOverridesPolicy,
- FirstPartySetsHandler::ParseError>,
- std::vector<FirstPartySetsHandler::ParseWarning>>;
+ using SetsMap = base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>;
+ // Keys are alias sites, values are their canonical representatives.
+ using Aliases = base::flat_map<net::SchemefulSite, net::SchemefulSite>;
+ using SingleSet = SetsMap;
+ using SetsAndAliases = std::pair<SetsMap, Aliases>;
+ enum class PolicySetType { kReplacement, kAddition };
+
+ struct CONTENT_EXPORT ParsedPolicySetLists {
+ ParsedPolicySetLists(std::vector<SingleSet> replacement_list,
+ std::vector<SingleSet> addition_list);
+
+ ParsedPolicySetLists();
+ ParsedPolicySetLists(ParsedPolicySetLists&&);
+ ParsedPolicySetLists& operator=(ParsedPolicySetLists&&) = default;
+ ParsedPolicySetLists(const ParsedPolicySetLists&);
+ ParsedPolicySetLists& operator=(const ParsedPolicySetLists&) = default;
+ ~ParsedPolicySetLists();
+
+ bool operator==(const ParsedPolicySetLists& other) const;
+
+ std::vector<SingleSet> replacements;
+ std::vector<SingleSet> additions;
+ };
+
+ using PolicyParseResult = std::pair<
+ base::expected<ParsedPolicySetLists, FirstPartySetsHandler::ParseError>,
+ std::vector<FirstPartySetsHandler::ParseWarning>>;
FirstPartySetParser() = delete;
~FirstPartySetParser() = delete;
@@ -43,12 +64,11 @@ class CONTENT_EXPORT FirstPartySetParser {
// not check versions or assertions, since it is intended only for sets
// received by Component Updater.
//
- // Returns an empty GlobalFirstPartySets instance if parsing or validation of
- // any set failed.
- static net::GlobalFirstPartySets ParseSetsFromStream(std::istream& input,
- base::Version version,
- bool emit_errors,
- bool emit_metrics);
+ // Returns an empty map if parsing or validation of any set failed. Must not
+ // be called before field trial state has been initialized.
+ static SetsAndAliases ParseSetsFromStream(std::istream& input,
+ bool emit_errors,
+ bool emit_metrics);
// Canonicalizes the passed in origin to a registered domain. In particular,
// this ensures that the origin is non-opaque, is HTTPS, and has a registered
@@ -64,11 +84,12 @@ class CONTENT_EXPORT FirstPartySetParser {
// returns an error.
[[nodiscard]] static PolicyParseResult ParseSetsFromEnterprisePolicy(
const base::Value::Dict& policy);
-
- [[nodiscard]] static net::LocalSetDeclaration ParseFromCommandLine(
- const std::string& switch_value);
};
+CONTENT_EXPORT std::ostream& operator<<(
+ std::ostream& os,
+ const FirstPartySetParser::ParsedPolicySetLists& lists);
+
} // namespace content
#endif // CONTENT_BROWSER_FIRST_PARTY_SETS_FIRST_PARTY_SET_PARSER_H_
diff --git a/content/browser/first_party_sets/first_party_sets_handler_impl_instance.cc b/content/browser/first_party_sets/first_party_sets_handler_impl.cc
similarity index 74%
rename from content/browser/first_party_sets/first_party_sets_handler_impl_instance.cc
rename to content/browser/first_party_sets/first_party_sets_handler_impl.cc
index 267e0786e139a7a1fc142b6fd1a92e3a5e8c716a..86eeb6f409b37de04a6843c7d1321e6be0be4003 100644
--- a/content/browser/first_party_sets/first_party_sets_handler_impl_instance.cc
+++ b/content/browser/first_party_sets/first_party_sets_handler_impl.cc
@@ -1,8 +1,8 @@
-// Copyright 2023 The Chromium Authors
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "content/browser/first_party_sets/first_party_sets_handler_impl_instance.h"
+#include "content/browser/first_party_sets/first_party_sets_handler_impl.h"
#include <memory>
#include <optional>
@@ -13,17 +13,16 @@
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
-#include "base/sequence_checker.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/types/expected.h"
#include "base/types/optional_util.h"
#include "base/values.h"
#include "content/browser/first_party_sets/first_party_set_parser.h"
-#include "content/browser/first_party_sets/first_party_sets_handler_impl.h"
#include "content/browser/first_party_sets/first_party_sets_loader.h"
#include "content/browser/first_party_sets/first_party_sets_overrides_policy.h"
#include "content/browser/first_party_sets/first_party_sets_site_data_remover.h"
+#include "content/browser/first_party_sets/local_set_declaration.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/first_party_sets_handler.h"
@@ -32,8 +31,7 @@
#include "net/first_party_sets/first_party_set_metadata.h"
#include "net/first_party_sets/first_party_sets_context_config.h"
#include "net/first_party_sets/global_first_party_sets.h"
-#include "net/first_party_sets/local_set_declaration.h"
-#include "net/first_party_sets/sets_mutation.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace net {
class SchemefulSite;
@@ -81,16 +79,15 @@ void FirstPartySetsHandlerImpl::SetInstanceForTesting(
// static
FirstPartySetsHandler* FirstPartySetsHandler::GetInstance() {
- if (g_test_instance) {
+ if (g_test_instance)
return g_test_instance;
- }
return FirstPartySetsHandlerImpl::GetInstance();
}
// static
FirstPartySetsHandlerImpl* FirstPartySetsHandlerImpl::GetInstance() {
- static base::NoDestructor<FirstPartySetsHandlerImplInstance> instance(
+ static base::NoDestructor<FirstPartySetsHandlerImpl> instance(
GetContentClient()->browser()->IsFirstPartySetsEnabled(),
GetContentClient()->browser()->WillProvidePublicFirstPartySets());
if (g_impl_test_instance) {
@@ -115,19 +112,17 @@ FirstPartySetsHandler::ValidateEnterprisePolicy(
}
// static
-FirstPartySetsHandlerImplInstance
-FirstPartySetsHandlerImplInstance::CreateForTesting(
+FirstPartySetsHandlerImpl FirstPartySetsHandlerImpl::CreateForTesting(
bool enabled,
bool embedder_will_provide_public_sets) {
- return FirstPartySetsHandlerImplInstance(enabled,
- embedder_will_provide_public_sets);
+ return FirstPartySetsHandlerImpl(enabled, embedder_will_provide_public_sets);
}
-void FirstPartySetsHandlerImplInstance::GetContextConfigForPolicy(
+void FirstPartySetsHandlerImpl::GetContextConfigForPolicy(
const base::Value::Dict* policy,
base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (!policy) {
+ if (!policy || !enabled_) {
std::move(callback).Run(net::FirstPartySetsContextConfig());
return;
}
@@ -140,49 +135,57 @@ void FirstPartySetsHandlerImplInstance::GetContextConfigForPolicy(
// of First-Party Sets has been fully initialized.
EnqueuePendingTask(
base::BindOnce(
- &FirstPartySetsHandlerImplInstance::GetContextConfigForPolicyInternal,
+ &FirstPartySetsHandlerImpl::GetContextConfigForPolicyInternal,
// base::Unretained(this) is safe here because this is a static
// singleton.
base::Unretained(this), policy->Clone(), base::ElapsedTimer())
.Then(std::move(callback)));
}
-FirstPartySetsHandlerImplInstance::FirstPartySetsHandlerImplInstance(
- bool enabled,
- bool embedder_will_provide_public_sets)
- : enabled_(enabled) {
- if (enabled) {
- on_sets_ready_callbacks_ =
- std::make_unique<base::circular_deque<base::OnceClosure>>();
- sets_loader_ = std::make_unique<FirstPartySetsLoader>(
- base::BindOnce(&FirstPartySetsHandlerImplInstance::SetCompleteSets,
- // base::Unretained(this) is safe here because
- // this is a static singleton.
- base::Unretained(this)));
- if (!embedder_will_provide_public_sets) {
- sets_loader_->SetComponentSets(base::Version(), base::File());
- }
- } else {
- SetCompleteSets(net::GlobalFirstPartySets());
- CHECK(global_sets_.has_value());
- }
+net::FirstPartySetsContextConfig
+FirstPartySetsHandlerImpl::ComputeEnterpriseContextConfig(
+ const net::GlobalFirstPartySets& global_sets,
+ const FirstPartySetParser::ParsedPolicySetLists& policy) {
+ return global_sets.ComputeConfig(
+ /*replacement_sets=*/policy.replacements,
+ /*addition_sets=*/
+ policy.additions);
}
-FirstPartySetsHandlerImplInstance::~FirstPartySetsHandlerImplInstance() =
- default;
+FirstPartySetsHandlerImpl::FirstPartySetsHandlerImpl(
+ base::PassKey<ScopedMockFirstPartySetsHandler>,
+ bool enabled,
+ bool embedder_will_provide_public_sets)
+ : FirstPartySetsHandlerImpl(enabled, embedder_will_provide_public_sets) {}
-std::optional<net::GlobalFirstPartySets>
-FirstPartySetsHandlerImplInstance::GetSets(
- base::OnceCallback<void(net::GlobalFirstPartySets)> callback) {
+FirstPartySetsHandlerImpl::FirstPartySetsHandlerImpl(
+ bool enabled,
+ bool embedder_will_provide_public_sets)
+ : enabled_(enabled),
+ embedder_will_provide_public_sets_(enabled &&
+ embedder_will_provide_public_sets),
+ sets_loader_(std::make_unique<FirstPartySetsLoader>(
+ base::BindOnce(&FirstPartySetsHandlerImpl::SetCompleteSets,
+ // base::Unretained(this) is safe here because
+ // this is a static singleton.
+ base::Unretained(this)))) {}
+
+FirstPartySetsHandlerImpl::~FirstPartySetsHandlerImpl() = default;
+
+absl::optional<net::GlobalFirstPartySets> FirstPartySetsHandlerImpl::GetSets(
+ SetsReadyOnceCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (global_sets_.has_value()) {
- return global_sets_->Clone();
+ if (!IsEnabled()) {
+ return net::GlobalFirstPartySets();
}
+ CHECK(IsEnabled());
+ if (global_sets_.has_value())
+ return global_sets_->Clone();
if (!callback.is_null()) {
// base::Unretained(this) is safe here because this is a static singleton.
EnqueuePendingTask(
- base::BindOnce(&FirstPartySetsHandlerImplInstance::GetGlobalSetsSync,
+ base::BindOnce(&FirstPartySetsHandlerImpl::GetGlobalSetsSync,
base::Unretained(this))
.Then(std::move(callback)));
}
@@ -190,33 +193,35 @@ FirstPartySetsHandlerImplInstance::GetSets(
return std::nullopt;
}
-void FirstPartySetsHandlerImplInstance::Init(
- const base::FilePath& user_data_dir,
- const net::LocalSetDeclaration& local_set) {
+void FirstPartySetsHandlerImpl::Init(const base::FilePath& user_data_dir,
+ const LocalSetDeclaration& local_set) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (initialized_) {
- return;
- }
+ CHECK(!initialized_);
+ CHECK(sets_loader_);
initialized_ = true;
SetDatabase(user_data_dir);
- if (sets_loader_) {
+ if (IsEnabled()) {
sets_loader_->SetManuallySpecifiedSet(local_set);
+ if (!embedder_will_provide_public_sets_) {
+ sets_loader_->SetComponentSets(base::Version(), base::File());
+ }
+ } else {
+ SetCompleteSets(net::GlobalFirstPartySets());
}
}
-bool FirstPartySetsHandlerImplInstance::IsEnabled() const {
+bool FirstPartySetsHandlerImpl::IsEnabled() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return enabled_;
}
-void FirstPartySetsHandlerImplInstance::SetPublicFirstPartySets(
+void FirstPartySetsHandlerImpl::SetPublicFirstPartySets(
const base::Version& version,
base::File sets_file) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (!sets_loader_) {
- FirstPartySetsLoader::DisposeFile(std::move(sets_file));
+ if (!enabled_ || !embedder_will_provide_public_sets_ || !sets_loader_) {
return;
}
@@ -224,7 +229,7 @@ void FirstPartySetsHandlerImplInstance::SetPublicFirstPartySets(
sets_loader_->SetComponentSets(version, std::move(sets_file));
}
-void FirstPartySetsHandlerImplInstance::GetPersistedSetsForTesting(
+void FirstPartySetsHandlerImpl::GetPersistedSetsForTesting(
const std::string& browser_context_id,
base::OnceCallback<void(
std::optional<std::pair<net::GlobalFirstPartySets,
@@ -242,7 +247,7 @@ void FirstPartySetsHandlerImplInstance::GetPersistedSetsForTesting(
.Then(std::move(callback));
}
-void FirstPartySetsHandlerImplInstance::HasBrowserContextClearedForTesting(
+void FirstPartySetsHandlerImpl::HasBrowserContextClearedForTesting(
const std::string& browser_context_id,
base::OnceCallback<void(std::optional<bool>)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -258,17 +263,18 @@ void FirstPartySetsHandlerImplInstance::HasBrowserContextClearedForTesting(
.Then(std::move(callback));
}
-void FirstPartySetsHandlerImplInstance::SetCompleteSets(
+void FirstPartySetsHandlerImpl::SetCompleteSets(
net::GlobalFirstPartySets sets) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(!global_sets_.has_value());
+ CHECK(sets_loader_);
global_sets_ = std::move(sets);
sets_loader_.reset();
InvokePendingQueries();
}
-void FirstPartySetsHandlerImplInstance::SetDatabase(
+void FirstPartySetsHandlerImpl::SetDatabase(
const base::FilePath& user_data_dir) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(db_helper_.is_null());
@@ -283,26 +289,22 @@ void FirstPartySetsHandlerImplInstance::SetDatabase(
user_data_dir.Append(kFirstPartySetsDatabase));
}
-void FirstPartySetsHandlerImplInstance::EnqueuePendingTask(
- base::OnceClosure run_task) {
+void FirstPartySetsHandlerImpl::EnqueuePendingTask(base::OnceClosure run_task) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(!global_sets_.has_value());
- CHECK(on_sets_ready_callbacks_);
if (!first_async_task_timer_.has_value()) {
first_async_task_timer_ = base::ElapsedTimer();
}
- on_sets_ready_callbacks_->push_back(std::move(run_task));
+ on_sets_ready_callbacks_.push_back(std::move(run_task));
}
-void FirstPartySetsHandlerImplInstance::InvokePendingQueries() {
+void FirstPartySetsHandlerImpl::InvokePendingQueries() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::circular_deque<base::OnceClosure> queue;
- if (on_sets_ready_callbacks_) {
- queue.swap(*on_sets_ready_callbacks_);
- }
+ queue.swap(on_sets_ready_callbacks_);
base::UmaHistogramCounts10000(
"Cookie.FirstPartySets.Browser.DelayedQueriesCount", queue.size());
@@ -316,11 +318,9 @@ void FirstPartySetsHandlerImplInstance::InvokePendingQueries() {
queue.pop_front();
std::move(callback).Run();
}
- on_sets_ready_callbacks_.reset();
}
-std::optional<net::FirstPartySetEntry>
-FirstPartySetsHandlerImplInstance::FindEntry(
+absl::optional<net::FirstPartySetEntry> FirstPartySetsHandlerImpl::FindEntry(
const net::SchemefulSite& site,
const net::FirstPartySetsContextConfig& config) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -330,14 +330,13 @@ FirstPartySetsHandlerImplInstance::FindEntry(
return global_sets_->FindEntry(site, config);
}
-net::GlobalFirstPartySets FirstPartySetsHandlerImplInstance::GetGlobalSetsSync()
- const {
+net::GlobalFirstPartySets FirstPartySetsHandlerImpl::GetGlobalSetsSync() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(global_sets_.has_value());
return global_sets_->Clone();
}
-void FirstPartySetsHandlerImplInstance::ClearSiteDataOnChangedSetsForContext(
+void FirstPartySetsHandlerImpl::ClearSiteDataOnChangedSetsForContext(
base::RepeatingCallback<BrowserContext*()> browser_context_getter,
const std::string& browser_context_id,
net::FirstPartySetsContextConfig context_config,
@@ -360,19 +359,17 @@ void FirstPartySetsHandlerImplInstance::ClearSiteDataOnChangedSetsForContext(
// base::Unretained(this) is safe because this is a static singleton.
EnqueuePendingTask(base::BindOnce(
- &FirstPartySetsHandlerImplInstance::
- ClearSiteDataOnChangedSetsForContextInternal,
+ &FirstPartySetsHandlerImpl::ClearSiteDataOnChangedSetsForContextInternal,
base::Unretained(this), browser_context_getter, browser_context_id,
std::move(context_config), std::move(callback)));
}
-void FirstPartySetsHandlerImplInstance::
- ClearSiteDataOnChangedSetsForContextInternal(
- base::RepeatingCallback<BrowserContext*()> browser_context_getter,
- const std::string& browser_context_id,
- net::FirstPartySetsContextConfig context_config,
- base::OnceCallback<void(net::FirstPartySetsContextConfig,
- net::FirstPartySetsCacheFilter)> callback) {
+void FirstPartySetsHandlerImpl::ClearSiteDataOnChangedSetsForContextInternal(
+ base::RepeatingCallback<BrowserContext*()> browser_context_getter,
+ const std::string& browser_context_id,
+ net::FirstPartySetsContextConfig context_config,
+ base::OnceCallback<void(net::FirstPartySetsContextConfig,
+ net::FirstPartySetsCacheFilter)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(global_sets_.has_value());
CHECK(!browser_context_id.empty());
@@ -394,7 +391,7 @@ void FirstPartySetsHandlerImplInstance::
base::OnceCallback<void(std::pair<std::vector<net::SchemefulSite>,
net::FirstPartySetsCacheFilter>)>
on_get_sites_to_clear = base::BindOnce(
- &FirstPartySetsHandlerImplInstance::OnGetSitesToClear,
+ &FirstPartySetsHandlerImpl::OnGetSitesToClear,
// base::Unretained(this) is safe here because this
// is a static singleton.
base::Unretained(this), browser_context_getter, browser_context_id,
@@ -408,7 +405,7 @@ void FirstPartySetsHandlerImplInstance::
.Then(std::move(on_get_sites_to_clear));
}
-void FirstPartySetsHandlerImplInstance::OnGetSitesToClear(
+void FirstPartySetsHandlerImpl::OnGetSitesToClear(
base::RepeatingCallback<BrowserContext*()> browser_context_getter,
const std::string& browser_context_id,
net::FirstPartySetsContextConfig context_config,
@@ -434,16 +431,15 @@ void FirstPartySetsHandlerImplInstance::OnGetSitesToClear(
FirstPartySetsSiteDataRemover::RemoveSiteData(
*browser_context->GetBrowsingDataRemover(),
std::move(sites_to_clear.first),
- base::BindOnce(&FirstPartySetsHandlerImplInstance::
- DidClearSiteDataOnChangedSetsForContext,
- // base::Unretained(this) is safe here because
- // this is a static singleton.
- base::Unretained(this), browser_context_id,
- std::move(context_config),
- std::move(sites_to_clear.second), std::move(callback)));
+ base::BindOnce(
+ &FirstPartySetsHandlerImpl::DidClearSiteDataOnChangedSetsForContext,
+ // base::Unretained(this) is safe here because
+ // this is a static singleton.
+ base::Unretained(this), browser_context_id, std::move(context_config),
+ std::move(sites_to_clear.second), std::move(callback)));
}
-void FirstPartySetsHandlerImplInstance::DidClearSiteDataOnChangedSetsForContext(
+void FirstPartySetsHandlerImpl::DidClearSiteDataOnChangedSetsForContext(
const std::string& browser_context_id,
net::FirstPartySetsContextConfig context_config,
net::FirstPartySetsCacheFilter cache_filter,
@@ -473,28 +469,30 @@ void FirstPartySetsHandlerImplInstance::DidClearSiteDataOnChangedSetsForContext(
std::move(callback).Run(std::move(context_config), std::move(cache_filter));
}
-void FirstPartySetsHandlerImplInstance::ComputeFirstPartySetMetadata(
+void FirstPartySetsHandlerImpl::ComputeFirstPartySetMetadata(
const net::SchemefulSite& site,
const net::SchemefulSite* top_frame_site,
+ const std::set<net::SchemefulSite>& party_context,
const net::FirstPartySetsContextConfig& config,
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!global_sets_.has_value()) {
EnqueuePendingTask(base::BindOnce(
- &FirstPartySetsHandlerImplInstance::
- ComputeFirstPartySetMetadataInternal,
+ &FirstPartySetsHandlerImpl::ComputeFirstPartySetMetadataInternal,
base::Unretained(this), site, base::OptionalFromPtr(top_frame_site),
- config.Clone(), base::ElapsedTimer(), std::move(callback)));
+ party_context, config.Clone(), base::ElapsedTimer(),
+ std::move(callback)));
return;
}
- std::move(callback).Run(
- global_sets_->ComputeMetadata(site, top_frame_site, config));
+ std::move(callback).Run(global_sets_->ComputeMetadata(site, top_frame_site,
+ party_context, config));
}
-void FirstPartySetsHandlerImplInstance::ComputeFirstPartySetMetadataInternal(
+void FirstPartySetsHandlerImpl::ComputeFirstPartySetMetadataInternal(
const net::SchemefulSite& site,
- const std::optional<net::SchemefulSite>& top_frame_site,
+ const absl::optional<net::SchemefulSite>& top_frame_site,
+ const std::set<net::SchemefulSite>& party_context,
const net::FirstPartySetsContextConfig& config,
const base::ElapsedTimer& timer,
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const {
@@ -506,11 +504,11 @@ void FirstPartySetsHandlerImplInstance::ComputeFirstPartySetMetadataInternal(
timer.Elapsed());
std::move(callback).Run(global_sets_->ComputeMetadata(
- site, base::OptionalToPtr(top_frame_site), config));
+ site, base::OptionalToPtr(top_frame_site), party_context, config));
}
net::FirstPartySetsContextConfig
-FirstPartySetsHandlerImplInstance::GetContextConfigForPolicyInternal(
+FirstPartySetsHandlerImpl::GetContextConfigForPolicyInternal(
const base::Value::Dict& policy,
const std::optional<base::ElapsedTimer>& timer) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -522,22 +520,16 @@ FirstPartySetsHandlerImplInstance::GetContextConfigForPolicyInternal(
timer->Elapsed());
}
- if (!enabled_) {
- return net::FirstPartySetsContextConfig();
- }
-
auto [parsed, warnings] =
FirstPartySetParser::ParseSetsFromEnterprisePolicy(policy);
- if (!parsed.has_value()) {
- return global_sets_->ComputeConfig(net::SetsMutation());
- }
-
- FirstPartySetsOverridesPolicy& policy_result = parsed.value();
- return global_sets_->ComputeConfig(std::move(policy_result.mutation()));
+ return parsed.has_value()
+ ? FirstPartySetsHandlerImpl::ComputeEnterpriseContextConfig(
+ global_sets_.value(), parsed.value())
+ : net::FirstPartySetsContextConfig();
}
-bool FirstPartySetsHandlerImplInstance::ForEachEffectiveSetEntry(
+bool FirstPartySetsHandlerImpl::ForEachEffectiveSetEntry(
const net::FirstPartySetsContextConfig& config,
base::FunctionRef<bool(const net::SchemefulSite&,
const net::FirstPartySetEntry&)> f) const {
diff --git a/content/browser/first_party_sets/first_party_sets_handler_impl.h b/content/browser/first_party_sets/first_party_sets_handler_impl.h
index b183d8841eda1fa05ecaf01f63d88fb4e6e7689d..ef5f6621bc15fb6cee467d8de18538bbcc7f282d 100644
--- a/content/browser/first_party_sets/first_party_sets_handler_impl.h
+++ b/content/browser/first_party_sets/first_party_sets_handler_impl.h
@@ -7,24 +7,65 @@
#include <optional>
+#include <string>
+#include <utility>
+
+#include "base/containers/circular_deque.h"
+#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/functional/callback.h"
+#include "base/no_destructor.h"
+#include "base/sequence_checker.h"
+#include "base/thread_annotations.h"
+#include "base/threading/sequence_bound.h"
+#include "base/timer/elapsed_timer.h"
+#include "base/types/pass_key.h"
+#include "base/values.h"
+#include "base/version.h"
+#include "content/browser/first_party_sets/first_party_set_parser.h"
+#include "content/browser/first_party_sets/first_party_sets_handler_database_helper.h"
+#include "content/browser/first_party_sets/first_party_sets_loader.h"
+#include "content/browser/first_party_sets/local_set_declaration.h"
#include "content/common/content_export.h"
#include "content/public/browser/first_party_sets_handler.h"
+#include "net/first_party_sets/first_party_sets_cache_filter.h"
+#include "net/first_party_sets/first_party_sets_context_config.h"
#include "net/first_party_sets/global_first_party_sets.h"
#include "net/first_party_sets/local_set_declaration.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace net {
+class FirstPartySetEntry;
+class SchemefulSite;
+} // namespace net
namespace content {
-// FirstPartySetsHandlerImpl is an abstract class, encapsulating the
-// content-internal details of the First-Party Sets infrastructure. This class
-// is abstract so that it can be mocked during testing.
+class BrowserContext;
+class ScopedMockFirstPartySetsHandler;
+
+// Class FirstPartySetsHandlerImpl is a singleton, it allows an embedder to
+// provide First-Party Sets inputs from custom sources, then parses/merges the
+// inputs to form the current First-Party Sets data, compares them with the
+// persisted First-Party Sets data used during the last browser session to get
+// a list of sites that changed the First-Party Set they are part of, invokes
+// the provided callback with the current First-Party Sets data, and writes
+// the current First-Party Sets data to disk.
class CONTENT_EXPORT FirstPartySetsHandlerImpl : public FirstPartySetsHandler {
public:
+ using SetsReadyOnceCallback =
+ base::OnceCallback<void(net::GlobalFirstPartySets)>;
+
static FirstPartySetsHandlerImpl* GetInstance();
static void SetInstanceForTesting(FirstPartySetsHandlerImpl* test_instance);
+ ~FirstPartySetsHandlerImpl() override;
+
+ FirstPartySetsHandlerImpl(const FirstPartySetsHandlerImpl&) = delete;
+ FirstPartySetsHandlerImpl& operator=(const FirstPartySetsHandlerImpl&) =
+ delete;
+
// This method reads the persisted First-Party Sets from the file under
// `user_data_dir` and sets the First-Party Set that was provided via the
// flag(s).
@@ -33,9 +74,14 @@ class CONTENT_EXPORT FirstPartySetsHandlerImpl : public FirstPartySetsHandler {
// persisted sets, since we may still need to clear data from a previous
// invocation of Chromium which had First-Party Sets enabled.
//
- // Only the first call has any effect.
- void virtual Init(const base::FilePath& user_data_dir,
- const net::LocalSetDeclaration& local_set) = 0;
+ // Must be called exactly once.
+ void Init(const base::FilePath& user_data_dir,
+ const LocalSetDeclaration& local_set);
+
+ // Factory method that exposes the ctor for testing.
+ static FirstPartySetsHandlerImpl CreateForTesting(
+ bool enabled,
+ bool embedder_will_provide_public_sets);
// Returns the fully-parsed and validated global First-Party Sets data.
// Returns the data synchronously via an std::optional if it's already
@@ -49,8 +95,164 @@ class CONTENT_EXPORT FirstPartySetsHandlerImpl : public FirstPartySetsHandler {
//
// If First-Party Sets is disabled, this returns a populated optional with an
// empty GlobalFirstPartySets instance.
- [[nodiscard]] virtual std::optional<net::GlobalFirstPartySets> GetSets(
- base::OnceCallback<void(net::GlobalFirstPartySets)> callback) = 0;
+ [[nodiscard]] virtual absl::optional<net::GlobalFirstPartySets> GetSets(
+ SetsReadyOnceCallback callback);
+
+ // FirstPartySetsHandler
+ bool IsEnabled() const override;
+ void SetPublicFirstPartySets(const base::Version& version,
+ base::File sets_file) override;
+ absl::optional<net::FirstPartySetEntry> FindEntry(
+ const net::SchemefulSite& site,
+ const net::FirstPartySetsContextConfig& config) const override;
+ void GetContextConfigForPolicy(
+ const base::Value::Dict* policy,
+ base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback)
+ override;
+ void ClearSiteDataOnChangedSetsForContext(
+ base::RepeatingCallback<BrowserContext*()> browser_context_getter,
+ const std::string& browser_context_id,
+ net::FirstPartySetsContextConfig context_config,
+ base::OnceCallback<void(net::FirstPartySetsContextConfig,
+ net::FirstPartySetsCacheFilter)> callback)
+ override;
+ void ComputeFirstPartySetMetadata(
+ const net::SchemefulSite& site,
+ const net::SchemefulSite* top_frame_site,
+ const std::set<net::SchemefulSite>& party_context,
+ const net::FirstPartySetsContextConfig& config,
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback) override;
+ bool ForEachEffectiveSetEntry(
+ const net::FirstPartySetsContextConfig& config,
+ base::FunctionRef<bool(const net::SchemefulSite&,
+ const net::FirstPartySetEntry&)> f) const override;
+ void GetPersistedSetsForTesting(
+ const std::string& browser_context_id,
+ base::OnceCallback<
+ void(absl::optional<std::pair<net::GlobalFirstPartySets,
+ net::FirstPartySetsContextConfig>>)>
+ callback);
+ void HasBrowserContextClearedForTesting(
+ const std::string& browser_context_id,
+ base::OnceCallback<void(absl::optional<bool>)> callback);
+
+ void SynchronouslyResetDBHelperForTesting() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ db_helper_.SynchronouslyResetForTest(); // IN-TEST
+ }
+
+ // Computes information needed by the FirstPartySetsAccessDelegate in order
+ // to update the browser's list of First-Party Sets to respect a profile's
+ // setting for the per-profile FirstPartySetsOverrides policy.
+ static net::FirstPartySetsContextConfig ComputeEnterpriseContextConfig(
+ const net::GlobalFirstPartySets& browser_sets,
+ const FirstPartySetParser::ParsedPolicySetLists& policy);
+
+ protected:
+ FirstPartySetsHandlerImpl(base::PassKey<ScopedMockFirstPartySetsHandler> key,
+ bool enabled,
+ bool embedder_will_provide_public_sets);
+
+ private:
+ friend class base::NoDestructor<FirstPartySetsHandlerImpl>;
+
+ FirstPartySetsHandlerImpl(bool enabled,
+ bool embedder_will_provide_public_sets);
+
+ // Sets the global First-Party Sets data. Must be called exactly once.
+ void SetCompleteSets(net::GlobalFirstPartySets sets);
+
+ // Sets `db_helper_`, which will initialize the underlying First-Party Sets
+ // database under `user_data_dir`. Must be called exactly once.
+ void SetDatabase(const base::FilePath& user_data_dir);
+
+ // Enqueues a task to be performed once initialization is complete.
+ void EnqueuePendingTask(base::OnceClosure run_task);
+
+ // Invokes any pending queries.
+ void InvokePendingQueries();
+
+ // Returns the global First-Party Sets. This clones the underlying
+ // data.
+ //
+ // Must be called after the list has been initialized.
+ net::GlobalFirstPartySets GetGlobalSetsSync() const;
+
+ // Performs the actual state clearing for the given context. Must not be
+ // called until initialization is complete.
+ void ClearSiteDataOnChangedSetsForContextInternal(
+ base::RepeatingCallback<BrowserContext*()> browser_context_getter,
+ const std::string& browser_context_id,
+ net::FirstPartySetsContextConfig context_config,
+ base::OnceCallback<void(net::FirstPartySetsContextConfig,
+ net::FirstPartySetsCacheFilter)> callback);
+
+ // Like ComputeFirstPartySetMetadata, but passes the result into the provided
+ // callback. Must not be called before `global_sets_` has been set.
+ void ComputeFirstPartySetMetadataInternal(
+ const net::SchemefulSite& site,
+ const absl::optional<net::SchemefulSite>& top_frame_site,
+ const std::set<net::SchemefulSite>& party_context,
+ const net::FirstPartySetsContextConfig& config,
+ const base::ElapsedTimer& timer,
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const;
+
+ // Parses the policy and computes the config that represents the changes
+ // needed to apply `policy` to `global_sets_`.
+ net::FirstPartySetsContextConfig GetContextConfigForPolicyInternal(
+ const base::Value::Dict& policy,
+ const absl::optional<base::ElapsedTimer>& timer) const;
+
+ void OnGetSitesToClear(
+ base::RepeatingCallback<BrowserContext*()> browser_context_getter,
+ const std::string& browser_context_id,
+ net::FirstPartySetsContextConfig context_config,
+ base::OnceCallback<void(net::FirstPartySetsContextConfig,
+ net::FirstPartySetsCacheFilter)> callback,
+ std::pair<std::vector<net::SchemefulSite>, net::FirstPartySetsCacheFilter>
+ sites_to_clear) const;
+
+ // `failed_data_types` is a bitmask used to indicate data types from
+ // BrowsingDataRemover::DataType enum that were failed to remove. 0 indicates
+ // success.
+ void DidClearSiteDataOnChangedSetsForContext(
+ const std::string& browser_context_id,
+ net::FirstPartySetsContextConfig context_config,
+ net::FirstPartySetsCacheFilter cache_filter,
+ base::OnceCallback<void(net::FirstPartySetsContextConfig,
+ net::FirstPartySetsCacheFilter)> callback,
+ uint64_t failed_data_types) const;
+
+ // Whether Init has been called already or not.
+ bool initialized_ = false;
+
+ // The global First-Party Sets, after parsing and validation.
+ //
+ // This is nullopt until all of the required inputs have been received.
+ absl::optional<net::GlobalFirstPartySets> global_sets_
+ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ bool enabled_ GUARDED_BY_CONTEXT(sequence_checker_);
+ bool embedder_will_provide_public_sets_ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ // We use a OnceCallback to ensure we only pass along the sets once
+ // during Chrome's lifetime (modulo reconfiguring the network service).
+ base::circular_deque<base::OnceClosure> on_sets_ready_callbacks_
+ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ std::unique_ptr<FirstPartySetsLoader> sets_loader_
+ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ // Timer starting when the first async task was enqueued, if any. Used for
+ // metrics.
+ absl::optional<base::ElapsedTimer> first_async_task_timer_
+ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ // Access the underlying DB on a database sequence to make sure none of DB
+ // operations that support blocking are called directly on the main thread.
+ base::SequenceBound<FirstPartySetsHandlerDatabaseHelper> db_helper_;
+
+ SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace content
diff --git a/content/browser/first_party_sets/first_party_sets_handler_impl_instance.h b/content/browser/first_party_sets/first_party_sets_handler_impl_instance.h
index 974da5d2b26053e5624a5a9aa6cee183692b7863..f5b96707c51af8a8ac9d190cf8b0883c7dc213ca 100644
--- a/content/browser/first_party_sets/first_party_sets_handler_impl_instance.h
+++ b/content/browser/first_party_sets/first_party_sets_handler_impl_instance.h
@@ -23,11 +23,13 @@
#include "content/browser/first_party_sets/first_party_sets_handler_database_helper.h"
#include "content/browser/first_party_sets/first_party_sets_handler_impl.h"
#include "content/browser/first_party_sets/first_party_sets_loader.h"
+#include "content/browser/first_party_sets/local_set_declaration.h"
#include "content/common/content_export.h"
#include "net/first_party_sets/first_party_sets_cache_filter.h"
#include "net/first_party_sets/first_party_sets_context_config.h"
#include "net/first_party_sets/global_first_party_sets.h"
#include "net/first_party_sets/local_set_declaration.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace net {
class FirstPartySetEntry;
@@ -62,8 +64,8 @@ class CONTENT_EXPORT FirstPartySetsHandlerImplInstance
// FirstPartySetsHandlerImpl:
void Init(const base::FilePath& user_data_dir,
- const net::LocalSetDeclaration& local_set) override;
- [[nodiscard]] std::optional<net::GlobalFirstPartySets> GetSets(
+ const LocalSetDeclaration& local_set) override;
+ [[nodiscard]] absl::optional<net::GlobalFirstPartySets> GetSets(
base::OnceCallback<void(net::GlobalFirstPartySets)> callback) override;
// FirstPartySetsHandler:
diff --git a/content/browser/first_party_sets/first_party_sets_loader.cc b/content/browser/first_party_sets/first_party_sets_loader.cc
index 21371a4962adf787595b6acba0d4656db563ae52..131319b69a691ae2a9b5e7c380d42c36e0882336 100644
--- a/content/browser/first_party_sets/first_party_sets_loader.cc
+++ b/content/browser/first_party_sets/first_party_sets_loader.cc
@@ -5,8 +5,11 @@
#include "content/browser/first_party_sets/first_party_sets_loader.h"
#include <optional>
+#include <iterator>
+#include <set>
#include <sstream>
#include <utility>
+#include <vector>
#include "base/containers/flat_map.h"
#include "base/files/file_util.h"
@@ -15,8 +18,10 @@
#include "base/task/thread_pool.h"
#include "base/version.h"
#include "content/browser/first_party_sets/first_party_set_parser.h"
+#include "content/browser/first_party_sets/local_set_declaration.h"
#include "net/first_party_sets/global_first_party_sets.h"
#include "net/first_party_sets/local_set_declaration.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace content {
@@ -28,6 +33,19 @@ std::string ReadSetsFile(base::File sets_file) {
return base::ReadStreamToString(file.get(), &raw_sets) ? raw_sets : "";
}
+void DisposeFile(base::File sets_file) {
+ if (!sets_file.IsValid()) {
+ return;
+ }
+ base::ThreadPool::PostTask(
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
+ base::BindOnce(
+ [](base::File sets_file) {
+ // Run `sets_file`'s dtor in the threadpool.
+ },
+ std::move(sets_file)));
+}
+
} // namespace
FirstPartySetsLoader::FirstPartySetsLoader(
@@ -39,11 +57,8 @@ FirstPartySetsLoader::~FirstPartySetsLoader() {
}
void FirstPartySetsLoader::SetManuallySpecifiedSet(
- const net::LocalSetDeclaration& local_set) {
+ const LocalSetDeclaration& local_set) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (manually_specified_set_.has_value()) {
- return;
- }
manually_specified_set_ = local_set;
UmaHistogramTimes(
"Cookie.FirstPartySets.InitializationDuration.ReadCommandLineSet2",
@@ -76,29 +91,18 @@ void FirstPartySetsLoader::SetComponentSets(base::Version version,
weak_factory_.GetWeakPtr(), std::move(version)));
}
-// static
-void FirstPartySetsLoader::DisposeFile(base::File file) {
- if (!file.IsValid()) {
- return;
- }
- base::ThreadPool::PostTask(
- FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
- base::BindOnce(
- [](base::File file) {
- // Run `file`'s dtor in the threadpool.
- },
- std::move(file)));
-}
-
void FirstPartySetsLoader::OnReadSetsFile(base::Version version,
const std::string& raw_sets) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(component_sets_parse_progress_, Progress::kStarted);
std::istringstream stream(raw_sets);
- sets_ = FirstPartySetParser::ParseSetsFromStream(stream, std::move(version),
- /*emit_errors=*/false,
- /*emit_metrics=*/true);
+ FirstPartySetParser::SetsAndAliases public_sets =
+ FirstPartySetParser::ParseSetsFromStream(stream, /*emit_errors=*/false,
+ /*emit_metrics=*/true);
+ sets_ = net::GlobalFirstPartySets(std::move(version),
+ std::move(public_sets.first),
+ std::move(public_sets.second));
component_sets_parse_progress_ = Progress::kFinished;
UmaHistogramTimes(
@@ -113,7 +117,9 @@ void FirstPartySetsLoader::MaybeFinishLoading() {
!manually_specified_set_.has_value()) {
return;
}
- sets_->ApplyManuallySpecifiedSet(manually_specified_set_.value());
+ if (!manually_specified_set_->empty()) {
+ sets_->ApplyManuallySpecifiedSet(manually_specified_set_->GetSet());
+ }
std::move(on_load_complete_).Run(std::move(sets_).value());
}
diff --git a/content/browser/first_party_sets/first_party_sets_loader.h b/content/browser/first_party_sets/first_party_sets_loader.h
index 1c49082d2fb462b0974ddf1bf46c4a254582b3c4..17fdab287fcc826de5100da62971585daee7615f 100644
--- a/content/browser/first_party_sets/first_party_sets_loader.h
+++ b/content/browser/first_party_sets/first_party_sets_loader.h
@@ -12,9 +12,11 @@
#include "base/sequence_checker.h"
#include "base/thread_annotations.h"
#include "base/timer/elapsed_timer.h"
+#include "content/browser/first_party_sets/local_set_declaration.h"
#include "content/common/content_export.h"
#include "net/first_party_sets/global_first_party_sets.h"
#include "net/first_party_sets/local_set_declaration.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace content {
@@ -36,8 +38,8 @@ class CONTENT_EXPORT FirstPartySetsLoader {
FirstPartySetsLoader& operator=(const FirstPartySetsLoader&) = delete;
// Stores the First-Party Set that was provided via the `kUseFirstPartySet`
- // flag/switch. Only the first call has any effect.
- void SetManuallySpecifiedSet(const net::LocalSetDeclaration& local_set);
+ // flag/switch.
+ void SetManuallySpecifiedSet(const LocalSetDeclaration& local_set);
// Asynchronously parses and stores the sets from `sets_file`, and merges with
// any previously-loaded sets as needed. In case of invalid input, the set of
@@ -47,9 +49,6 @@ class CONTENT_EXPORT FirstPartySetsLoader {
// invocations are ignored.
void SetComponentSets(base::Version version, base::File sets_file);
- // Closes the given file safely.
- static void DisposeFile(base::File file);
-
private:
// Parses the contents of `raw_sets` as a collection of First-Party Set
// declarations, and stores the result.
@@ -66,7 +65,7 @@ class CONTENT_EXPORT FirstPartySetsLoader {
// Holds the set that was provided on the command line (if any). This is
// nullopt until `SetManuallySpecifiedSet` is called.
- std::optional<net::LocalSetDeclaration> manually_specified_set_
+ absl::optional<LocalSetDeclaration> manually_specified_set_
GUARDED_BY_CONTEXT(sequence_checker_);
enum Progress {
diff --git a/content/browser/first_party_sets/first_party_sets_loader_unittest.cc b/content/browser/first_party_sets/first_party_sets_loader_unittest.cc
index 000941b0480c5c9cb2698ca7f4656c9439ba9d8f..2346d3b7c5253450a069dc83835818158579f788 100644
--- a/content/browser/first_party_sets/first_party_sets_loader_unittest.cc
+++ b/content/browser/first_party_sets/first_party_sets_loader_unittest.cc
@@ -169,6 +169,7 @@ TEST_F(FirstPartySetsLoaderTest, SetsManuallySpecified) {
Optional(net::FirstPartySetEntry(bar, net::SiteType::kAssociated, 0)));
}
+<<<<<<< HEAD
TEST_F(FirstPartySetsLoaderTest, SetsManuallySpecified_Idempotent) {
const net::SchemefulSite bar(GURL("https://bar.test"));
const net::SchemefulSite associated1(GURL("https://associatedsite1.test"));
@@ -208,4 +209,6 @@ TEST_F(FirstPartySetsLoaderTest, SetsManuallySpecified_Idempotent) {
bar, net::SiteType::kAssociated, 0))));
}
+=======
+>>>>>>> fix: revert sameparty cookie attribute removal
} // namespace content
diff --git a/content/browser/first_party_sets/local_set_declaration.cc b/content/browser/first_party_sets/local_set_declaration.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ec77f974a1ffad3fcb8ceb027eeb2c009dfed79c
--- /dev/null
+++ b/content/browser/first_party_sets/local_set_declaration.cc
@@ -0,0 +1,89 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/first_party_sets/local_set_declaration.h"
+
+#include <sstream>
+#include <string>
+
+#include "base/logging.h"
+#include "base/ranges/algorithm.h"
+#include "content/browser/first_party_sets/first_party_set_parser.h"
+#include "net/base/schemeful_site.h"
+#include "net/first_party_sets/first_party_set_entry.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace content {
+
+namespace {
+
+absl::optional<FirstPartySetParser::SingleSet> CanonicalizeSet(
+ const std::string& use_first_party_set_flag_value) {
+ std::istringstream stream(use_first_party_set_flag_value);
+
+ FirstPartySetParser::SetsAndAliases parsed =
+ FirstPartySetParser::ParseSetsFromStream(stream, /*emit_errors=*/true,
+ /*emit_metrics*/ false);
+
+ FirstPartySetParser::SetsMap entries = std::move(parsed.first);
+ FirstPartySetParser::Aliases aliases = std::move(parsed.second);
+
+ if (entries.empty()) {
+ return absl::nullopt;
+ }
+
+ const net::SchemefulSite primary = entries.begin()->second.primary();
+
+ if (base::ranges::any_of(
+ entries,
+ [&primary](const FirstPartySetParser::SetsMap::value_type& pair) {
+ return pair.second.primary() != primary;
+ })) {
+ // More than one set was provided. That is (currently) unsupported.
+ LOG(ERROR) << "Ignoring use-related-website-set switch due to multiple set "
+ "declarations.";
+ return absl::nullopt;
+ }
+
+ for (const auto& [alias, canonical] : aliases) {
+ auto it = entries.find(canonical);
+ CHECK(it != entries.end());
+ bool inserted = entries.emplace(alias, it->second).second;
+ CHECK(inserted);
+ }
+
+ return absl::make_optional(std::move(entries));
+}
+
+} // namespace
+
+LocalSetDeclaration::LocalSetDeclaration()
+ : LocalSetDeclaration(absl::nullopt) {}
+
+LocalSetDeclaration::LocalSetDeclaration(
+ const std::string& use_first_party_set_flag_value)
+ : LocalSetDeclaration(CanonicalizeSet(use_first_party_set_flag_value)) {}
+
+LocalSetDeclaration::LocalSetDeclaration(
+ absl::optional<FirstPartySetParser::SingleSet> parsed_set)
+ : parsed_set_(std::move(parsed_set)) {}
+
+LocalSetDeclaration::~LocalSetDeclaration() = default;
+
+LocalSetDeclaration::LocalSetDeclaration(const LocalSetDeclaration&) = default;
+LocalSetDeclaration& LocalSetDeclaration::operator=(
+ const LocalSetDeclaration&) = default;
+
+LocalSetDeclaration::LocalSetDeclaration(LocalSetDeclaration&&) = default;
+LocalSetDeclaration& LocalSetDeclaration::operator=(LocalSetDeclaration&&) =
+ default;
+
+const FirstPartySetParser::SingleSet& LocalSetDeclaration::GetSet() const {
+ CHECK(!empty());
+ const FirstPartySetParser::SingleSet& set = parsed_set_.value();
+ CHECK(!set.empty());
+ return set;
+}
+
+} // namespace content
diff --git a/content/browser/first_party_sets/local_set_declaration.h b/content/browser/first_party_sets/local_set_declaration.h
new file mode 100644
index 0000000000000000000000000000000000000000..7d1e3e6dd810a81d2abdd9a5cbfaa8faef277f77
--- /dev/null
+++ b/content/browser/first_party_sets/local_set_declaration.h
@@ -0,0 +1,48 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_FIRST_PARTY_SETS_LOCAL_SET_DECLARATION_H_
+#define CONTENT_BROWSER_FIRST_PARTY_SETS_LOCAL_SET_DECLARATION_H_
+
+#include <string>
+
+#include "content/browser/first_party_sets/first_party_set_parser.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class CONTENT_EXPORT LocalSetDeclaration {
+ public:
+ LocalSetDeclaration();
+
+ explicit LocalSetDeclaration(
+ const std::string& use_first_party_set_flag_value);
+
+ ~LocalSetDeclaration();
+
+ LocalSetDeclaration(const LocalSetDeclaration&);
+ LocalSetDeclaration& operator=(const LocalSetDeclaration&);
+ LocalSetDeclaration(LocalSetDeclaration&&);
+ LocalSetDeclaration& operator=(LocalSetDeclaration&&);
+
+ bool empty() const { return !parsed_set_.has_value(); }
+
+ size_t size() const { return empty() ? 0 : GetSet().size(); }
+
+ // Gets the set entries. Must not be called if `empty()` returns true.
+ const FirstPartySetParser::SingleSet& GetSet() const;
+
+ private:
+ explicit LocalSetDeclaration(
+ absl::optional<FirstPartySetParser::SingleSet> parsed_set);
+
+ // Stores the result of parsing the inputs. Specifically, this may be empty if
+ // no set was locally defined; otherwise, it holds the collection of
+ // FirstPartySetEntries and any ccTLD aliases.
+ absl::optional<FirstPartySetParser::SingleSet> parsed_set_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_FIRST_PARTY_SETS_LOCAL_SET_DECLARATION_H_
diff --git a/content/browser/first_party_sets/test/scoped_mock_first_party_sets_handler.cc b/content/browser/first_party_sets/test/scoped_mock_first_party_sets_handler.cc
index d9325e80b26c9aba49c5d71fc49daeac14933685..e3b2f0428a1ff0234326cc30bcd5a724c7c231be 100644
--- a/content/browser/first_party_sets/test/scoped_mock_first_party_sets_handler.cc
+++ b/content/browser/first_party_sets/test/scoped_mock_first_party_sets_handler.cc
@@ -44,7 +44,7 @@ ScopedMockFirstPartySetsHandler::FindEntry(
void ScopedMockFirstPartySetsHandler::Init(
const base::FilePath& user_data_dir,
- const net::LocalSetDeclaration& local_set) {}
+ const LocalSetDeclaration& local_set) {}
[[nodiscard]] std::optional<net::GlobalFirstPartySets>
ScopedMockFirstPartySetsHandler::GetSets(
diff --git a/content/browser/first_party_sets/test/scoped_mock_first_party_sets_handler.h b/content/browser/first_party_sets/test/scoped_mock_first_party_sets_handler.h
index 5df5104bf47270a038de4e188ac2592adccf590f..de44481760169c409369d38ff48edc84d194b34f 100644
--- a/content/browser/first_party_sets/test/scoped_mock_first_party_sets_handler.h
+++ b/content/browser/first_party_sets/test/scoped_mock_first_party_sets_handler.h
@@ -7,6 +7,7 @@
#include <optional>
#include <string>
+#include <utility>
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
@@ -67,8 +68,8 @@ class ScopedMockFirstPartySetsHandler
const net::FirstPartySetEntry&)> f) const override;
// FirstPartySetsHandlerImpl:
void Init(const base::FilePath& user_data_dir,
- const net::LocalSetDeclaration& local_set) override;
- [[nodiscard]] std::optional<net::GlobalFirstPartySets> GetSets(
+ const LocalSetDeclaration& local_set) override;
+ [[nodiscard]] absl::optional<net::GlobalFirstPartySets> GetSets(
base::OnceCallback<void(net::GlobalFirstPartySets)> callback) override;
// Helper functions for tests to set up context.
diff --git a/content/browser/media/android/media_resource_getter_impl.cc b/content/browser/media/android/media_resource_getter_impl.cc
index 1272f4b36aa27c08fd9cd57f3c89845533fbfae1..f853d1ff148a52f66ec7cf597eae01c82eef98cf 100644
--- a/content/browser/media/android/media_resource_getter_impl.cc
+++ b/content/browser/media/android/media_resource_getter_impl.cc
@@ -61,7 +61,7 @@ GetRestrictedCookieManagerForContext(
site_for_cookies.IsFirstParty(top_frame_origin.GetURL()));
net::IsolationInfo isolation_info = net::IsolationInfo::Create(
net::IsolationInfo::RequestType::kOther, top_frame_origin,
- top_frame_origin, site_for_cookies);
+ top_frame_origin, site_for_cookies, absl::nullopt);
mojo::PendingRemote<network::mojom::RestrictedCookieManager> pipe;
static_cast<StoragePartitionImpl*>(storage_partition)
diff --git a/content/browser/renderer_host/cookie_utils.cc b/content/browser/renderer_host/cookie_utils.cc
index b26798dd429a3de3221911c3e5fe6df3e7e2f1e6..08d4ef9a657a2f77e2a7f82ce08a2846ffeb7c19 100644
--- a/content/browser/renderer_host/cookie_utils.cc
+++ b/content/browser/renderer_host/cookie_utils.cc
@@ -190,6 +190,8 @@ void RecordSchemefulContextDowngradeUKM(
bool ShouldReportDevToolsIssueForStatus(
const net::CookieInclusionStatus& status) {
return status.ShouldWarn() ||
+ status.HasExclusionReason(
+ net::CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY) ||
status.HasExclusionReason(
net::CookieInclusionStatus::EXCLUDE_DOMAIN_NON_ASCII) ||
status.HasExclusionReason(
@@ -229,6 +231,10 @@ void EmitCookieWarningsAndMetricsOnce(
bool breaking_context_downgrade = false;
bool lax_allow_unsafe_cookies = false;
+ bool same_party = false;
+ bool same_party_exclusion_overruled_samesite = false;
+ bool same_party_inclusion_overruled_samesite = false;
+
bool samesite_cookie_inclusion_changed_by_cross_site_redirect = false;
bool partitioned_cookies_exist = false;
@@ -286,6 +292,22 @@ void EmitCookieWarningsAndMetricsOnce(
net::CookieInclusionStatus::
WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE);
+ same_party = same_party ||
+ status.HasWarningReason(
+ net::CookieInclusionStatus::WARN_TREATED_AS_SAMEPARTY);
+
+ same_party_exclusion_overruled_samesite =
+ same_party_exclusion_overruled_samesite ||
+ status.HasWarningReason(
+ net::CookieInclusionStatus::
+ WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE);
+
+ same_party_inclusion_overruled_samesite =
+ same_party_inclusion_overruled_samesite ||
+ status.HasWarningReason(
+ net::CookieInclusionStatus::
+ WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE);
+
samesite_cookie_inclusion_changed_by_cross_site_redirect =
samesite_cookie_inclusion_changed_by_cross_site_redirect ||
status.HasWarningReason(
@@ -385,6 +407,23 @@ void EmitCookieWarningsAndMetricsOnce(
rfh, blink::mojom::WebFeature::kLaxAllowingUnsafeCookies);
}
+ if (same_party) {
+ GetContentClient()->browser()->LogWebFeatureForCurrentPage(
+ rfh, blink::mojom::WebFeature::kSamePartyCookieAttribute);
+ }
+
+ if (same_party_exclusion_overruled_samesite) {
+ GetContentClient()->browser()->LogWebFeatureForCurrentPage(
+ rfh,
+ blink::mojom::WebFeature::kSamePartyCookieExclusionOverruledSameSite);
+ }
+
+ if (same_party_inclusion_overruled_samesite) {
+ GetContentClient()->browser()->LogWebFeatureForCurrentPage(
+ rfh,
+ blink::mojom::WebFeature::kSamePartyCookieInclusionOverruledSameSite);
+ }
+
if (samesite_cookie_inclusion_changed_by_cross_site_redirect) {
GetContentClient()->browser()->LogWebFeatureForCurrentPage(
rfh, blink::mojom::WebFeature::
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index bafeeb41441d7a585bef170f81d69fe54417da63..e9385fef76514e7b341a1b35adfafc3e4f16189d 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -4157,7 +4157,10 @@ net::IsolationInfo RenderFrameHostImpl::ComputeIsolationInfoInternal(
net::SiteForCookies candidate_site_for_cookies(top_frame_site);
- // Walk up the frame tree to check SiteForCookies.
+ std::set<net::SchemefulSite> party_context;
+
+ // Walk up the frame tree to check SiteForCookies and compute the
+ // |party_context|.
//
// If |request_type| is kOther, then IsolationInfo is being computed
// for subresource requests. Check/compute starting from the frame itself.
@@ -4175,6 +4178,9 @@ net::IsolationInfo RenderFrameHostImpl::ComputeIsolationInfoInternal(
rfh == this ? frame_origin : rfh->last_committed_origin_;
net::SchemefulSite cur_site = net::SchemefulSite(cur_origin);
+ if (top_frame_site != cur_site) {
+ party_context.insert(cur_site);
+ }
candidate_site_for_cookies.CompareWithFrameTreeSiteAndRevise(cur_site);
}
@@ -4192,7 +4198,7 @@ net::IsolationInfo RenderFrameHostImpl::ComputeIsolationInfoInternal(
ComputeNonce(is_credentialless, fenced_frame_nonce_for_navigation);
return net::IsolationInfo::Create(request_type, top_frame_origin,
frame_origin, candidate_site_for_cookies,
- nonce);
+ std::move(party_context), nonce);
}
std::optional<base::UnguessableToken> RenderFrameHostImpl::ComputeNonce(
diff --git a/content/browser/service_worker/service_worker_main_resource_loader_interceptor.cc b/content/browser/service_worker/service_worker_main_resource_loader_interceptor.cc
index 055ee2779362331aa87699131d6ba226003b03aa..1d2641a247dfbda1885b2567759b98167bf39eb6 100644
--- a/content/browser/service_worker/service_worker_main_resource_loader_interceptor.cc
+++ b/content/browser/service_worker/service_worker_main_resource_loader_interceptor.cc
@@ -221,7 +221,7 @@ void ServiceWorkerMainResourceLoaderInterceptor::MaybeCreateLoader(
isolation_info_ = net::IsolationInfo::Create(
isolation_info_.request_type(),
isolation_info_.top_frame_origin().value(), new_origin,
- new_site_for_cookies, isolation_info_.nonce());
+ new_site_for_cookies, absl::nullopt, isolation_info_.nonce());
// Attempt to get the storage key from |RenderFrameHostImpl|. This correctly
// accounts for extension URLs. The absence of this logic was a potential
diff --git a/content/browser/worker_host/shared_worker_host.cc b/content/browser/worker_host/shared_worker_host.cc
index 2cf831086db9eb7b65c3a53da70a295448af0121..b0ef55c6351a8f7e07f8626416a7ce92496715ba 100644
--- a/content/browser/worker_host/shared_worker_host.cc
+++ b/content/browser/worker_host/shared_worker_host.cc
@@ -428,7 +428,14 @@ SharedWorkerHost::CreateNetworkFactoryParamsForSubresources() {
}
network::mojom::URLLoaderFactoryParamsPtr factory_params =
URLLoaderFactoryParamsHelper::CreateForWorker(
- GetProcessHost(), origin, GetStorageKey().ToPartialNetIsolationInfo(),
+ GetProcessHost(), origin,
+ net::IsolationInfo::Create(
+ net::IsolationInfo::RequestType::kOther,
+ // TODO(https://crbug.com/1147281): We
+ // should pass the top_level_site from
+ // `GetStorageKey()` instead.
+ origin, origin, net::SiteForCookies::FromOrigin(origin),
+ /*party_context=*/absl::nullopt, GetStorageKey().nonce()),
std::move(coep_reporter),
/*url_loader_network_observer=*/mojo::NullRemote(),
/*devtools_observer=*/mojo::NullRemote(),
diff --git a/content/browser/worker_host/shared_worker_service_impl.cc b/content/browser/worker_host/shared_worker_service_impl.cc
index fd286b84287d247ad04cb62f4e7560db3d5040d5..3f1c9919d207dab6da985778bcbfe29f2c5ea708 100644
--- a/content/browser/worker_host/shared_worker_service_impl.cc
+++ b/content/browser/worker_host/shared_worker_service_impl.cc
@@ -370,7 +370,11 @@ SharedWorkerHost* SharedWorkerServiceImpl::CreateWorker(
worker_process_host->GetID(), host->token(), host->instance().url(),
&creator, &creator, host->instance().storage_key().ToNetSiteForCookies(),
host->instance().storage_key().origin(), host->instance().storage_key(),
- host->instance().storage_key().ToPartialNetIsolationInfo(),
+ net::IsolationInfo::Create(net::IsolationInfo::RequestType::kOther,
+ worker_origin, worker_origin,
+ net::SiteForCookies::FromOrigin(worker_origin),
+ /*party_context=*/absl::nullopt,
+ host->instance().storage_key().nonce()),
creator.BuildClientSecurityStateForWorkers(), credentials_mode,
std::move(outside_fetch_client_settings_object),
network::mojom::RequestDestination::kSharedWorker,
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index c7f6be5f6a651647cc3f6814f25ce4cb0bf1e4ef..a86f719d115fb400bceb1e1bdf213b8b4f667700 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -1913,7 +1913,8 @@ class CONTENT_EXPORT ContentBrowserClient {
// |site_for_cookies| is empty, no domains are first-party).
// |top_frame_origin| held by |isolation_info| represents the domain for
// top-level frame, and can be used to look up preferences that are dependent
- // on that.
+ // on that. |party_context| hold by |isolation_info| is for the purposes of
+ // SameParty cookies inclusion calculation.
//
// |*receiver| is always valid upon entry.
//
diff --git a/content/public/browser/first_party_sets_handler.h b/content/public/browser/first_party_sets_handler.h
index 9ec93b54956dc17e0ad9e7383830761812199e2f..029c546412649326ac74e0de47b773efe747e3d6 100644
--- a/content/public/browser/first_party_sets_handler.h
+++ b/content/public/browser/first_party_sets_handler.h
@@ -194,6 +194,7 @@ class CONTENT_EXPORT FirstPartySetsHandler {
virtual void ComputeFirstPartySetMetadata(
const net::SchemefulSite& site,
const net::SchemefulSite* top_frame_site,
+ const std::set<net::SchemefulSite>& party_context,
const net::FirstPartySetsContextConfig& config,
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) = 0;
diff --git a/google_apis/gaia/oauth2_mint_token_flow.cc b/google_apis/gaia/oauth2_mint_token_flow.cc
index 4d7761e1d66665d4dbaa9d6b46f38fb0e2cfb288..ca7bf54fd1610619105b08e0041a81415e2df547 100644
--- a/google_apis/gaia/oauth2_mint_token_flow.cc
+++ b/google_apis/gaia/oauth2_mint_token_flow.cc
@@ -474,7 +474,7 @@ bool OAuth2MintTokenFlow::ParseRemoteConsentResponse(
is_secure ? *is_secure : false,
is_http_only ? *is_http_only : false,
net::StringToCookieSameSite(same_site ? *same_site : ""),
- net::COOKIE_PRIORITY_DEFAULT,
+ net::COOKIE_PRIORITY_DEFAULT, /* same_party */ false,
/* partition_key */ std::nullopt);
cookies.push_back(*cookie);
}
diff --git a/google_apis/gaia/oauth_multilogin_result.cc b/google_apis/gaia/oauth_multilogin_result.cc
index 22a559059bc033ab3b2abd8a39e10671dd445cd4..be37adbd30714ee9fc6176f979ccba81d3713e2c 100644
--- a/google_apis/gaia/oauth_multilogin_result.cc
+++ b/google_apis/gaia/oauth_multilogin_result.cc
@@ -105,6 +105,7 @@ void OAuthMultiloginResult::TryParseCookiesFromValue(
const std::string* priority = cookie_dict.FindString("priority");
std::optional<double> expiration_delta = cookie_dict.FindDouble("maxAge");
const std::string* same_site = cookie_dict.FindString("sameSite");
+ const std::string* same_party = cookie_dict.FindString("sameParty");
base::Time now = base::Time::Now();
// TODO(crbug.com/1264458) If CreateSanitizedCookie were used below, this
@@ -130,6 +131,7 @@ void OAuthMultiloginResult::TryParseCookiesFromValue(
samesite_mode = net::StringToCookieSameSite(*same_site, &samesite_string);
}
net::RecordCookieSameSiteAttributeValueHistogram(samesite_string);
+ bool same_party_bool = same_party && (*same_party == "1");
// TODO(crbug.com/1155648) Consider using CreateSanitizedCookie instead.
std::unique_ptr<net::CanonicalCookie> new_cookie =
net::CanonicalCookie::FromStorage(
@@ -138,8 +140,8 @@ void OAuthMultiloginResult::TryParseCookiesFromValue(
/*last_access=*/now, /*last_update=*/now, is_secure.value_or(true),
is_http_only.value_or(true), samesite_mode,
net::StringToCookiePriority(priority ? *priority : "medium"),
- /*partition_key=*/std::nullopt, net::CookieSourceScheme::kUnset,
- url::PORT_UNSPECIFIED);
+ same_party_bool, /*partition_key=*/std::nullopt,
+ net::CookieSourceScheme::kUnset, url::PORT_UNSPECIFIED);
// If the unique_ptr is null, it means the cookie was not canonical.
// FromStorage() also uses a less strict version of IsCanonical(), we need
// to check the stricter version as well here.
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 65bc73a317778a9ec085bb5744a50c8bf271215a..7ed364bb5844891454bf18d7c7c6e8b08723a78f 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -516,6 +516,8 @@ component("net") {
"first_party_sets/local_set_declaration.h",
"first_party_sets/sets_mutation.cc",
"first_party_sets/sets_mutation.h",
+ "first_party_sets/same_party_context.cc",
+ "first_party_sets/same_party_context.h",
"http/alternative_service.cc",
"http/alternative_service.h",
"http/bidirectional_stream.cc",
diff --git a/net/base/features.cc b/net/base/features.cc
index 84235adad43d182bd0471b9465557d293bffed1d..f5eae4b9b02f6297772de9062e138ee26871e946 100644
--- a/net/base/features.cc
+++ b/net/base/features.cc
@@ -230,6 +230,10 @@ BASE_FEATURE(kCookieSameSiteConsidersRedirectChain,
"CookieSameSiteConsidersRedirectChain",
base::FEATURE_DISABLED_BY_DEFAULT);
+BASE_FEATURE(kSamePartyAttributeEnabled,
+ "SamePartyAttributeEnabled",
+ base::FEATURE_DISABLED_BY_DEFAULT);
+
BASE_FEATURE(kWaitForFirstPartySetsInit,
"WaitForFirstPartySetsInit",
base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/net/base/features.h b/net/base/features.h
index f4afe84de8dc3b1f4cc1692af6fd0f7f7ae77816..79420b79a3e812140f1d02fee6a26760bb458b1c 100644
--- a/net/base/features.h
+++ b/net/base/features.h
@@ -282,6 +282,12 @@ NET_EXPORT BASE_DECLARE_FEATURE(kUdpSocketPosixAlwaysUpdateBytesReceived);
// See spec changes in https://github.com/httpwg/http-extensions/pull/1348
NET_EXPORT BASE_DECLARE_FEATURE(kCookieSameSiteConsidersRedirectChain);
+// When this feature is enabled, the SameParty attribute is enabled. (Note that
+// when this feature is disabled, the SameParty attribute is still parsed and
+// saved for cookie-sets, but it has no associated semantics (when setting or
+// reading cookies).)
+NET_EXPORT BASE_DECLARE_FEATURE(kSamePartyAttributeEnabled);
+
// When this feature is enabled, the network service will wait until First-Party
// Sets are initialized before issuing requests that use the HTTP cache or
// cookies.
diff --git a/net/base/isolation_info.cc b/net/base/isolation_info.cc
index c58b63d3fc63a29b374ef60c80134354f28bf18d..2c03a4c29fb5ca56ea7ed223230241961c41b594 100644
--- a/net/base/isolation_info.cc
+++ b/net/base/isolation_info.cc
@@ -48,11 +48,13 @@ bool IsConsistent(IsolationInfo::RequestType request_type,
const std::optional<url::Origin>& top_frame_origin,
const std::optional<url::Origin>& frame_origin,
const SiteForCookies& site_for_cookies,
- const std::optional<base::UnguessableToken>& nonce) {
+ absl::optional<std::set<SchemefulSite>> party_context,
+ const absl::optional<base::UnguessableToken>& nonce) {
// Check for the default-constructed case.
if (!top_frame_origin) {
return request_type == IsolationInfo::RequestType::kOther &&
- !frame_origin && !nonce && site_for_cookies.IsNull();
+ !frame_origin && !nonce && site_for_cookies.IsNull() &&
+ !party_context;
}
// As long as there is a |top_frame_origin|, |site_for_cookies| must be
@@ -74,6 +76,9 @@ bool IsConsistent(IsolationInfo::RequestType request_type,
//
// TODO(https://crbug.com/1060631): Once CreatePartial() is removed,
// check if SiteForCookies is non-null if the scheme is HTTP or HTTPS.
+ //
+ // TODO(https://crbug.com/1151947): Once CreatePartial() is removed,
+ // check if party_context is non-null and empty.
break;
case IsolationInfo::RequestType::kSubFrame:
// For subframe navigations, the subframe's origin may not be consistent
@@ -95,7 +100,8 @@ IsolationInfo::IsolationInfo()
/*top_frame_origin=*/std::nullopt,
/*frame_origin=*/std::nullopt,
SiteForCookies(),
- /*nonce=*/std::nullopt) {}
+ /*nonce=*/absl::nullopt,
+ /*party_context=*/absl::nullopt) {}
IsolationInfo::IsolationInfo(const IsolationInfo&) = default;
IsolationInfo::IsolationInfo(IsolationInfo&&) = default;
@@ -107,13 +113,15 @@ IsolationInfo IsolationInfo::CreateForInternalRequest(
const url::Origin& top_frame_origin) {
return IsolationInfo(RequestType::kOther, top_frame_origin, top_frame_origin,
SiteForCookies::FromOrigin(top_frame_origin),
- /*nonce=*/std::nullopt);
+ /*nonce=*/absl::nullopt,
+ /*party_context=*/std::set<SchemefulSite>());
}
IsolationInfo IsolationInfo::CreateTransient() {
url::Origin opaque_origin;
return IsolationInfo(RequestType::kOther, opaque_origin, opaque_origin,
- SiteForCookies(), /*nonce=*/std::nullopt);
+ SiteForCookies(), /*nonce=*/absl::nullopt,
+ /*party_context=*/absl::nullopt);
}
std::optional<IsolationInfo> IsolationInfo::Deserialize(
@@ -130,11 +138,19 @@ std::optional<IsolationInfo> IsolationInfo::Deserialize(
if (proto.has_frame_origin())
frame_origin = url::Origin::Create(GURL(proto.frame_origin()));
+ absl::optional<std::set<SchemefulSite>> party_context;
+ if (proto.has_party_context()) {
+ party_context = std::set<SchemefulSite>();
+ for (const auto& site : proto.party_context().site()) {
+ party_context->insert(SchemefulSite::Deserialize(site));
+ }
+ }
+
return IsolationInfo::CreateIfConsistent(
static_cast<RequestType>(proto.request_type()),
std::move(top_frame_origin), std::move(frame_origin),
SiteForCookies::FromUrl(GURL(proto.site_for_cookies())),
- /*nonce=*/std::nullopt);
+ std::move(party_context), /*nonce=*/absl::nullopt);
}
IsolationInfo IsolationInfo::Create(
@@ -142,9 +158,10 @@ IsolationInfo IsolationInfo::Create(
const url::Origin& top_frame_origin,
const url::Origin& frame_origin,
const SiteForCookies& site_for_cookies,
- const std::optional<base::UnguessableToken>& nonce) {
+ absl::optional<std::set<SchemefulSite>> party_context,
+ const absl::optional<base::UnguessableToken>& nonce) {
return IsolationInfo(request_type, top_frame_origin, frame_origin,
- site_for_cookies, nonce);
+ site_for_cookies, nonce, std::move(party_context));
}
IsolationInfo IsolationInfo::DoNotUseCreatePartialFromNak(
@@ -173,7 +190,8 @@ IsolationInfo IsolationInfo::DoNotUseCreatePartialFromNak(
auto isolation_info = IsolationInfo::Create(
IsolationInfo::RequestType::kOther, top_frame_origin,
- frame_origin.value(), SiteForCookies(), nonce);
+ frame_origin.value(), SiteForCookies(),
+ /*party_context=*/absl::nullopt, nonce);
// TODO(crbug/1343856): DCHECK isolation info is fully populated.
return isolation_info;
}
@@ -183,13 +201,14 @@ std::optional<IsolationInfo> IsolationInfo::CreateIfConsistent(
const std::optional<url::Origin>& top_frame_origin,
const std::optional<url::Origin>& frame_origin,
const SiteForCookies& site_for_cookies,
- const std::optional<base::UnguessableToken>& nonce) {
+ absl::optional<std::set<SchemefulSite>> party_context,
+ const absl::optional<base::UnguessableToken>& nonce) {
if (!IsConsistent(request_type, top_frame_origin, frame_origin,
- site_for_cookies, nonce)) {
- return std::nullopt;
+ site_for_cookies, party_context, nonce)) {
+ return absl::nullopt;
}
return IsolationInfo(request_type, top_frame_origin, frame_origin,
- site_for_cookies, nonce);
+ site_for_cookies, nonce, std::move(party_context));
}
IsolationInfo IsolationInfo::CreateForRedirect(
@@ -199,12 +218,14 @@ IsolationInfo IsolationInfo::CreateForRedirect(
if (request_type_ == RequestType::kSubFrame) {
return IsolationInfo(request_type_, top_frame_origin_, new_origin,
- site_for_cookies_, nonce_);
+ site_for_cookies_, nonce_, party_context_);
}
DCHECK_EQ(RequestType::kMainFrame, request_type_);
+ DCHECK(!party_context_ || party_context_->empty());
return IsolationInfo(request_type_, new_origin, new_origin,
- SiteForCookies::FromOrigin(new_origin), nonce_);
+ SiteForCookies::FromOrigin(new_origin), nonce_,
+ party_context_);
}
const std::optional<url::Origin>& IsolationInfo::frame_origin() const {
@@ -223,7 +244,8 @@ bool IsolationInfo::IsEqualForTesting(const IsolationInfo& other) const {
network_isolation_key_ == other.network_isolation_key_ &&
network_anonymization_key_ == other.network_anonymization_key_ &&
nonce_ == other.nonce_ &&
- site_for_cookies_.IsEquivalent(other.site_for_cookies_));
+ site_for_cookies_.IsEquivalent(other.site_for_cookies_) &&
+ party_context_ == other.party_context_);
}
std::string IsolationInfo::Serialize() const {
@@ -242,6 +264,13 @@ std::string IsolationInfo::Serialize() const {
info.set_site_for_cookies(site_for_cookies_.RepresentativeUrl().spec());
+ if (party_context_) {
+ auto* pc = info.mutable_party_context();
+ for (const auto& site : *party_context_) {
+ pc->add_site(site.Serialize());
+ }
+ }
+
return info.SerializeAsString();
}
@@ -280,6 +309,18 @@ std::string IsolationInfo::DebugString() const {
s += "; network_isolation_key: ";
s += network_isolation_key_.ToDebugString();
+ s += "; party_context: ";
+ if (party_context_) {
+ s += "{";
+ for (auto& site : party_context_.value()) {
+ s += site.GetDebugString();
+ s += ", ";
+ }
+ s += "}";
+ } else {
+ s += "(none)";
+ }
+
s += "; nonce: ";
if (nonce_) {
s += nonce_.value().ToString();
@@ -308,11 +349,13 @@ IsolationInfo::CreateNetworkAnonymizationKeyForIsolationInfo(
frame_site, nonce);
}
-IsolationInfo::IsolationInfo(RequestType request_type,
- const std::optional<url::Origin>& top_frame_origin,
- const std::optional<url::Origin>& frame_origin,
- const SiteForCookies& site_for_cookies,
- const std::optional<base::UnguessableToken>& nonce)
+IsolationInfo::IsolationInfo(
+ RequestType request_type,
+ const absl::optional<url::Origin>& top_frame_origin,
+ const absl::optional<url::Origin>& frame_origin,
+ const SiteForCookies& site_for_cookies,
+ const absl::optional<base::UnguessableToken>& nonce,
+ absl::optional<std::set<SchemefulSite>> party_context)
: request_type_(request_type),
top_frame_origin_(top_frame_origin),
frame_origin_(frame_origin),
@@ -327,9 +370,13 @@ IsolationInfo::IsolationInfo(RequestType request_type,
frame_origin,
nonce)),
site_for_cookies_(site_for_cookies),
- nonce_(nonce) {
+ nonce_(nonce),
+ party_context_(party_context.has_value() &&
+ party_context->size() > kPartyContextMaxSize
+ ? absl::nullopt
+ : party_context) {
DCHECK(IsConsistent(request_type_, top_frame_origin_, frame_origin_,
- site_for_cookies_, nonce));
+ site_for_cookies_, party_context_, nonce));
}
} // namespace net
diff --git a/net/base/isolation_info.h b/net/base/isolation_info.h
index c391feb3dab23ebe8ea600846d0d7d79b9b96369..0f9313b155e94ee82d935835b5fec5687f99c1d4 100644
--- a/net/base/isolation_info.h
+++ b/net/base/isolation_info.h
@@ -67,8 +67,11 @@ class NET_EXPORT IsolationInfo {
kOther,
};
+ // Bound the party_context size with a reasonable number.
+ static constexpr size_t kPartyContextMaxSize = 20;
+
// Default constructor returns an IsolationInfo with empty origins, a null
- // SiteForCookies(), and a RequestType of kOther.
+ // SiteForCookies(), null |party_context|, and a RequestType of kOther.
IsolationInfo();
IsolationInfo(const IsolationInfo&);
IsolationInfo(IsolationInfo&&);
@@ -80,7 +83,7 @@ class NET_EXPORT IsolationInfo {
// Simple constructor for internal requests. Sets |frame_origin| and
// |site_for_cookies| match |top_frame_origin|. Sets |request_type| to
// kOther. Will only send SameSite cookies to the site associated with
- // the passed in origin.
+ // the passed in origin. |party_context| is set to be an empty set.
static IsolationInfo CreateForInternalRequest(
const url::Origin& top_frame_origin);
@@ -105,6 +108,7 @@ class NET_EXPORT IsolationInfo {
// * If |request_type| is kOther, |top_frame_origin| and
// |frame_origin| must be first party with respect to |site_for_cookies|, or
// |site_for_cookies| must be null.
+ // * If |party_context| is not empty, |top_frame_origin| must not be null.
// * If |nonce| is specified, then |top_frame_origin| must not be null.
//
// Note that the |site_for_cookies| consistency checks are skipped when
@@ -114,7 +118,8 @@ class NET_EXPORT IsolationInfo {
const url::Origin& top_frame_origin,
const url::Origin& frame_origin,
const SiteForCookies& site_for_cookies,
- const std::optional<base::UnguessableToken>& nonce = std::nullopt);
+ absl::optional<std::set<SchemefulSite>> party_context = absl::nullopt,
+ const absl::optional<base::UnguessableToken>& nonce = absl::nullopt);
// TODO(crbug/1372769): Remove this and create a safer way to ensure NIKs
// created from NAKs aren't used by accident.
@@ -132,7 +137,8 @@ class NET_EXPORT IsolationInfo {
const std::optional<url::Origin>& top_frame_origin,
const std::optional<url::Origin>& frame_origin,
const SiteForCookies& site_for_cookies,
- const std::optional<base::UnguessableToken>& nonce = std::nullopt);
+ absl::optional<std::set<SchemefulSite>> party_context = absl::nullopt,
+ const absl::optional<base::UnguessableToken>& nonce = absl::nullopt);
// Create a new IsolationInfo for a redirect to the supplied origin. |this| is
// unmodified.
@@ -174,6 +180,15 @@ class NET_EXPORT IsolationInfo {
// Do not use outside of testing. Returns the `frame_origin_`.
const std::optional<url::Origin>& frame_origin_for_testing() const;
+ // Return |party_context| which exclude the top frame origin and the frame
+ // origin.
+ // TODO(mmenke): Make this function PartyContextForTesting() after switching
+ // RenderFrameHostImpl to use the parent IsolationInfo to create the child
+ // IsolationInfo instead of walking through all parent frames.
+ const absl::optional<std::set<SchemefulSite>>& party_context() const {
+ return party_context_;
+ }
+
bool IsEqualForTesting(const IsolationInfo& other) const;
NetworkAnonymizationKey CreateNetworkAnonymizationKeyForIsolationInfo(
@@ -192,7 +207,8 @@ class NET_EXPORT IsolationInfo {
const std::optional<url::Origin>& top_frame_origin,
const std::optional<url::Origin>& frame_origin,
const SiteForCookies& site_for_cookies,
- const std::optional<base::UnguessableToken>& nonce);
+ const absl::optional<base::UnguessableToken>& nonce,
+ absl::optional<std::set<SchemefulSite>> party_context);
RequestType request_type_;
@@ -211,7 +227,26 @@ class NET_EXPORT IsolationInfo {
// for non-opaque origins.
std::optional<base::UnguessableToken> nonce_;
- // Mojo serialization code needs to access internal fields.
+ // This will hold the list of distinct sites in the form of SchemefulSite to
+ // be used for First-Party-Sets check.
+ //
+ // For |request_type_| being either RequestType::kMainFrame or
+ // RequestType::kSubFrame, |party_context| holds the set of the sites
+ // of the frames in between the current frame and the top frame (i.e. not
+ // considering the current frame or the top frame).
+ //
+ // For |request_type_| being RequestType::kOther, |party_context_| holds the
+ // above, and also the site of the current frame.
+ //
+ // Note that if an intermediate frame shares a site with the top frame, that
+ // frame's site is not reflected in the |party_context_|. Also note that if an
+ // intermediate frame shares a site with the current frame, that frame's site
+ // is still included in the set. The top frame's site is excluded because it
+ // is redundant with the |top_frame_origin_| field. The current frame is
+ // excluded to make it easier to update on subframe redirects.
+ absl::optional<std::set<SchemefulSite>> party_context_;
+
+ // Mojo serialization code needs to access internal party_context_ field.
friend struct mojo::StructTraits<network::mojom::IsolationInfoDataView,
IsolationInfo>;
};
diff --git a/net/base/isolation_info.proto b/net/base/isolation_info.proto
index 249f7bf414d44c0345650f72ffdfe99414073a2a..9a769ab079c0f2d632fcc46527d5d1b9b7838fad 100644
--- a/net/base/isolation_info.proto
+++ b/net/base/isolation_info.proto
@@ -14,6 +14,6 @@ message IsolationInfo {
optional string frame_origin = 3;
optional string site_for_cookies = 4;
- reserved 5;
- reserved "party_context";
+ message PartyContext { repeated string site = 1; }
+ optional PartyContext party_context = 5;
}
\ No newline at end of file
diff --git a/net/base/network_delegate.cc b/net/base/network_delegate.cc
index 6aad5c02def9fd6556bb9e65b0b53e138f71481f..33b1a0010ddd63381bd46bd5f74c5c953d77f876 100644
--- a/net/base/network_delegate.cc
+++ b/net/base/network_delegate.cc
@@ -168,6 +168,16 @@ bool NetworkDelegate::CanUseReportingClient(const url::Origin& origin,
return OnCanUseReportingClient(origin, endpoint);
}
+absl::optional<FirstPartySetsCacheFilter::MatchInfo>
+NetworkDelegate::GetFirstPartySetsCacheFilterMatchInfoMaybeAsync(
+ const SchemefulSite& request_site,
+ base::OnceCallback<void(FirstPartySetsCacheFilter::MatchInfo)> callback)
+ const {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ return OnGetFirstPartySetsCacheFilterMatchInfoMaybeAsync(request_site,
+ std::move(callback));
+}
+
// static
void NetworkDelegate::ExcludeAllCookies(
net::CookieInclusionStatus::ExclusionReason reason,
diff --git a/net/base/network_delegate.h b/net/base/network_delegate.h
index d1bd6c2cfcd02bb3cb030e82693c91013deebe99..145933ebd1fe6de0c9b3b05deedbeff7c4f1cccd 100644
--- a/net/base/network_delegate.h
+++ b/net/base/network_delegate.h
@@ -48,6 +48,7 @@ class CookieInclusionStatus;
class HttpRequestHeaders;
class HttpResponseHeaders;
class IPEndPoint;
+class SchemefulSite;
class URLRequest;
class NET_EXPORT NetworkDelegate {
@@ -121,6 +122,20 @@ class NET_EXPORT NetworkDelegate {
bool CanUseReportingClient(const url::Origin& origin,
const GURL& endpoint) const;
+ // Gets the First-Party Sets cache filter info, which is used to mark the
+ // cache and determine if the previously stored cache of `request_site` can be
+ // accessed.
+ //
+ // The result may be returned synchronously, or `callback` may be invoked
+ // asynchronously with the result. The callback will be invoked iff the return
+ // value is nullopt; i.e. a result will be provided via return value or
+ // callback, but not both, and not neither.
+ absl::optional<FirstPartySetsCacheFilter::MatchInfo>
+ GetFirstPartySetsCacheFilterMatchInfoMaybeAsync(
+ const SchemefulSite& request_site,
+ base::OnceCallback<void(FirstPartySetsCacheFilter::MatchInfo)> callback)
+ const;
+
protected:
// Adds the given ExclusionReason to all cookies in
// `mayble_included_cookies`, and moves the contents of
@@ -291,6 +306,12 @@ class NET_EXPORT NetworkDelegate {
virtual bool OnCanUseReportingClient(const url::Origin& origin,
const GURL& endpoint) const = 0;
+
+ virtual absl::optional<FirstPartySetsCacheFilter::MatchInfo>
+ OnGetFirstPartySetsCacheFilterMatchInfoMaybeAsync(
+ const SchemefulSite& request_site,
+ base::OnceCallback<void(FirstPartySetsCacheFilter::MatchInfo)> callback)
+ const = 0;
};
} // namespace net
diff --git a/net/base/network_delegate_impl.cc b/net/base/network_delegate_impl.cc
index d4c02a79b022afcce7dffc6f42940bb93df6957f..fc89f9d80d786511ecf04acf89b58100b254a282 100644
--- a/net/base/network_delegate_impl.cc
+++ b/net/base/network_delegate_impl.cc
@@ -98,4 +98,12 @@ bool NetworkDelegateImpl::OnCanUseReportingClient(const url::Origin& origin,
return true;
}
+absl::optional<FirstPartySetsCacheFilter::MatchInfo>
+NetworkDelegateImpl::OnGetFirstPartySetsCacheFilterMatchInfoMaybeAsync(
+ const SchemefulSite& request_site,
+ base::OnceCallback<void(FirstPartySetsCacheFilter::MatchInfo)> callback)
+ const {
+ return {FirstPartySetsCacheFilter::MatchInfo()};
+}
+
} // namespace net
diff --git a/net/base/network_delegate_impl.h b/net/base/network_delegate_impl.h
index 812f471436512a3e1f7ddef3d243b91b46a4288c..dd9ea88cf43f332668aec575ab135b9e3be55446 100644
--- a/net/base/network_delegate_impl.h
+++ b/net/base/network_delegate_impl.h
@@ -28,6 +28,7 @@ class Origin;
namespace net {
+class SchemefulSite;
class CookieOptions;
class CookieInclusionStatus;
class HttpRequestHeaders;
@@ -101,6 +102,12 @@ class NET_EXPORT NetworkDelegateImpl : public NetworkDelegate {
bool OnCanUseReportingClient(const url::Origin& origin,
const GURL& endpoint) const override;
+
+ absl::optional<FirstPartySetsCacheFilter::MatchInfo>
+ OnGetFirstPartySetsCacheFilterMatchInfoMaybeAsync(
+ const SchemefulSite& request_site,
+ base::OnceCallback<void(FirstPartySetsCacheFilter::MatchInfo)> callback)
+ const override;
};
} // namespace net
diff --git a/net/cookies/canonical_cookie.cc b/net/cookies/canonical_cookie.cc
index 02636104eae6d2223d637a11a89f92fcaf1497cc..1b76fecd6b10291ab027f61f38fdca2a9bacfcc8 100644
--- a/net/cookies/canonical_cookie.cc
+++ b/net/cookies/canonical_cookie.cc
@@ -364,9 +364,11 @@ void HistogramSessionCookieAge(const CanonicalCookie& cookie) {
} // namespace
CookieAccessParams::CookieAccessParams(CookieAccessSemantics access_semantics,
- bool delegate_treats_url_as_trustworthy)
+ bool delegate_treats_url_as_trustworthy,
+ CookieSamePartyStatus same_party_status)
: access_semantics(access_semantics),
- delegate_treats_url_as_trustworthy(delegate_treats_url_as_trustworthy) {}
+ delegate_treats_url_as_trustworthy(delegate_treats_url_as_trustworthy),
+ same_party_status(same_party_status) {}
CanonicalCookie::CanonicalCookie() = default;
@@ -393,6 +395,7 @@ CanonicalCookie::CanonicalCookie(
bool httponly,
CookieSameSite same_site,
CookiePriority priority,
+ bool same_party,
absl::optional<CookiePartitionKey> partition_key,
CookieSourceScheme source_scheme,
int source_port)
@@ -408,6 +411,7 @@ CanonicalCookie::CanonicalCookie(
httponly_(httponly),
same_site_(same_site),
priority_(priority),
+ same_party_(same_party),
partition_key_(std::move(partition_key)),
source_scheme_(source_scheme),
source_port_(source_port) {}
@@ -641,6 +645,12 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::Create(
status->AddExclusionReason(CookieInclusionStatus::EXCLUDE_INVALID_PREFIX);
}
+ bool is_same_party_valid = IsCookieSamePartyValid(parsed_cookie);
+ if (!is_same_party_valid) {
+ status->AddExclusionReason(
+ CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY);
+ }
+
bool partition_has_nonce = CookiePartitionKey::HasNonce(cookie_partition_key);
bool is_partitioned_valid =
IsCookiePartitionedValid(url, parsed_cookie, partition_has_nonce);
@@ -715,7 +725,8 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::Create(
cookie_expires, creation_time,
/*last_update=*/base::Time::Now(), parsed_cookie.IsSecure(),
parsed_cookie.IsHttpOnly(), samesite, parsed_cookie.Priority(),
- cookie_partition_key, source_scheme, source_port);
+ parsed_cookie.IsSameParty(), cookie_partition_key, source_scheme,
+ source_port);
// TODO(chlily): Log metrics.
if (!cc->IsCanonical()) {
@@ -762,6 +773,7 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::CreateSanitizedCookie(
bool http_only,
CookieSameSite same_site,
CookiePriority priority,
+ bool same_party,
absl::optional<CookiePartitionKey> partition_key,
CookieInclusionStatus* status) {
// Put a pointer on the stack so the rest of the function can assign to it if
@@ -909,6 +921,10 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::CreateSanitizedCookie(
net::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX);
}
+ if (!IsCookieSamePartyValid(same_party, secure, same_site)) {
+ status->AddExclusionReason(
+ net::CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY);
+ }
if (!IsCookiePartitionedValid(url, secure,
/*is_partitioned=*/partition_key.has_value(),
/*partition_has_nonce=*/
@@ -931,7 +947,7 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::CreateSanitizedCookie(
base::PassKey<CanonicalCookie>(), name, value, cookie_domain,
encoded_cookie_path, creation_time, expiration_time, last_access_time,
/*last_update=*/base::Time::Now(), secure, http_only, same_site, priority,
- partition_key, source_scheme, source_port);
+ same_party, partition_key, source_scheme, source_port);
DCHECK(cc->IsCanonical());
return cc;
@@ -951,6 +967,7 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::FromStorage(
bool httponly,
CookieSameSite same_site,
CookiePriority priority,
+ bool same_party,
absl::optional<CookiePartitionKey> partition_key,
CookieSourceScheme source_scheme,
int source_port) {
@@ -965,8 +982,8 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::FromStorage(
auto cc = std::make_unique<CanonicalCookie>(
base::PassKey<CanonicalCookie>(), std::move(name), std::move(value),
std::move(domain), std::move(path), creation, expiration, last_access,
- last_update, secure, httponly, same_site, priority, partition_key,
- source_scheme, validated_port);
+ last_update, secure, httponly, same_site, priority, same_party,
+ partition_key, source_scheme, validated_port);
if (cc->IsCanonicalForFromStorage()) {
// This will help capture the number of times a cookie is canonical but does
@@ -996,13 +1013,14 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::CreateUnsafeCookieForTesting(
bool httponly,
CookieSameSite same_site,
CookiePriority priority,
+ bool same_party,
absl::optional<CookiePartitionKey> partition_key,
CookieSourceScheme source_scheme,
int source_port) {
return std::make_unique<CanonicalCookie>(
base::PassKey<CanonicalCookie>(), name, value, domain, path, creation,
expiration, last_access, last_update, secure, httponly, same_site,
- priority, partition_key, source_scheme, source_port);
+ priority, same_party, partition_key, source_scheme, source_port);
}
bool CanonicalCookie::IsFirstPartyPartitioned() const {
@@ -1252,10 +1270,56 @@ CookieAccessResult CanonicalCookie::IncludeForRequestURL(
CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE);
}
- ApplySameSiteCookieWarningToStatus(SameSite(), effective_same_site,
- IsSecure(),
- options.same_site_cookie_context(),
- &status, false /* is_cookie_being_set */);
+ switch (params.same_party_status) {
+ case CookieSamePartyStatus::kEnforceSamePartyExclude:
+ DCHECK(IsSameParty());
+ status.AddExclusionReason(
+ CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT);
+ [[fallthrough]];
+ case CookieSamePartyStatus::kEnforceSamePartyInclude: {
+ status.AddWarningReason(CookieInclusionStatus::WARN_TREATED_AS_SAMEPARTY);
+ // Remove any SameSite exclusion reasons, since SameParty overrides
+ // SameSite.
+ DCHECK(!status.HasExclusionReason(
+ CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT));
+ DCHECK_NE(effective_same_site, CookieEffectiveSameSite::STRICT_MODE);
+ bool included_by_samesite =
+ !status.HasExclusionReason(
+ CookieInclusionStatus::EXCLUDE_SAMESITE_LAX) &&
+ !status.HasExclusionReason(
+ CookieInclusionStatus::
+ EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX);
+ if (!included_by_samesite) {
+ status.RemoveExclusionReasons({
+ CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
+ CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
+ });
+ }
+
+ // Update metrics.
+ if (status.HasOnlyExclusionReason(
+ CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT) &&
+ included_by_samesite) {
+ status.AddWarningReason(
+ CookieInclusionStatus::WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE);
+ }
+ if (status.IsInclude()) {
+ if (!included_by_samesite) {
+ status.AddWarningReason(
+ CookieInclusionStatus::
+ WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE);
+ }
+ }
+ break;
+ }
+ case CookieSamePartyStatus::kNoSamePartyEnforcement:
+ // Only apply SameSite-related warnings if SameParty is not in effect.
+ ApplySameSiteCookieWarningToStatus(
+ SameSite(), effective_same_site, IsSecure(),
+ options.same_site_cookie_context(), &status,
+ false /* is_cookie_being_set */);
+ break;
+ }
if (status.IsInclude()) {
UMA_HISTOGRAM_ENUMERATION("Cookie.IncludedRequestEffectiveSameSite",
@@ -1425,10 +1489,59 @@ CookieAccessResult CanonicalCookie::IsSetPermittedInContext(
break;
}
- ApplySameSiteCookieWarningToStatus(
- SameSite(), access_result.effective_same_site, IsSecure(),
- options.same_site_cookie_context(), &access_result.status,
- true /* is_cookie_being_set */);
+ switch (params.same_party_status) {
+ case CookieSamePartyStatus::kEnforceSamePartyExclude:
+ DCHECK(IsSameParty());
+ access_result.status.AddExclusionReason(
+ CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT);
+ [[fallthrough]];
+ case CookieSamePartyStatus::kEnforceSamePartyInclude: {
+ DCHECK(IsSameParty());
+ access_result.status.AddWarningReason(
+ CookieInclusionStatus::WARN_TREATED_AS_SAMEPARTY);
+ // Remove any SameSite exclusion reasons, since SameParty overrides
+ // SameSite.
+ DCHECK(!access_result.status.HasExclusionReason(
+ CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT));
+ DCHECK_NE(access_result.effective_same_site,
+ CookieEffectiveSameSite::STRICT_MODE);
+ bool included_by_samesite =
+ !access_result.status.HasExclusionReason(
+ CookieInclusionStatus::EXCLUDE_SAMESITE_LAX) &&
+ !access_result.status.HasExclusionReason(
+ CookieInclusionStatus::
+ EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX);
+ if (!included_by_samesite) {
+ access_result.status.RemoveExclusionReasons({
+ CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
+ CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
+ });
+ }
+
+ // Update metrics.
+ if (access_result.status.HasOnlyExclusionReason(
+ CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT) &&
+ included_by_samesite) {
+ access_result.status.AddWarningReason(
+ CookieInclusionStatus::WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE);
+ }
+ if (access_result.status.IsInclude()) {
+ if (!included_by_samesite) {
+ access_result.status.AddWarningReason(
+ CookieInclusionStatus::
+ WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE);
+ }
+ }
+ break;
+ }
+ case CookieSamePartyStatus::kNoSamePartyEnforcement:
+ // Only apply SameSite-related warnings if SameParty is not in effect.
+ ApplySameSiteCookieWarningToStatus(
+ SameSite(), access_result.effective_same_site, IsSecure(),
+ options.same_site_cookie_context(), &access_result.status,
+ true /* is_cookie_being_set */);
+ break;
+ }
if (access_result.status.IsInclude()) {
UMA_HISTOGRAM_ENUMERATION("Cookie.IncludedResponseEffectiveSameSite",
@@ -1537,6 +1650,9 @@ bool CanonicalCookie::IsCanonicalForFromStorage() const {
if (name_ == "" && HasHiddenPrefixName(value_))
return false;
+ if (!IsCookieSamePartyValid(same_party_, secure_, same_site_))
+ return false;
+
if (IsPartitioned()) {
if (CookiePartitionKey::HasNonce(partition_key_))
return true;
@@ -1783,6 +1899,23 @@ bool CanonicalCookie::IsRecentlyCreated(base::TimeDelta age_threshold) const {
return (base::Time::Now() - creation_date_) <= age_threshold;
}
+// static
+bool CanonicalCookie::IsCookieSamePartyValid(
+ const ParsedCookie& parsed_cookie) {
+ return IsCookieSamePartyValid(parsed_cookie.IsSameParty(),
+ parsed_cookie.IsSecure(),
+ parsed_cookie.SameSite());
+}
+
+// static
+bool CanonicalCookie::IsCookieSamePartyValid(bool is_same_party,
+ bool is_secure,
+ CookieSameSite same_site) {
+ if (!is_same_party)
+ return true;
+ return is_secure && (same_site != CookieSameSite::STRICT_MODE);
+}
+
// static
bool CanonicalCookie::IsCookiePartitionedValid(
const GURL& url,
diff --git a/net/cookies/canonical_cookie.h b/net/cookies/canonical_cookie.h
index 599b17b834e6816f05f029014e2e53cb067a318d..272f70b3a25a2f93bd99b042db423591b03b0e54 100644
--- a/net/cookies/canonical_cookie.h
+++ b/net/cookies/canonical_cookie.h
@@ -43,7 +43,8 @@ using CookieAccessResultList = std::vector<CookieWithAccessResult>;
struct NET_EXPORT CookieAccessParams {
CookieAccessParams() = delete;
CookieAccessParams(CookieAccessSemantics access_semantics,
- bool delegate_treats_url_as_trustworthy);
+ bool delegate_treats_url_as_trustworthy,
+ CookieSamePartyStatus same_party_status);
// |access_semantics| is the access mode of the cookie access check.
CookieAccessSemantics access_semantics = CookieAccessSemantics::UNKNOWN;
@@ -51,6 +52,10 @@ struct NET_EXPORT CookieAccessParams {
// CookieAccessDelegate has authorized access to secure cookies from URLs
// which might not otherwise be able to do so.
bool delegate_treats_url_as_trustworthy = false;
+ // |same_party_status| indicates whether, and how, SameParty restrictions
+ // should be enforced.
+ CookieSamePartyStatus same_party_status =
+ CookieSamePartyStatus::kNoSamePartyEnforcement;
};
class NET_EXPORT CanonicalCookie {
@@ -107,6 +112,7 @@ class NET_EXPORT CanonicalCookie {
bool httponly,
CookieSameSite same_site,
CookiePriority priority,
+ bool same_party,
absl::optional<CookiePartitionKey> partition_key,
CookieSourceScheme scheme_secure = CookieSourceScheme::kUnset,
int source_port = url::PORT_UNSPECIFIED);
@@ -167,6 +173,7 @@ class NET_EXPORT CanonicalCookie {
bool http_only,
CookieSameSite same_site,
CookiePriority priority,
+ bool same_party,
absl::optional<CookiePartitionKey> partition_key,
CookieInclusionStatus* status = nullptr);
@@ -190,6 +197,7 @@ class NET_EXPORT CanonicalCookie {
bool httponly,
CookieSameSite same_site,
CookiePriority priority,
+ bool same_party,
absl::optional<CookiePartitionKey> partition_key,
CookieSourceScheme source_scheme,
int source_port);
@@ -209,6 +217,7 @@ class NET_EXPORT CanonicalCookie {
bool httponly,
CookieSameSite same_site,
CookiePriority priority,
+ bool same_party,
absl::optional<CookiePartitionKey> partition_key = absl::nullopt,
CookieSourceScheme scheme_secure = CookieSourceScheme::kUnset,
int source_port = url::PORT_UNSPECIFIED);
@@ -240,6 +249,7 @@ class NET_EXPORT CanonicalCookie {
bool IsHttpOnly() const { return httponly_; }
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<CookiePartitionKey>& PartitionKey() const {
return partition_key_;
@@ -366,7 +376,7 @@ class NET_EXPORT CanonicalCookie {
last_access_date_ == other.last_access_date_ &&
expiry_date_ == other.expiry_date_ && secure_ == other.secure_ &&
httponly_ == other.httponly_ && same_site_ == other.same_site_ &&
- priority_ == other.priority_ &&
+ priority_ == other.priority_ && same_party_ == other.same_party_ &&
partition_key_ == other.partition_key_ && name_ == other.name_ &&
value_ == other.value_ && domain_ == other.domain_ &&
path_ == other.path_ &&
@@ -380,8 +390,9 @@ class NET_EXPORT CanonicalCookie {
auto f = [](const CanonicalCookie& c) {
return std::tie(c.creation_date_, c.last_access_date_, c.expiry_date_,
c.secure_, c.httponly_, c.same_site_, c.priority_,
- c.partition_key_, c.name_, c.value_, c.domain_, c.path_,
- c.last_update_date_, c.source_scheme_, c.source_port_);
+ c.same_party_, c.partition_key_, c.name_, c.value_,
+ c.domain_, c.path_, c.last_update_date_, c.source_scheme_,
+ c.source_port_);
};
return f(*this) < f(other);
}
@@ -603,6 +614,14 @@ class NET_EXPORT CanonicalCookie {
// Returns whether the cookie was created at most |age_threshold| ago.
bool IsRecentlyCreated(base::TimeDelta age_threshold) const;
+ // Returns true iff the cookie does not violate any rules associated with
+ // creating a cookie with the SameParty attribute. In particular, if a cookie
+ // has SameParty, then it must be Secure and must not be SameSite=Strict.
+ static bool IsCookieSamePartyValid(const ParsedCookie& parsed_cookie);
+ static bool IsCookieSamePartyValid(bool is_same_party,
+ bool is_secure,
+ CookieSameSite same_site);
+
// Returns true iff the cookie is a partitioned cookie with a nonce or that
// does not violate the semantics of the Partitioned attribute:
// - Must have the Secure attribute OR the cookie partition contains a nonce.
@@ -628,6 +647,7 @@ class NET_EXPORT CanonicalCookie {
bool httponly_{false};
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 or without a nonce. If the value is non-null, then the cookie
// will only be delivered when the top-frame site matches the partition key
diff --git a/net/cookies/canonical_cookie_fuzzer.cc b/net/cookies/canonical_cookie_fuzzer.cc
index c2113af5acc47b720e13d9ddf605a1e223bcc420..0df06e5022a675de884ee35e69b5fcd17efa7ca7 100644
--- a/net/cookies/canonical_cookie_fuzzer.cc
+++ b/net/cookies/canonical_cookie_fuzzer.cc
@@ -66,7 +66,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
url, name, value, domain, path, creation, expiration, last_access,
data_provider.ConsumeBool() /* secure */,
data_provider.ConsumeBool() /* httponly */, same_site, priority,
- partition_key);
+ data_provider.ConsumeBool() /* same_party */, partition_key);
if (sanitized_cookie) {
CHECK(sanitized_cookie->IsCanonical());
diff --git a/net/cookies/cookie_access_delegate.cc b/net/cookies/cookie_access_delegate.cc
index 256dd856cce9fb482926f7a0c8bb80676a37e0e7..9811f944fff0a20a1a7b431e214f3578ed30785b 100644
--- a/net/cookies/cookie_access_delegate.cc
+++ b/net/cookies/cookie_access_delegate.cc
@@ -4,7 +4,13 @@
#include "net/cookies/cookie_access_delegate.h"
-class GURL;
+#include <set>
+
+#include "base/functional/callback.h"
+#include "net/base/schemeful_site.h"
+#include "net/cookies/cookie_partition_key.h"
+#include "net/first_party_sets/first_party_set_entry.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace net {
diff --git a/net/cookies/cookie_access_delegate.h b/net/cookies/cookie_access_delegate.h
index 0eec2486fae7b793ee522954cd3c05a1047b2776..ee8e3d0fab27ef7f087194ad8fcfb6f17b042592 100644
--- a/net/cookies/cookie_access_delegate.h
+++ b/net/cookies/cookie_access_delegate.h
@@ -5,6 +5,8 @@
#ifndef NET_COOKIES_COOKIE_ACCESS_DELEGATE_H_
#define NET_COOKIES_COOKIE_ACCESS_DELEGATE_H_
+#include <set>
+
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/functional/callback_forward.h"
@@ -15,7 +17,7 @@
#include "net/cookies/cookie_partition_key.h"
#include "net/first_party_sets/first_party_set_entry.h"
#include "net/first_party_sets/first_party_set_metadata.h"
-#include "net/first_party_sets/first_party_sets_cache_filter.h"
+#include "net/first_party_sets/same_party_context.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
@@ -50,23 +52,21 @@ class NET_EXPORT CookieAccessDelegate {
const GURL& url,
const SiteForCookies& site_for_cookies) const = 0;
- // Calls `callback` with First-Party Sets metadata about `site` and
- // `top_frame_site`, and cache filter info for `site`. Cache filter info is
- // used to determine if the existing HTTP cache entries for `site` are allowed
- // to be accessed.
+ // Calls `callback` with metadata indicating whether `site` is same-party with
+ // `party_context` and `top_frame_site`; and `site`'s owner, if applicable..
+ // If `top_frame_site` is nullptr, then `site` will be checked only against
+ // `party_context`.
//
// This may return a result synchronously, or asynchronously invoke `callback`
// with the result. The callback will be invoked iff the return value is
// nullopt; i.e. a result will be provided via return value or callback, but
// not both, and not neither.
- [[nodiscard]] virtual absl::optional<
- std::pair<FirstPartySetMetadata, FirstPartySetsCacheFilter::MatchInfo>>
+ [[nodiscard]] virtual absl::optional<FirstPartySetMetadata>
ComputeFirstPartySetMetadataMaybeAsync(
const net::SchemefulSite& site,
const net::SchemefulSite* top_frame_site,
- base::OnceCallback<void(FirstPartySetMetadata,
- FirstPartySetsCacheFilter::MatchInfo)> callback)
- const = 0;
+ const std::set<net::SchemefulSite>& party_context,
+ base::OnceCallback<void(FirstPartySetMetadata)> callback) const = 0;
// Returns the entries of a set of sites if the sites are in non-trivial sets.
// If a given site is not in a non-trivial set, the output does not contain a
diff --git a/net/cookies/cookie_constants.h b/net/cookies/cookie_constants.h
index 33dd35c7cc3f4ce03fe359f33afc3f9a3b700476..9d8a2fa9e5255d4dc18fd1e7d5b8bc5e24728a95 100644
--- a/net/cookies/cookie_constants.h
+++ b/net/cookies/cookie_constants.h
@@ -118,6 +118,16 @@ enum class CookieAccessSemantics {
LEGACY,
};
+enum class CookieSamePartyStatus {
+ // Used when there should be no SameParty enforcement (either because the
+ // cookie is not marked SameParty, or the enforcement is irrelevant).
+ kNoSamePartyEnforcement = 0,
+ // Used when SameParty enforcement says to exclude the cookie.
+ kEnforceSamePartyExclude = 1,
+ // Used when SameParty enforcement says to include the cookie.
+ kEnforceSamePartyInclude = 2,
+};
+
// What scheme was used in the setting of a cookie.
// Do not renumber.
enum class CookieSourceScheme {
diff --git a/net/cookies/cookie_inclusion_status.cc b/net/cookies/cookie_inclusion_status.cc
index b6cf92b53dfc6d74933c2bbb2dc068a74cb70f5b..56b4796e11a4b4354d028bae30793f6631e81202 100644
--- a/net/cookies/cookie_inclusion_status.cc
+++ b/net/cookies/cookie_inclusion_status.cc
@@ -259,6 +259,9 @@ std::string CookieInclusionStatus::GetDebugString() const {
{EXCLUDE_DISALLOWED_CHARACTER, "EXCLUDE_DISALLOWED_CHARACTER"},
{EXCLUDE_THIRD_PARTY_PHASEOUT, "EXCLUDE_THIRD_PARTY_PHASEOUT"},
{EXCLUDE_NO_COOKIE_CONTENT, "EXCLUDE_NO_COOKIE_CONTENT"},
+ {EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT,
+ "EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT"},
+ {EXCLUDE_INVALID_SAMEPARTY, "EXCLUDE_INVALID_SAMEPARTY"},
};
static_assert(
std::size(exclusion_reasons) == ExclusionReason::NUM_EXCLUSION_REASONS,
@@ -308,6 +311,11 @@ std::string CookieInclusionStatus::GetDebugString() const {
"WARN_TENTATIVELY_ALLOWING_SECURE_SOURCE_SCHEME"},
{WARN_SHADOWING_DOMAIN, "WARN_SHADOWING_DOMAIN"},
{WARN_THIRD_PARTY_PHASEOUT, "WARN_THIRD_PARTY_PHASEOUT"},
+ {WARN_TREATED_AS_SAMEPARTY, "WARN_TREATED_AS_SAMEPARTY"},
+ {WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE,
+ "WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE"},
+ {WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE,
+ "WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE"},
};
static_assert(
std::size(warning_reasons) == WarningReason::NUM_WARNING_REASONS,
diff --git a/net/cookies/cookie_inclusion_status.h b/net/cookies/cookie_inclusion_status.h
index 98d8012e544a537da8f0bd51a03bcda230178d78..f95ce28aab5335e4351d3438add73e40d78670c8 100644
--- a/net/cookies/cookie_inclusion_status.h
+++ b/net/cookies/cookie_inclusion_status.h
@@ -78,7 +78,8 @@ class NET_EXPORT CookieInclusionStatus {
// Cookie was set with an invalid __Host- or __Secure- prefix.
EXCLUDE_INVALID_PREFIX = 15,
/// Cookie was set with an invalid Partitioned attribute, which is only
- // valid if the cookie has a __Host- prefix.
+ // valid if the cookie has a __Host- prefix and does not have the SameParty
+ // attribute.
EXCLUDE_INVALID_PARTITIONED = 16,
// Cookie exceeded the name/value pair size limit.
EXCLUDE_NAME_VALUE_PAIR_EXCEEDS_MAX_SIZE = 17,
@@ -108,6 +109,12 @@ class NET_EXPORT CookieInclusionStatus {
EXCLUDE_THIRD_PARTY_PHASEOUT = 25,
// Cookie contains no content or only whitespace.
EXCLUDE_NO_COOKIE_CONTENT = 26,
+ // The cookie specified SameParty, but was used in a cross-party context.
+ EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT = 27,
+ // Cookie was set with an invalid SameParty attribute in combination with
+ // other attributes. (SameParty is invalid if Secure is not present, or if
+ // SameSite=Strict is present.)
+ EXCLUDE_INVALID_SAMEPARTY = 28,
// This should be kept last.
NUM_EXCLUSION_REASONS
@@ -227,6 +234,24 @@ class NET_EXPORT CookieInclusionStatus {
// This cookie will be blocked for third-party cookie phaseout.
WARN_THIRD_PARTY_PHASEOUT = 16,
+ // The cookie was treated as SameParty. This is different from looking at
+ // whether the cookie has the SameParty attribute, since we may choose to
+ // ignore that attribute for one reason or another. E.g., we ignore the
+ // SameParty attribute if the site is not a member of a nontrivial
+ // First-Party Set.
+ WARN_TREATED_AS_SAMEPARTY = 17,
+
+ // The cookie was excluded solely for SameParty reasons (i.e. it was in
+ // cross-party context), but would have been included by SameSite. (This can
+ // only occur in cross-party, cross-site contexts, for cookies that are
+ // 'SameParty; SameSite=None'.)
+ WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE = 18,
+
+ // The cookie was included due to SameParty, even though it would have been
+ // excluded by SameSite. (This can only occur in same-party, cross-site
+ // contexts, for cookies that are 'SameParty; SameSite=Lax'.)
+ WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE = 19,
+
// This should be kept last.
NUM_WARNING_REASONS
};
@@ -378,7 +403,9 @@ class NET_EXPORT CookieInclusionStatus {
// Returns true if the cookie was excluded because of user preferences.
// HasOnlyExclusionReason(EXCLUDE_USER_PREFERENCES) will not return true for
- // third-party cookies blocked in sites in the same First-Party Set. See
+ // third-party cookies blocked in sites in the same First-Party Set (note:
+ // this is not the same as the cookie being blocked in a same-party context,
+ // which takes the entire ancestor chain into account). See
// https://crbug.com/1366868.
bool ExcludedByUserPreferences() const;
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index 643279afbb341f792832086c73ee2a231170ffa1..f88a61ac69e24d553ad6220a9ba3f76fde40cd41 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -377,7 +377,9 @@ CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
base::TimeDelta last_access_threshold,
NetLog* net_log)
- : change_dispatcher_(this),
+ : same_party_attribute_enabled_(base::FeatureList::IsEnabled(
+ net::features::kSamePartyAttributeEnabled)),
+ change_dispatcher_(this, same_party_attribute_enabled_),
net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::COOKIE_STORE)),
store_(std::move(store)),
last_access_threshold_(last_access_threshold),
@@ -739,9 +741,13 @@ bool CookieMonster::MatchCookieDeletionInfo(
delete_info.url.value());
}
+ // Deletion uses all inclusive options, so it's ok to get the
+ // `CookieSamePartyStatus` wrong here.
return delete_info.Matches(
- cookie, CookieAccessParams{GetAccessSemanticsForCookie(cookie),
- delegate_treats_url_as_trustworthy});
+ cookie,
+ CookieAccessParams{GetAccessSemanticsForCookie(cookie),
+ delegate_treats_url_as_trustworthy,
+ CookieSamePartyStatus::kNoSamePartyEnforcement});
}
void CookieMonster::DeleteCanonicalCookie(const CanonicalCookie& cookie,
@@ -1283,8 +1289,11 @@ void CookieMonster::FilterCookiesWithOptions(
// cookie |options|.
CookieAccessResult access_result = cookie_ptr->IncludeForRequestURL(
url, options,
- CookieAccessParams{GetAccessSemanticsForCookie(*cookie_ptr),
- delegate_treats_url_as_trustworthy});
+ CookieAccessParams{
+ GetAccessSemanticsForCookie(*cookie_ptr),
+ delegate_treats_url_as_trustworthy,
+ cookie_util::GetSamePartyStatus(*cookie_ptr, options,
+ same_party_attribute_enabled_)});
cookies_and_access_results.emplace_back(cookie_ptr, access_result);
// Record the names of all origin cookies that would be included if both
@@ -1629,7 +1638,9 @@ void CookieMonster::SetCanonicalCookie(
CookieAccessResult access_result = cc->IsSetPermittedInContext(
source_url, options,
CookieAccessParams(GetAccessSemanticsForCookie(*cc),
- delegate_treats_url_as_trustworthy),
+ delegate_treats_url_as_trustworthy,
+ cookie_util::GetSamePartyStatus(
+ *cc, options, same_party_attribute_enabled_)),
cookieable_schemes_, cookie_access_result);
const std::string key(GetKey(cc->Domain()));
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
index 6871ed30edce4645a913d36c61a3e75ef84aae65..bf4a25a85bc51167d99897848959b1dbc117e941 100644
--- a/net/cookies/cookie_monster.h
+++ b/net/cookies/cookie_monster.h
@@ -746,6 +746,8 @@ class NET_EXPORT CookieMonster : public CookieStore {
// Cookie jar sizes per partition.
std::map<CookiePartitionKey, size_t> bytes_per_cookie_partition_;
+ bool same_party_attribute_enabled_ = false;
+
CookieMonsterChangeDispatcher change_dispatcher_;
// Indicates whether the cookie store has been initialized.
diff --git a/net/cookies/cookie_monster_change_dispatcher.cc b/net/cookies/cookie_monster_change_dispatcher.cc
index 61bd41e5a273e9d8d467deb587794600257feae6..34448cfee892b93558016c4fba22123c9522f6c4 100644
--- a/net/cookies/cookie_monster_change_dispatcher.cc
+++ b/net/cookies/cookie_monster_change_dispatcher.cc
@@ -37,6 +37,7 @@ CookieMonsterChangeDispatcher::Subscription::Subscription(
std::string name_key,
GURL url,
CookiePartitionKeyCollection cookie_partition_key_collection,
+ bool same_party_attribute_enabled,
net::CookieChangeCallback callback)
: change_dispatcher_(std::move(change_dispatcher)),
domain_key_(std::move(domain_key)),
@@ -45,6 +46,7 @@ CookieMonsterChangeDispatcher::Subscription::Subscription(
cookie_partition_key_collection_(
std::move(cookie_partition_key_collection)),
callback_(std::move(callback)),
+ same_party_attribute_enabled_(same_party_attribute_enabled),
task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()) {
DCHECK(url_.is_valid() || url_.is_empty());
DCHECK_EQ(url_.is_empty(), domain_key_ == kGlobalDomainKey);
@@ -73,11 +75,14 @@ void CookieMonsterChangeDispatcher::Subscription::DispatchChange(
cookie_access_delegate &&
cookie_access_delegate->ShouldTreatUrlAsTrustworthy(url_);
CookieOptions options = CookieOptions::MakeAllInclusive();
+ CookieSamePartyStatus same_party_status = cookie_util::GetSamePartyStatus(
+ cookie, options, same_party_attribute_enabled_);
if (!cookie
.IncludeForRequestURL(
url_, options,
CookieAccessParams{change.access_result.access_semantics,
- delegate_treats_url_as_trustworthy})
+ delegate_treats_url_as_trustworthy,
+ same_party_status})
.status.IsInclude()) {
return;
}
@@ -111,8 +116,10 @@ void CookieMonsterChangeDispatcher::Subscription::DoDispatchChange(
}
CookieMonsterChangeDispatcher::CookieMonsterChangeDispatcher(
- const CookieMonster* cookie_monster)
- : cookie_monster_(cookie_monster) {}
+ const CookieMonster* cookie_monster,
+ bool same_party_attribute_enabled)
+ : cookie_monster_(cookie_monster),
+ same_party_attribute_enabled_(same_party_attribute_enabled) {}
CookieMonsterChangeDispatcher::~CookieMonsterChangeDispatcher() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -154,7 +161,7 @@ CookieMonsterChangeDispatcher::AddCallbackForCookie(
std::unique_ptr<Subscription> subscription = std::make_unique<Subscription>(
weak_ptr_factory_.GetWeakPtr(), DomainKey(url), NameKey(name), url,
CookiePartitionKeyCollection::FromOptional(cookie_partition_key),
- std::move(callback));
+ same_party_attribute_enabled_, std::move(callback));
LinkSubscription(subscription.get());
return subscription;
@@ -171,7 +178,7 @@ CookieMonsterChangeDispatcher::AddCallbackForUrl(
weak_ptr_factory_.GetWeakPtr(), DomainKey(url),
std::string(kGlobalNameKey), url,
CookiePartitionKeyCollection::FromOptional(cookie_partition_key),
- std::move(callback));
+ same_party_attribute_enabled_, std::move(callback));
LinkSubscription(subscription.get());
return subscription;
@@ -185,7 +192,8 @@ CookieMonsterChangeDispatcher::AddCallbackForAllChanges(
std::unique_ptr<Subscription> subscription = std::make_unique<Subscription>(
weak_ptr_factory_.GetWeakPtr(), std::string(kGlobalDomainKey),
std::string(kGlobalNameKey), GURL(""),
- CookiePartitionKeyCollection::ContainsAll(), std::move(callback));
+ CookiePartitionKeyCollection::ContainsAll(),
+ same_party_attribute_enabled_, std::move(callback));
LinkSubscription(subscription.get());
return subscription;
diff --git a/net/cookies/cookie_monster_change_dispatcher.h b/net/cookies/cookie_monster_change_dispatcher.h
index d6f449140b0244263b0c248e9163eb9940407541..31ca1e979ce1133dd6a78a7d8d09a6aba8f0ee44 100644
--- a/net/cookies/cookie_monster_change_dispatcher.h
+++ b/net/cookies/cookie_monster_change_dispatcher.h
@@ -33,7 +33,8 @@ class CookieMonsterChangeDispatcher : public CookieChangeDispatcher {
base::RepeatingCallbackList<void(const CookieChangeInfo&)>;
// Expects |cookie_monster| to outlive this.
- explicit CookieMonsterChangeDispatcher(const CookieMonster* cookie_monster);
+ CookieMonsterChangeDispatcher(const CookieMonster* cookie_monster,
+ bool same_party_attribute_enabled);
CookieMonsterChangeDispatcher(const CookieMonsterChangeDispatcher&) = delete;
CookieMonsterChangeDispatcher& operator=(
@@ -78,6 +79,7 @@ class CookieMonsterChangeDispatcher : public CookieChangeDispatcher {
std::string name_key,
GURL url,
CookiePartitionKeyCollection cookie_partition_key_collection,
+ bool same_party_attribute_enabled,
net::CookieChangeCallback callback);
Subscription(const Subscription&) = delete;
@@ -105,6 +107,7 @@ class CookieMonsterChangeDispatcher : public CookieChangeDispatcher {
const GURL url_; // empty() means no URL-based filtering.
const CookiePartitionKeyCollection cookie_partition_key_collection_;
const net::CookieChangeCallback callback_;
+ bool same_party_attribute_enabled_;
void DoDispatchChange(const CookieChangeInfo& change) const;
@@ -154,6 +157,8 @@ class CookieMonsterChangeDispatcher : public CookieChangeDispatcher {
CookieDomainMap cookie_domain_map_;
+ const bool same_party_attribute_enabled_;
+
THREAD_CHECKER(thread_checker_);
// Vends weak pointers to subscriptions.
diff --git a/net/cookies/cookie_monster_netlog_params.cc b/net/cookies/cookie_monster_netlog_params.cc
index 667920356812c6675ae2ce4f83ab0ecf85df0abe..7f766060610af6056480ec241b6a4f03d4fb0be2 100644
--- a/net/cookies/cookie_monster_netlog_params.cc
+++ b/net/cookies/cookie_monster_netlog_params.cc
@@ -33,6 +33,7 @@ base::Value::Dict NetLogCookieMonsterCookieAdded(
dict.Set("same_site", CookieSameSiteToString(cookie->SameSite()));
dict.Set("is_persistent", cookie->IsPersistent());
dict.Set("sync_requested", sync_requested);
+ dict.Set("same_party", cookie->IsSameParty());
return dict;
}
diff --git a/net/cookies/cookie_options.cc b/net/cookies/cookie_options.cc
index d3e96410b39057e3a8d20078d69cbd728f7c8bde..42eb151094e5b26671ea576bf402f8a877e862a3 100644
--- a/net/cookies/cookie_options.cc
+++ b/net/cookies/cookie_options.cc
@@ -8,7 +8,9 @@
#include <tuple>
+#include "base/metrics/histogram_functions.h"
#include "net/cookies/cookie_util.h"
+#include "net/first_party_sets/same_party_context.h"
namespace net {
@@ -99,6 +101,8 @@ CookieOptions CookieOptions::MakeAllInclusive() {
options.set_include_httponly();
options.set_same_site_cookie_context(SameSiteCookieContext::MakeInclusive());
options.set_do_not_update_access_time();
+ options.set_same_party_context(SamePartyContext::MakeInclusive());
+ options.set_is_in_nontrivial_first_party_set(true);
return options;
}
diff --git a/net/cookies/cookie_options.h b/net/cookies/cookie_options.h
index b240265067e9ee72f8f15092a5fb63aed9c0d563..fc7cddad43a74945d5af6c2100893720f3895734 100644
--- a/net/cookies/cookie_options.h
+++ b/net/cookies/cookie_options.h
@@ -10,8 +10,11 @@
#include <ostream>
#include <string>
-#include "base/check_op.h"
#include "net/base/net_export.h"
+#include "net/cookies/cookie_constants.h"
+#include "net/cookies/cookie_inclusion_status.h"
+#include "net/first_party_sets/same_party_context.h"
+#include "url/gurl.h"
namespace net {
@@ -228,12 +231,14 @@ class NET_EXPORT CookieOptions {
// * Excludes SameSite cookies
// * Updates last-accessed time.
// * Does not report excluded cookies in APIs that can do so.
+ // * Excludes SameParty cookies.
//
// These settings can be altered by calling:
//
// * |set_{include,exclude}_httponly()|
// * |set_same_site_cookie_context()|
// * |set_do_not_update_access_time()|
+ // * |set_same_party_cookie_context_type()|
CookieOptions();
CookieOptions(const CookieOptions& other);
CookieOptions(CookieOptions&& other);
@@ -264,6 +269,26 @@ class NET_EXPORT CookieOptions {
void unset_return_excluded_cookies() { return_excluded_cookies_ = false; }
bool return_excluded_cookies() const { return return_excluded_cookies_; }
+ void set_same_party_context(const SamePartyContext& context) {
+ same_party_context_ = context;
+ }
+ const SamePartyContext& same_party_context() const {
+ return same_party_context_;
+ }
+
+ // Getter/setter of |full_party_context_size_| for logging purposes.
+ void set_full_party_context_size(uint32_t len) {
+ full_party_context_size_ = len;
+ }
+ uint32_t full_party_context_size() const { return full_party_context_size_; }
+
+ void set_is_in_nontrivial_first_party_set(bool is_member) {
+ is_in_nontrivial_first_party_set_ = is_member;
+ }
+ bool is_in_nontrivial_first_party_set() const {
+ return is_in_nontrivial_first_party_set_;
+ }
+
// Convenience method for where you need a CookieOptions that will
// work for getting/setting all types of cookies, including HttpOnly and
// SameSite cookies. Also specifies not to update the access time, because
@@ -279,6 +304,19 @@ class NET_EXPORT CookieOptions {
SameSiteCookieContext same_site_cookie_context_;
bool update_access_time_ = true;
bool return_excluded_cookies_ = false;
+
+ SamePartyContext same_party_context_;
+
+ // The size of the isolation_info.party_context plus the top-frame site.
+ // Stored for logging purposes.
+ uint32_t full_party_context_size_ = 0;
+ // Whether the site requesting cookie access (as opposed to e.g. the
+ // `site_for_cookies`) is a member (or owner) of a nontrivial First-Party
+ // Set.
+ // This is included here temporarily, for the purpose of ignoring SameParty
+ // for sites that are not participating in the Origin Trial.
+ // TODO(https://crbug.com/1163990): remove this field.
+ bool is_in_nontrivial_first_party_set_ = false;
};
NET_EXPORT bool operator==(
diff --git a/net/cookies/cookie_util.cc b/net/cookies/cookie_util.cc
index db5099ac3dd70410a4bb266cd078a06b1818ab20..d02ec0664fedc634b17afd857645fdf59e31b21a 100644
--- a/net/cookies/cookie_util.cc
+++ b/net/cookies/cookie_util.cc
@@ -32,7 +32,7 @@
#include "net/cookies/cookie_monster.h"
#include "net/cookies/cookie_options.h"
#include "net/first_party_sets/first_party_set_metadata.h"
-#include "net/first_party_sets/first_party_sets_cache_filter.h"
+#include "net/first_party_sets/same_party_context.h"
#include "net/http/http_util.h"
#include "url/gurl.h"
#include "url/url_constants.h"
@@ -899,24 +899,23 @@ bool IsSchemefulSameSiteEnabled() {
return base::FeatureList::IsEnabled(features::kSchemefulSameSite);
}
-absl::optional<
- std::pair<FirstPartySetMetadata, FirstPartySetsCacheFilter::MatchInfo>>
-ComputeFirstPartySetMetadataMaybeAsync(
+absl::optional<FirstPartySetMetadata> ComputeFirstPartySetMetadataMaybeAsync(
const SchemefulSite& request_site,
const IsolationInfo& isolation_info,
const CookieAccessDelegate* cookie_access_delegate,
- base::OnceCallback<void(FirstPartySetMetadata,
- FirstPartySetsCacheFilter::MatchInfo)> callback) {
- if (cookie_access_delegate) {
+ bool force_ignore_top_frame_party,
+ base::OnceCallback<void(FirstPartySetMetadata)> callback) {
+ if (isolation_info.party_context().has_value() && cookie_access_delegate) {
return cookie_access_delegate->ComputeFirstPartySetMetadataMaybeAsync(
request_site,
- base::OptionalToPtr(
- isolation_info.network_isolation_key().GetTopFrameSite()),
- std::move(callback));
+ force_ignore_top_frame_party
+ ? nullptr
+ : base::OptionalToPtr(
+ isolation_info.network_isolation_key().GetTopFrameSite()),
+ isolation_info.party_context().value(), std::move(callback));
}
- return std::make_pair(FirstPartySetMetadata(),
- FirstPartySetsCacheFilter::MatchInfo());
+ return FirstPartySetMetadata();
}
CookieOptions::SameSiteCookieContext::ContextMetadata::HttpMethod
@@ -945,6 +944,23 @@ HttpMethodStringToEnum(const std::string& in) {
return HttpMethod::kUnknown;
}
+CookieSamePartyStatus GetSamePartyStatus(
+ const CanonicalCookie& cookie,
+ const CookieOptions& options,
+ const bool same_party_attribute_enabled) {
+ if (!same_party_attribute_enabled || !cookie.IsSameParty() ||
+ !options.is_in_nontrivial_first_party_set()) {
+ return CookieSamePartyStatus::kNoSamePartyEnforcement;
+ }
+
+ switch (options.same_party_context().context_type()) {
+ case SamePartyContext::Type::kCrossParty:
+ return CookieSamePartyStatus::kEnforceSamePartyExclude;
+ case SamePartyContext::Type::kSameParty:
+ return CookieSamePartyStatus::kEnforceSamePartyInclude;
+ };
+}
+
bool IsCookieAccessResultInclude(CookieAccessResult cookie_access_result) {
return cookie_access_result.status.IsInclude();
}
diff --git a/net/cookies/cookie_util.h b/net/cookies/cookie_util.h
index 096ddb1b3c0c6c73ee0f918d9124813814dc7abf..e170851338dd98015392cb3212824c70054028e5 100644
--- a/net/cookies/cookie_util.h
+++ b/net/cookies/cookie_util.h
@@ -17,7 +17,6 @@
#include "net/cookies/cookie_options.h"
#include "net/cookies/site_for_cookies.h"
#include "net/first_party_sets/first_party_set_metadata.h"
-#include "net/first_party_sets/first_party_sets_cache_filter.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/origin.h"
@@ -291,27 +290,37 @@ NET_EXPORT bool IsTimeLimitedInsecureCookiesEnabled();
// Returns whether the respective feature is enabled.
NET_EXPORT bool IsSchemefulSameSiteEnabled();
-// Computes the First-Party Sets metadata and cache match information.
-// `isolation_info` must be fully populated.
+// Computes the First-Party Sets metadata, determining which of the cookies for
+// `request_site` can be accessed. `isolation_info` must be fully populated. If
+// `force_ignore_top_frame_party` is true, the top frame from `isolation_info`
+// will be assumed to be same-party with `request_site`, regardless of what it
+// is.
//
// The result may be returned synchronously, or `callback` may be invoked
// asynchronously with the result. The callback will be invoked iff the return
// value is nullopt; i.e. a result will be provided via return value or
// callback, but not both, and not neither.
-[[nodiscard]] NET_EXPORT absl::optional<
- std::pair<FirstPartySetMetadata, FirstPartySetsCacheFilter::MatchInfo>>
+[[nodiscard]] NET_EXPORT absl::optional<FirstPartySetMetadata>
ComputeFirstPartySetMetadataMaybeAsync(
const SchemefulSite& request_site,
const IsolationInfo& isolation_info,
const CookieAccessDelegate* cookie_access_delegate,
- base::OnceCallback<void(FirstPartySetMetadata,
- FirstPartySetsCacheFilter::MatchInfo)> callback);
+ bool force_ignore_top_frame_party,
+ base::OnceCallback<void(FirstPartySetMetadata)> callback);
// Converts a string representing the http request method to its enum
// representation.
NET_EXPORT CookieOptions::SameSiteCookieContext::ContextMetadata::HttpMethod
HttpMethodStringToEnum(const std::string& in);
+// Get the SameParty inclusion status. If the cookie is not SameParty, returns
+// kNoSamePartyEnforcement; if the cookie is SameParty but does not have a
+// valid context, returns kEnforceSamePartyExclude.
+NET_EXPORT CookieSamePartyStatus
+GetSamePartyStatus(const CanonicalCookie& cookie,
+ const CookieOptions& options,
+ bool same_party_attribute_enabled);
+
// Takes a CookieAccessResult and returns a bool, returning true if the
// CookieInclusionStatus in CookieAccessResult was set to "include", else
// returning false.
diff --git a/net/cookies/parse_cookie_line_fuzzer.cc b/net/cookies/parse_cookie_line_fuzzer.cc
index ebc3fc7278667217816fd24993b3edc5579e2454..736311afbe8a06a87a4d2b0207dbdcbfc03c2ca4 100644
--- a/net/cookies/parse_cookie_line_fuzzer.cc
+++ b/net/cookies/parse_cookie_line_fuzzer.cc
@@ -36,7 +36,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Call zero or one of ParsedCookie's mutator methods. Should not call
// anything other than SetName/SetValue when !IsValid().
- const uint8_t action = data_provider.ConsumeIntegralInRange(0, 11);
+ const uint8_t action = data_provider.ConsumeIntegralInRange(0, 12);
switch (action) {
case 1:
parsed_cookie.SetName(GetArbitraryNameValueString(&data_provider));
@@ -80,6 +80,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
GetArbitraryAttributeValueString(&data_provider));
break;
case 11:
+ parsed_cookie.SetIsSameParty(data_provider.ConsumeBool());
+ break;
+ case 12:
parsed_cookie.SetIsPartitioned(data_provider.ConsumeBool());
break;
}
diff --git a/net/cookies/parsed_cookie.cc b/net/cookies/parsed_cookie.cc
index 24b36dd569a325e20354ce90d07035c2f112864c..8998acd3e25ac39013c835fb046f37e6d9fa007d 100644
--- a/net/cookies/parsed_cookie.cc
+++ b/net/cookies/parsed_cookie.cc
@@ -63,6 +63,7 @@ const char kSecureTokenName[] = "secure";
const char kHttpOnlyTokenName[] = "httponly";
const char kSameSiteTokenName[] = "samesite";
const char kPriorityTokenName[] = "priority";
+const char kSamePartyTokenName[] = "sameparty";
const char kPartitionedTokenName[] = "partitioned";
const char kTerminator[] = "\n\r\0";
@@ -270,6 +271,10 @@ bool ParsedCookie::SetPriority(const std::string& priority) {
return SetString(&priority_index_, kPriorityTokenName, priority);
}
+bool ParsedCookie::SetIsSameParty(bool is_same_party) {
+ return SetBool(&same_party_index_, kSamePartyTokenName, is_same_party);
+}
+
bool ParsedCookie::SetIsPartitioned(bool is_partitioned) {
return SetBool(&partitioned_index_, kPartitionedTokenName, is_partitioned);
}
@@ -285,6 +290,7 @@ std::string ParsedCookie::ToCookieLine() const {
// we need to consider whether the name component is a special token.
if (it == pairs_.begin() ||
(it->first != kSecureTokenName && it->first != kHttpOnlyTokenName &&
+ it->first != kSamePartyTokenName &&
it->first != kPartitionedTokenName)) {
out.append("=");
out.append(it->second);
@@ -668,6 +674,8 @@ void ParsedCookie::SetupAttributes() {
same_site_index_ = i;
} else if (pairs_[i].first == kPriorityTokenName) {
priority_index_ = i;
+ } else if (pairs_[i].first == kSamePartyTokenName) {
+ same_party_index_ = i;
} else if (pairs_[i].first == kPartitionedTokenName) {
partitioned_index_ = i;
} else {
@@ -741,10 +749,10 @@ void ParsedCookie::ClearAttributePair(size_t index) {
if (index == 0)
return;
- size_t* indexes[] = {
- &path_index_, &domain_index_, &expires_index_,
- &maxage_index_, &secure_index_, &httponly_index_,
- &same_site_index_, &priority_index_, &partitioned_index_};
+ size_t* indexes[] = {&path_index_, &domain_index_, &expires_index_,
+ &maxage_index_, &secure_index_, &httponly_index_,
+ &same_site_index_, &priority_index_, &same_party_index_,
+ &partitioned_index_};
for (size_t* attribute_index : indexes) {
if (*attribute_index == index)
*attribute_index = 0;
diff --git a/net/cookies/parsed_cookie.h b/net/cookies/parsed_cookie.h
index ed84c8fc4328b5c96b84b40d3a56974cecb64c42..3fe624444cdf28a180cffce920dd3fd8057e368c 100644
--- a/net/cookies/parsed_cookie.h
+++ b/net/cookies/parsed_cookie.h
@@ -85,6 +85,7 @@ class NET_EXPORT ParsedCookie {
CookieSameSite SameSite(
CookieSameSiteString* samesite_string = nullptr) const;
CookiePriority Priority() const;
+ bool IsSameParty() const { return same_party_index_ != 0; }
bool IsPartitioned() const { return partitioned_index_ != 0; }
bool HasInternalHtab() const { return internal_htab_; }
TruncatingCharacterInCookieStringType
@@ -115,6 +116,7 @@ class NET_EXPORT ParsedCookie {
bool SetIsHttpOnly(bool is_http_only);
bool SetSameSite(const std::string& same_site);
bool SetPriority(const std::string& priority);
+ bool SetIsSameParty(bool is_same_party);
bool SetIsPartitioned(bool is_partitioned);
// Returns the cookie description as it appears in a HTML response header.
@@ -211,6 +213,7 @@ class NET_EXPORT ParsedCookie {
size_t httponly_index_ = 0;
size_t same_site_index_ = 0;
size_t priority_index_ = 0;
+ size_t same_party_index_ = 0;
size_t partitioned_index_ = 0;
TruncatingCharacterInCookieStringType truncating_char_in_cookie_string_type_ =
TruncatingCharacterInCookieStringType::kTruncatingCharNone;
diff --git a/net/extras/sqlite/sqlite_persistent_cookie_store.cc b/net/extras/sqlite/sqlite_persistent_cookie_store.cc
index 0adc6857266535320dedbeee8881f50b14d213f1..920bac177582797f2f819e9f93f2a1d07e7d18a0 100644
--- a/net/extras/sqlite/sqlite_persistent_cookie_store.cc
+++ b/net/extras/sqlite/sqlite_persistent_cookie_store.cc
@@ -228,8 +228,8 @@ namespace {
// Version 3 updated the database to include the last access time, so we can
// expire them in decreasing order of use when we've reached the maximum
// number of cookies.
-const int kCurrentVersionNumber = 21;
-const int kCompatibleVersionNumber = 21;
+const int kCurrentVersionNumber = 20;
+const int kCompatibleVersionNumber = 20;
} // namespace
@@ -685,45 +685,6 @@ bool CreateV20Schema(sql::Database* db) {
return true;
}
-bool CreateV21Schema(sql::Database* db) {
- CHECK(!db->DoesTableExist("cookies"));
-
- const char* kCreateTableQuery =
- "CREATE TABLE cookies("
- "creation_utc INTEGER NOT NULL,"
- "host_key TEXT NOT NULL,"
- "top_frame_site_key TEXT NOT NULL,"
- "name TEXT NOT NULL,"
- "value TEXT NOT NULL,"
- "encrypted_value BLOB NOT NULL,"
- "path TEXT NOT NULL,"
- "expires_utc INTEGER NOT NULL,"
- "is_secure INTEGER NOT NULL,"
- "is_httponly INTEGER NOT NULL,"
- "last_access_utc INTEGER NOT NULL,"
- "has_expires INTEGER NOT NULL,"
- "is_persistent INTEGER NOT NULL,"
- "priority INTEGER NOT NULL,"
- "samesite INTEGER NOT NULL,"
- "source_scheme INTEGER NOT NULL,"
- "source_port INTEGER NOT NULL,"
- "last_update_utc INTEGER NOT NULL);";
-
- const char* kCreateIndexQuery =
- "CREATE UNIQUE INDEX cookies_unique_index "
- "ON cookies(host_key, top_frame_site_key, name, path, source_scheme, "
- "source_port)";
-
- if (!db->Execute(kCreateTableQuery)) {
- return false;
- }
- if (!db->Execute(kCreateIndexQuery)) {
- return false;
- }
-
- return true;
-}
-
} // namespace
void SQLitePersistentCookieStore::Backend::Load(
@@ -796,7 +757,7 @@ bool SQLitePersistentCookieStore::Backend::CreateDatabaseSchema() {
if (db()->DoesTableExist("cookies"))
return true;
- return CreateV21Schema(db());
+ return CreateV20Schema(db());
}
bool SQLitePersistentCookieStore::Backend::DoInitializeDatabase() {
@@ -870,14 +831,14 @@ bool SQLitePersistentCookieStore::Backend::LoadCookiesForDomains(
"SELECT creation_utc, host_key, top_frame_site_key, name, value, path, "
"expires_utc, is_secure, is_httponly, last_access_utc, has_expires, "
"is_persistent, priority, encrypted_value, samesite, source_scheme, "
- "source_port, last_update_utc FROM cookies WHERE host_key = ?"));
+ "source_port, is_same_party, last_update_utc FROM cookies WHERE host_key = ?"));
} else {
smt.Assign(db()->GetCachedStatement(
SQL_FROM_HERE,
"SELECT creation_utc, host_key, top_frame_site_key, name, value, path, "
"expires_utc, is_secure, is_httponly, last_access_utc, has_expires, "
"is_persistent, priority, encrypted_value, samesite, source_scheme, "
- "source_port, last_update_utc FROM cookies WHERE "
+ "source_port, is_same_party, last_update_utc FROM cookies WHERE "
"host_key = ? AND "
"is_persistent = 1"));
}
@@ -984,13 +945,14 @@ bool SQLitePersistentCookieStore::Backend::MakeCookiesFromSQLStatement(
statement.ColumnTime(0), // creation_utc
statement.ColumnTime(6), // expires_utc
statement.ColumnTime(9), // last_access_utc
- statement.ColumnTime(17), // last_update_utc
+ statement.ColumnTime(18), // last_update_utc
statement.ColumnBool(7), // secure
statement.ColumnBool(8), // http_only
DBCookieSameSiteToCookieSameSite(static_cast<DBCookieSameSite>(
statement.ColumnInt(14))), // samesite
DBCookiePriorityToCookiePriority(static_cast<DBCookiePriority>(
statement.ColumnInt(12))), // priority
+ statement.ColumnBool(17), // is_same_party
std::move(cookie_partition_key), // top_frame_site_key
DBToCookieSourceScheme(statement.ColumnInt(15)), // source_scheme
statement.ColumnInt(16)); // source_port
@@ -1225,55 +1187,6 @@ SQLitePersistentCookieStore::Backend::DoMigrateDatabaseSchema() {
}
}
- if (cur_version == 20) {
- SCOPED_UMA_HISTOGRAM_TIMER("Cookie.TimeDatabaseMigrationToV21");
-
- sql::Transaction transaction(db());
- if (!transaction.Begin()) {
- return absl::nullopt;
- }
-
- if (!db()->Execute("DROP TABLE IF EXISTS cookies_old")) {
- return absl::nullopt;
- }
- if (!db()->Execute("ALTER TABLE cookies RENAME TO cookies_old")) {
- return absl::nullopt;
- }
- if (!db()->Execute("DROP INDEX IF EXISTS cookies_unique_index")) {
- return absl::nullopt;
- }
-
- if (!CreateV21Schema(db())) {
- return absl::nullopt;
- }
-
- static constexpr char insert_cookies_sql[] =
- "INSERT OR REPLACE INTO cookies "
- "(creation_utc, host_key, top_frame_site_key, name, value, "
- "encrypted_value, path, expires_utc, is_secure, is_httponly, "
- "last_access_utc, has_expires, is_persistent, priority, samesite, "
- "source_scheme, source_port, last_update_utc) "
- "SELECT creation_utc, host_key, top_frame_site_key, name, value,"
- " encrypted_value, path, expires_utc, is_secure, is_httponly,"
- " last_access_utc, has_expires, is_persistent, priority, "
- " samesite, source_scheme, source_port, last_update_utc "
- "FROM cookies_old ORDER BY creation_utc ASC";
- if (!db()->Execute(insert_cookies_sql)) {
- return absl::nullopt;
- }
- if (!db()->Execute("DROP TABLE cookies_old")) {
- return absl::nullopt;
- }
-
- ++cur_version;
- if (!meta_table()->SetVersionNumber(cur_version) ||
- !meta_table()->SetCompatibleVersionNumber(
- std::min(cur_version, kCompatibleVersionNumber)) ||
- !transaction.Commit()) {
- return absl::nullopt;
- }
- }
-
// Put future migration cases here.
return absl::make_optional(cur_version);
@@ -1375,7 +1288,7 @@ void SQLitePersistentCookieStore::Backend::DoCommit() {
"INSERT INTO cookies (creation_utc, host_key, top_frame_site_key, name, "
"value, encrypted_value, path, expires_utc, is_secure, is_httponly, "
"last_access_utc, has_expires, is_persistent, priority, samesite, "
- "source_scheme, source_port, last_update_utc) "
+ "source_scheme, source_port, is_same_party, last_update_utc) "
"VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
if (!add_statement.is_valid())
return;
@@ -1444,7 +1357,8 @@ void SQLitePersistentCookieStore::Backend::DoCommit() {
14, CookieSameSiteToDBCookieSameSite(po->cc().SameSite()));
add_statement.BindInt(15, static_cast<int>(po->cc().SourceScheme()));
add_statement.BindInt(16, po->cc().SourcePort());
- add_statement.BindTime(17, po->cc().LastUpdateDate());
+ add_statement.BindBool(17, po->cc().IsSameParty());
+ add_statement.BindTime(18, po->cc().LastUpdateDate());
if (!add_statement.Run()) {
DLOG(WARNING) << "Could not add a cookie to the DB.";
RecordCookieCommitProblem(COOKIE_COMMIT_PROBLEM_ADD);
diff --git a/net/first_party_sets/first_party_set_metadata.cc b/net/first_party_sets/first_party_set_metadata.cc
index ba6fc9679184fda286fe32f7dd963b7371f0d8d5..fb2303c5851d547150e7a47266a9a602e6ea9f91 100644
--- a/net/first_party_sets/first_party_set_metadata.cc
+++ b/net/first_party_sets/first_party_set_metadata.cc
@@ -13,9 +13,11 @@ namespace net {
FirstPartySetMetadata::FirstPartySetMetadata() = default;
FirstPartySetMetadata::FirstPartySetMetadata(
+ const SamePartyContext& context,
const FirstPartySetEntry* frame_entry,
const FirstPartySetEntry* top_frame_entry)
- : frame_entry_(base::OptionalFromPtr(frame_entry)),
+ : context_(context),
+ frame_entry_(base::OptionalFromPtr(frame_entry)),
top_frame_entry_(base::OptionalFromPtr(top_frame_entry)) {}
FirstPartySetMetadata::FirstPartySetMetadata(FirstPartySetMetadata&&) = default;
@@ -25,14 +27,18 @@ FirstPartySetMetadata& FirstPartySetMetadata::operator=(
FirstPartySetMetadata::~FirstPartySetMetadata() = default;
bool FirstPartySetMetadata::operator==(
- const FirstPartySetMetadata& other) const = default;
+ const FirstPartySetMetadata& other) const {
+ return std::tie(context_, frame_entry_, top_frame_entry_) ==
+ std::tie(other.context_, other.frame_entry_, other.top_frame_entry_);
+}
bool FirstPartySetMetadata::operator!=(
const FirstPartySetMetadata& other) const = default;
std::ostream& operator<<(std::ostream& os,
const FirstPartySetMetadata& metadata) {
- os << "{" << base::OptionalToPtr(metadata.frame_entry()) << ", "
+ os << "{" << metadata.context() << ", "
+ << base::OptionalToPtr(metadata.frame_entry()) << ", "
<< base::OptionalToPtr(metadata.top_frame_entry()) << "}";
return os;
}
diff --git a/net/first_party_sets/first_party_set_metadata.h b/net/first_party_sets/first_party_set_metadata.h
index b23e52575bc2ae0634075890782eb46716116217..77cf13c75599522be3efda658b8685b21532c41c 100644
--- a/net/first_party_sets/first_party_set_metadata.h
+++ b/net/first_party_sets/first_party_set_metadata.h
@@ -7,6 +7,7 @@
#include "net/base/net_export.h"
#include "net/first_party_sets/first_party_set_entry.h"
+#include "net/first_party_sets/same_party_context.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace net {
@@ -20,7 +21,8 @@ class NET_EXPORT FirstPartySetMetadata {
// `frame_entry` and `top_frame_entry` must live for the duration of the ctor;
// nullptr indicates that there's no First-Party Set that's associated with
// the current frame or the top frame, respectively, in the given context.
- FirstPartySetMetadata(const FirstPartySetEntry* frame_entry,
+ FirstPartySetMetadata(const SamePartyContext& context,
+ const FirstPartySetEntry* frame_entry,
const FirstPartySetEntry* top_frame_entry);
FirstPartySetMetadata(FirstPartySetMetadata&&);
@@ -31,6 +33,10 @@ class NET_EXPORT FirstPartySetMetadata {
bool operator==(const FirstPartySetMetadata& other) const;
bool operator!=(const FirstPartySetMetadata& other) const;
+ const SamePartyContext& context() const { return context_; }
+
+ // Returns a optional<T>& instead of a T* so that operator== can be defined
+ // more easily.
const absl::optional<FirstPartySetEntry>& frame_entry() const {
return frame_entry_;
}
@@ -43,6 +49,7 @@ class NET_EXPORT FirstPartySetMetadata {
bool AreSitesInSameFirstPartySet() const;
private:
+ SamePartyContext context_ = SamePartyContext();
absl::optional<FirstPartySetEntry> frame_entry_ = absl::nullopt;
absl::optional<FirstPartySetEntry> top_frame_entry_ = absl::nullopt;
};
diff --git a/net/first_party_sets/global_first_party_sets.cc b/net/first_party_sets/global_first_party_sets.cc
index c916b0f4e106afdef92b3cd4d95cff3edf4d5594..b4d88f4da90d6b16965449ccc583746c5fe58a08 100644
--- a/net/first_party_sets/global_first_party_sets.cc
+++ b/net/first_party_sets/global_first_party_sets.cc
@@ -19,7 +19,6 @@
#include "net/first_party_sets/first_party_set_entry_override.h"
#include "net/first_party_sets/first_party_set_metadata.h"
#include "net/first_party_sets/first_party_sets_context_config.h"
-#include "net/first_party_sets/local_set_declaration.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace net {
@@ -29,6 +28,13 @@ namespace {
using FlattenedSets = base::flat_map<SchemefulSite, FirstPartySetEntry>;
using SingleSet = base::flat_map<SchemefulSite, FirstPartySetEntry>;
+// Converts WS to HTTP, and WSS to HTTPS.
+SchemefulSite NormalizeScheme(const SchemefulSite& site) {
+ SchemefulSite normalized_site = site;
+ normalized_site.ConvertWebSocketToHttp();
+ return normalized_site;
+}
+
// Converts a list of First-Party Sets from a SingleSet to a FlattenedSet
// representation.
FlattenedSets SetListToFlattenedSets(const std::vector<SingleSet>& set_list) {
@@ -60,6 +66,11 @@ const SchemefulSite& ProjectKey(
return p.first;
}
+SamePartyContext::Type ContextTypeFromBool(bool is_same_party) {
+ return is_same_party ? SamePartyContext::Type::kSameParty
+ : SamePartyContext::Type::kCrossParty;
+}
+
} // namespace
GlobalFirstPartySets::GlobalFirstPartySets() = default;
@@ -76,29 +87,25 @@ GlobalFirstPartySets::GlobalFirstPartySets(
public_sets_version.IsValid()
? std::move(aliases)
: base::flat_map<SchemefulSite, SchemefulSite>(),
- FirstPartySetsContextConfig(),
- base::flat_map<SchemefulSite, SchemefulSite>()) {}
+ FirstPartySetsContextConfig()) {}
GlobalFirstPartySets::GlobalFirstPartySets(
base::Version public_sets_version,
base::flat_map<SchemefulSite, FirstPartySetEntry> entries,
base::flat_map<SchemefulSite, SchemefulSite> aliases,
- FirstPartySetsContextConfig manual_config,
- base::flat_map<SchemefulSite, SchemefulSite> manual_aliases)
+ FirstPartySetsContextConfig manual_config)
: public_sets_version_(std::move(public_sets_version)),
entries_(std::move(entries)),
aliases_(std::move(aliases)),
- manual_config_(std::move(manual_config)),
- manual_aliases_(std::move(manual_aliases)) {
- if (!public_sets_version_.IsValid()) {
+ manual_config_(std::move(manual_config)) {
+ if (public_sets_version_.IsValid()) {
+ CHECK(base::ranges::all_of(aliases_, [&](const auto& pair) {
+ return entries_.contains(pair.second);
+ }));
+ } else {
CHECK(entries_.empty());
CHECK(aliases_.empty());
}
-
- CHECK(base::ranges::all_of(aliases_, [&](const auto& pair) {
- return entries_.contains(pair.second);
- }));
- CHECK(!ContainsSingleton());
}
GlobalFirstPartySets::GlobalFirstPartySets(GlobalFirstPartySets&&) = default;
@@ -107,15 +114,18 @@ GlobalFirstPartySets& GlobalFirstPartySets::operator=(GlobalFirstPartySets&&) =
GlobalFirstPartySets::~GlobalFirstPartySets() = default;
-bool GlobalFirstPartySets::operator==(const GlobalFirstPartySets& other) const =
- default;
+bool GlobalFirstPartySets::operator==(const GlobalFirstPartySets& other) const {
+ return std::tie(public_sets_version_, entries_, aliases_, manual_config_) ==
+ std::tie(other.public_sets_version_, other.entries_, other.aliases_,
+ other.manual_config_);
+}
bool GlobalFirstPartySets::operator!=(const GlobalFirstPartySets& other) const =
default;
GlobalFirstPartySets GlobalFirstPartySets::Clone() const {
return GlobalFirstPartySets(public_sets_version_, entries_, aliases_,
- manual_config_.Clone(), manual_aliases_);
+ manual_config_.Clone());
}
absl::optional<FirstPartySetEntry> GlobalFirstPartySets::FindEntry(
@@ -127,9 +137,11 @@ absl::optional<FirstPartySetEntry> GlobalFirstPartySets::FindEntry(
absl::optional<FirstPartySetEntry> GlobalFirstPartySets::FindEntry(
const SchemefulSite& site,
const FirstPartySetsContextConfig* config) const {
- // Check if `site` can be found in the customizations first.
+ const SchemefulSite normalized_site = NormalizeScheme(site);
+
+ // Check if `normalized_site` can be found in the customizations first.
if (config) {
- if (const auto override = config->FindOverride(site);
+ if (const auto override = config->FindOverride(normalized_site);
override.has_value()) {
return override->IsDeletion() ? absl::nullopt
: absl::make_optional(override->GetEntry());
@@ -137,7 +149,7 @@ absl::optional<FirstPartySetEntry> GlobalFirstPartySets::FindEntry(
}
// Now see if it's in the manual config (with or without a manual alias).
- if (const auto manual_override = manual_config_.FindOverride(site);
+ if (const auto manual_override = manual_config_.FindOverride(normalized_site);
manual_override.has_value()) {
return manual_override->IsDeletion()
? absl::nullopt
@@ -145,9 +157,9 @@ absl::optional<FirstPartySetEntry> GlobalFirstPartySets::FindEntry(
}
// Finally, look up in `entries_`, applying an alias if applicable.
- const auto canonical_it = aliases_.find(site);
+ const auto canonical_it = aliases_.find(normalized_site);
const SchemefulSite& canonical_site =
- canonical_it == aliases_.end() ? site : canonical_it->second;
+ canonical_it == aliases_.end() ? normalized_site : canonical_it->second;
if (const auto entry_it = entries_.find(canonical_site);
entry_it != entries_.end()) {
return entry_it->second;
@@ -173,42 +185,55 @@ GlobalFirstPartySets::FindEntries(
FirstPartySetMetadata GlobalFirstPartySets::ComputeMetadata(
const SchemefulSite& site,
const SchemefulSite* top_frame_site,
+ const std::set<SchemefulSite>& party_context,
const FirstPartySetsContextConfig& fps_context_config) const {
+ SamePartyContext::Type context_type =
+ ContextTypeFromBool(IsContextSamePartyWithSite(
+ site, top_frame_site, party_context, fps_context_config));
+
+ SamePartyContext context(context_type);
+
absl::optional<FirstPartySetEntry> top_frame_entry =
top_frame_site ? FindEntry(*top_frame_site, fps_context_config)
: absl::nullopt;
return FirstPartySetMetadata(
- base::OptionalToPtr(FindEntry(site, fps_context_config)),
+ context, base::OptionalToPtr(FindEntry(site, fps_context_config)),
base::OptionalToPtr(top_frame_entry));
}
-void GlobalFirstPartySets::ApplyManuallySpecifiedSet(
- const LocalSetDeclaration& local_set_declaration) {
- CHECK(manual_config_.empty());
- CHECK(manual_aliases_.empty());
- if (local_set_declaration.empty()) {
- // Nothing to do.
- return;
- }
+bool GlobalFirstPartySets::IsContextSamePartyWithSite(
+ const SchemefulSite& site,
+ const SchemefulSite* top_frame_site,
+ const std::set<SchemefulSite>& party_context,
+ const FirstPartySetsContextConfig& fps_context_config) const {
+ const absl::optional<FirstPartySetEntry> site_entry =
+ FindEntry(site, fps_context_config);
+ if (!site_entry.has_value())
+ return false;
- base::flat_map<SchemefulSite, SchemefulSite> manual_aliases =
- local_set_declaration.aliases();
+ const auto is_in_same_set_as_frame_site =
+ [this, &site_entry,
+ &fps_context_config](const SchemefulSite& context_site) -> bool {
+ const absl::optional<FirstPartySetEntry> context_entry =
+ FindEntry(context_site, fps_context_config);
+ return context_entry.has_value() &&
+ context_entry->primary() == site_entry->primary();
+ };
- base::flat_map<SchemefulSite, FirstPartySetEntry> manual_entries =
- local_set_declaration.entries();
- for (const auto& [alias, canonical] : manual_aliases) {
- manual_entries.emplace(alias, manual_entries.find(canonical)->second);
- }
+ if (top_frame_site && !is_in_same_set_as_frame_site(*top_frame_site))
+ return false;
+ return base::ranges::all_of(party_context, is_in_same_set_as_frame_site);
+}
+
+void GlobalFirstPartySets::ApplyManuallySpecifiedSet(
+ const base::flat_map<SchemefulSite, FirstPartySetEntry>& manual_entries) {
+ CHECK(manual_config_.empty());
// We handle the manually-specified set the same way as we handle
// replacement enterprise policy sets.
- manual_config_ = ComputeConfig(SetsMutation(
- /*replacement_sets=*/{manual_entries},
- /*addition_sets=*/{}));
- manual_aliases_ = std::move(manual_aliases);
-
- CHECK(!ContainsSingleton());
+ manual_config_ = ComputeConfig(
+ /*replacement_sets=*/{manual_entries}, /*addition_sets=*/{});
}
void GlobalFirstPartySets::UnsafeSetManualConfig(
@@ -218,9 +243,8 @@ void GlobalFirstPartySets::UnsafeSetManualConfig(
}
FirstPartySetsContextConfig GlobalFirstPartySets::ComputeConfig(
- const SetsMutation& mutation) const {
- const std::vector<SingleSet>& replacement_sets = mutation.replacements();
- const std::vector<SingleSet>& addition_sets = mutation.additions();
+ const std::vector<SingleSet>& replacement_sets,
+ const std::vector<SingleSet>& addition_sets) const {
if (base::ranges::all_of(replacement_sets,
[](const SingleSet& set) { return set.empty(); }) &&
base::ranges::all_of(addition_sets,
@@ -334,15 +358,14 @@ FirstPartySetsContextConfig GlobalFirstPartySets::ComputeConfig(
}
}
- // For every pre-existing alias that would now refer to a site in the overlay,
- // which is not already contained in the overlay, we explicitly ignore that
- // alias.
- ForEachAlias([&](const SchemefulSite& alias, const SchemefulSite& canonical) {
- if (base::Contains(site_to_entry, canonical, ProjectKey) &&
+ // For every public alias that would now refer to a site in the overlay, which
+ // is not already contained in the overlay, we explicitly ignore that alias.
+ for (const auto& [alias, site] : aliases_) {
+ if (base::Contains(site_to_entry, site, ProjectKey) &&
!base::Contains(site_to_entry, alias, ProjectKey)) {
site_to_entry.emplace_back(alias, FirstPartySetEntryOverride());
}
- });
+ }
return FirstPartySetsContextConfig(std::move(site_to_entry));
}
@@ -466,42 +489,6 @@ bool GlobalFirstPartySets::ForEachEffectiveSetEntry(
});
}
-void GlobalFirstPartySets::ForEachAlias(
- base::FunctionRef<void(const SchemefulSite&, const SchemefulSite&)> f)
- const {
- for (const auto& [alias, site] : manual_aliases_) {
- f(alias, site);
- }
- for (const auto& [alias, site] : aliases_) {
- if (manual_config_.Contains(alias)) {
- continue;
- }
- f(alias, site);
- }
-}
-
-bool GlobalFirstPartySets::ContainsSingleton() const {
- std::set<SchemefulSite> possible_singletons;
- std::set<SchemefulSite> not_singletons;
-
- ForEachEffectiveSetEntry(
- nullptr,
- [&](const SchemefulSite& site, const FirstPartySetEntry& entry) -> bool {
- if (!not_singletons.contains(entry.primary())) {
- if (site == entry.primary()) {
- possible_singletons.insert(entry.primary());
- } else {
- not_singletons.insert(entry.primary());
- possible_singletons.erase(entry.primary());
- }
- }
-
- return true;
- });
-
- return !possible_singletons.empty();
-}
-
std::ostream& operator<<(std::ostream& os, const GlobalFirstPartySets& sets) {
os << "{entries = {";
for (const auto& [site, entry] : sets.entries_) {
@@ -518,10 +505,6 @@ std::ostream& operator<<(std::ostream& os, const GlobalFirstPartySets& sets) {
os << "{" << site.Serialize() << ": " << override << "},";
return true;
});
- os << "}, manual_aliases = {";
- for (const auto& [alias, canonical] : sets.manual_aliases_) {
- os << "{" << alias.Serialize() << ": " << canonical.Serialize() << "}, ";
- }
os << "}}";
return os;
}
diff --git a/net/first_party_sets/global_first_party_sets.h b/net/first_party_sets/global_first_party_sets.h
index d87aaec1747738a29dc03cdfcb9266c48ef8b699..cc2b42c89deb47fda879a5bef2c4a7f9989c139d 100644
--- a/net/first_party_sets/global_first_party_sets.h
+++ b/net/first_party_sets/global_first_party_sets.h
@@ -5,6 +5,8 @@
#ifndef NET_FIRST_PARTY_SETS_GLOBAL_FIRST_PARTY_SETS_H_
#define NET_FIRST_PARTY_SETS_GLOBAL_FIRST_PARTY_SETS_H_
+#include <set>
+
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/functional/function_ref.h"
@@ -14,8 +16,6 @@
#include "net/first_party_sets/first_party_set_entry.h"
#include "net/first_party_sets/first_party_set_entry_override.h"
#include "net/first_party_sets/first_party_sets_context_config.h"
-#include "net/first_party_sets/local_set_declaration.h"
-#include "net/first_party_sets/sets_mutation.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace mojo {
@@ -55,8 +55,15 @@ class NET_EXPORT GlobalFirstPartySets {
GlobalFirstPartySets Clone() const;
// Returns a FirstPartySetsContextConfig that respects the overrides given by
- // `mutation`, relative to this instance's state.
- FirstPartySetsContextConfig ComputeConfig(const SetsMutation& mutation) const;
+ // `replacement_sets` and `addition_sets`, relative to this instance's state.
+ //
+ // Preconditions: sets defined by `replacement_sets` and
+ // `addition_sets` must be disjoint.
+ FirstPartySetsContextConfig ComputeConfig(
+ const std::vector<base::flat_map<SchemefulSite, FirstPartySetEntry>>&
+ replacement_sets,
+ const std::vector<base::flat_map<SchemefulSite, FirstPartySetEntry>>&
+ addition_sets) const;
// Returns the entry corresponding to the given `site`, if one exists.
// Respects any customization/overlay specified by `config`. This is
@@ -76,12 +83,14 @@ class NET_EXPORT GlobalFirstPartySets {
FirstPartySetMetadata ComputeMetadata(
const SchemefulSite& site,
const SchemefulSite* top_frame_site,
+ const std::set<SchemefulSite>& party_context,
const FirstPartySetsContextConfig& fps_context_config) const;
// Modifies this instance such that it will respect the given
- // manually-specified set.
+ // manually-specified set. `manual_entries` should contain entries for aliases
+ // as well as "canonical" sites.
void ApplyManuallySpecifiedSet(
- const LocalSetDeclaration& local_set_declaration);
+ const base::flat_map<SchemefulSite, FirstPartySetEntry>& manual_entries);
// Directly sets this instance's manual config. This is unsafe, because it
// assumes that the config was computed by this instance (or one with
@@ -141,8 +150,7 @@ class NET_EXPORT GlobalFirstPartySets {
base::Version public_sets_version,
base::flat_map<SchemefulSite, FirstPartySetEntry> entries,
base::flat_map<SchemefulSite, SchemefulSite> aliases,
- FirstPartySetsContextConfig manual_config,
- base::flat_map<SchemefulSite, SchemefulSite> manual_aliases);
+ FirstPartySetsContextConfig manual_config);
// Same as the public version of FindEntry, but is allowed to omit the
// `config` argument (i.e. pass nullptr instead of a reference).
@@ -159,6 +167,18 @@ class NET_EXPORT GlobalFirstPartySets {
const std::vector<base::flat_map<SchemefulSite, FirstPartySetEntry>>&
addition_sets) const;
+ // Returns whether `site` is same-party with `party_context`, and
+ // `top_frame_site` (if it is not nullptr). That is, is `site`'s primary the
+ // same as the primaries of every member of `party_context` and of
+ // `top_frame_site`? Note: if `site` is not a member of a First-Party Set,
+ // then this returns false. If `top_frame_site` is nullptr, then it is
+ // ignored.
+ bool IsContextSamePartyWithSite(
+ const SchemefulSite& site,
+ const SchemefulSite* top_frame_site,
+ const std::set<SchemefulSite>& party_context,
+ const FirstPartySetsContextConfig& fps_context_config) const;
+
// Same as the public version of ForEachEffectiveSetEntry, but is allowed to
// omit the `config` argument (i.e. pass nullptr instead of a reference).
bool ForEachEffectiveSetEntry(
@@ -166,16 +186,6 @@ class NET_EXPORT GlobalFirstPartySets {
base::FunctionRef<bool(const SchemefulSite&, const FirstPartySetEntry&)>
f) const;
- // Iterates over the mappings in `manual_aliases_` and `aliases_` (skipping
- // entries of `aliases_` that are shadowed), invoking `f` for each `alias,
- // canonical` pair.
- void ForEachAlias(base::FunctionRef<void(const SchemefulSite&,
- const SchemefulSite&)> f) const;
-
- // Returns true iff this instance contains a singleton set (a set with only
- // one site).
- bool ContainsSingleton() const;
-
// The version associated with the component_updater-provided public sets.
// This may be invalid if the "First-Party Sets" component has not been
// installed yet, or has been corrupted. Entries and aliases from invalid
@@ -193,10 +203,6 @@ class NET_EXPORT GlobalFirstPartySets {
// Stores the customizations induced by the manually-specified set. May be
// empty if no switch was provided.
FirstPartySetsContextConfig manual_config_;
-
- // Stores the aliases contained in the manually-specified set. (Note that the
- // aliases are *also* stored in `manual_config_`.)
- base::flat_map<SchemefulSite, SchemefulSite> manual_aliases_;
};
NET_EXPORT std::ostream& operator<<(std::ostream& os,
diff --git a/net/first_party_sets/local_set_declaration.cc b/net/first_party_sets/local_set_declaration.cc
index e86933593a7d471f4100e44dc18d74a5ef4480a0..c37b932c20d204ea074f0cdf5ad1cfabc94a04b3 100644
--- a/net/first_party_sets/local_set_declaration.cc
+++ b/net/first_party_sets/local_set_declaration.cc
@@ -13,16 +13,11 @@ namespace net {
LocalSetDeclaration::LocalSetDeclaration() = default;
LocalSetDeclaration::LocalSetDeclaration(
- base::flat_map<SchemefulSite, FirstPartySetEntry> set_entries,
- base::flat_map<SchemefulSite, SchemefulSite> aliases)
- : entries_(std::move(set_entries)), aliases_(std::move(aliases)) {
- // Every alias must map to some canonical site in `entries_`.
- CHECK(base::ranges::all_of(
- aliases_, [&](const auto& p) { return entries_.contains(p.second); }));
-
+ base::flat_map<SchemefulSite, FirstPartySetEntry> set_entries)
+ : entries_(std::move(set_entries)) {
if (!entries_.empty()) {
// Must not be a singleton set (i.e. must have more than one entry).
- CHECK_GT(entries_.size() + aliases_.size(), 1u);
+ CHECK_GT(entries_.size(), 1u);
// All provided entries must have the same primary site. I.e., there must
// only be one set.
diff --git a/net/first_party_sets/local_set_declaration.h b/net/first_party_sets/local_set_declaration.h
index 32814cf5157ba05e91bc87afa466272d24953c8e..6d6ad781ec088112dfe4e537a3587b206cd2b85d 100644
--- a/net/first_party_sets/local_set_declaration.h
+++ b/net/first_party_sets/local_set_declaration.h
@@ -30,8 +30,7 @@ class NET_EXPORT LocalSetDeclaration {
// the same set (i.e. they must have the same primary site). The set must not
// be a singleton (i.e. must have more than one entry, or must be empty).
explicit LocalSetDeclaration(
- base::flat_map<SchemefulSite, FirstPartySetEntry> set_entries,
- base::flat_map<SchemefulSite, SchemefulSite> aliases);
+ base::flat_map<SchemefulSite, FirstPartySetEntry> set_entries);
~LocalSetDeclaration();
@@ -48,17 +47,10 @@ class NET_EXPORT LocalSetDeclaration {
return entries_;
}
- const base::flat_map<SchemefulSite, SchemefulSite>& aliases() const {
- return aliases_;
- }
-
private:
- // Stores the set of entries, without ccTLD aliases. This may be empty if no
- // set was locally defined.
+ // Stores the set of entries and ccTLD aliases. This may be empty if no set
+ // was locally defined.
base::flat_map<SchemefulSite, FirstPartySetEntry> entries_;
-
- // Stores the ccTLD aliases. May be empty.
- base::flat_map<SchemefulSite, SchemefulSite> aliases_;
};
} // namespace net
diff --git a/net/first_party_sets/same_party_context.cc b/net/first_party_sets/same_party_context.cc
new file mode 100644
index 0000000000000000000000000000000000000000..afa9ddf645cc8776d7c9303da9d93725b945a5d7
--- /dev/null
+++ b/net/first_party_sets/same_party_context.cc
@@ -0,0 +1,28 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/first_party_sets/same_party_context.h"
+
+#include <ostream>
+
+namespace net {
+
+SamePartyContext::SamePartyContext(Type context_type)
+ : context_type_(context_type) {}
+
+bool SamePartyContext::operator==(const SamePartyContext& other) const {
+ return context_type_ == other.context_type_;
+}
+
+std::ostream& operator<<(std::ostream& os, const SamePartyContext& spc) {
+ os << "{" << static_cast<int>(spc.context_type()) << "}";
+ return os;
+}
+
+// static
+SamePartyContext SamePartyContext::MakeInclusive() {
+ return SamePartyContext(Type::kSameParty);
+}
+
+} // namespace net
diff --git a/net/first_party_sets/same_party_context.h b/net/first_party_sets/same_party_context.h
new file mode 100644
index 0000000000000000000000000000000000000000..448f000d8ab368f071d73da887e0e857c33e8973
--- /dev/null
+++ b/net/first_party_sets/same_party_context.h
@@ -0,0 +1,51 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_FIRST_PARTY_SETS_SAME_PARTY_CONTEXT_H_
+#define NET_FIRST_PARTY_SETS_SAME_PARTY_CONTEXT_H_
+
+#include <ostream>
+
+#include "net/base/net_export.h"
+
+namespace net {
+
+// This struct bundles together a few different notions of same-party-ness.
+// `context_type()` gives the notion of same-party-ness that Chromium should use
+// in all cases except metrics; other accessors are just for metrics purposes,
+// to explore the impact of different definitions of "same-party".
+class NET_EXPORT SamePartyContext {
+ public:
+ // Computed for every cookie access attempt but is only relevant for SameParty
+ // cookies.
+ enum class Type {
+ // The opposite to kSameParty. Should be the default value.
+ kCrossParty = 0,
+ // If the request URL is in the same First-Party Sets as the top-frame site
+ // and each member of the isolation_info.party_context.
+ kSameParty = 1,
+ };
+
+ SamePartyContext() = default;
+ explicit SamePartyContext(Type context_type);
+
+ bool operator==(const SamePartyContext& other) const;
+
+ // How trusted is the current browser environment when it comes to accessing
+ // SameParty cookies. Default is not trusted, e.g. kCrossParty.
+ Type context_type() const { return context_type_; }
+
+ // Creates a SamePartyContext that is as permissive as possible.
+ static SamePartyContext MakeInclusive();
+
+ private:
+ Type context_type_ = Type::kCrossParty;
+};
+
+NET_EXPORT std::ostream& operator<<(std::ostream& os,
+ const SamePartyContext& spc);
+
+} // namespace net
+
+#endif // NET_FIRST_PARTY_SETS_SAME_PARTY_CONTEXT_H_
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index 1bd70e772aaba0e04a9b82140109b8d1e511db15..7f8d7a6ab265c2f0d1144429a5f3c6f08c7c38e3 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -1212,7 +1212,7 @@ IsolationInfo URLRequest::CreateIsolationInfoFromNetworkAnonymizationKey(
auto isolation_info = IsolationInfo::Create(
IsolationInfo::RequestType::kOther, top_frame_origin,
frame_origin.value(), SiteForCookies(),
- network_anonymization_key.GetNonce());
+ /*party_context=*/absl::nullopt, network_anonymization_key.GetNonce());
// TODO(crbug/1343856): DCHECK isolation info is fully populated.
return isolation_info;
}
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index ce7074e0474ec80fc105d9668201c95d9dc020d2..ba2991b94361773b63803678a518b6f4e63c67ad 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -315,6 +315,16 @@ class NET_EXPORT URLRequest : public base::SupportsUserData {
force_ignore_site_for_cookies_ = attach;
}
+ // Indicates whether the top frame party will be considered same-party to the
+ // request URL (regardless of what it is), for the purpose of SameParty
+ // cookies.
+ bool force_ignore_top_frame_party_for_cookies() const {
+ return force_ignore_top_frame_party_for_cookies_;
+ }
+ void set_force_ignore_top_frame_party_for_cookies(bool force) {
+ force_ignore_top_frame_party_for_cookies_ = force;
+ }
+
// Indicates if the request should be treated as a main frame navigation for
// SameSite cookie computations. This flag overrides the IsolationInfo
// request type associated with fetches from a service worker context.
@@ -971,6 +981,7 @@ class NET_EXPORT URLRequest : public base::SupportsUserData {
absl::optional<CookiePartitionKey> cookie_partition_key_ = absl::nullopt;
bool force_ignore_site_for_cookies_ = false;
+ bool force_ignore_top_frame_party_for_cookies_ = false;
bool force_main_frame_for_same_site_cookies_ = false;
CookieSettingOverrides cookie_setting_overrides_;
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 3afc5526490ed43cd57636a3174a8b2166adc868..3a8302b4e57d8d621a7df0c22474d9cac6407491 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -63,7 +63,7 @@
#include "net/filter/zstd_source_stream.h"
#include "net/first_party_sets/first_party_set_entry.h"
#include "net/first_party_sets/first_party_set_metadata.h"
-#include "net/first_party_sets/first_party_sets_cache_filter.h"
+#include "net/first_party_sets/same_party_context.h"
#include "net/http/http_content_disposition.h"
#include "net/http/http_log_util.h"
#include "net/http/http_network_session.h"
@@ -180,11 +180,22 @@ void LogTrustAnchor(const net::HashValueVector& spki_hashes) {
}
net::CookieOptions CreateCookieOptions(
- net::CookieOptions::SameSiteCookieContext same_site_context) {
+ net::CookieOptions::SameSiteCookieContext same_site_context,
+ const net::SamePartyContext& same_party_context,
+ const net::IsolationInfo& isolation_info,
+ bool is_in_nontrivial_first_party_set) {
net::CookieOptions options;
options.set_return_excluded_cookies();
options.set_include_httponly();
options.set_same_site_cookie_context(same_site_context);
+ options.set_same_party_context(same_party_context);
+ if (isolation_info.party_context().has_value()) {
+ // Count the top-frame site since it's not in the party_context.
+ options.set_full_party_context_size(isolation_info.party_context()->size() +
+ 1);
+ }
+ options.set_is_in_nontrivial_first_party_set(
+ is_in_nontrivial_first_party_set);
return options;
}
@@ -380,33 +391,53 @@ void URLRequestHttpJob::Start() {
IsSameSiteIgnoringWebSocketProtocol(request_initiator_site().value(),
request()->url()));
+ bool should_add_cookie_header = ShouldAddCookieHeader();
UMA_HISTOGRAM_BOOLEAN("Net.HttpJob.CanIncludeCookies",
- ShouldAddCookieHeader());
-
- CookieStore* cookie_store = request()->context()->cookie_store();
- const CookieAccessDelegate* delegate =
- cookie_store ? cookie_store->cookie_access_delegate() : nullptr;
+ should_add_cookie_header);
request_->net_log().BeginEvent(NetLogEventType::FIRST_PARTY_SETS_METADATA);
- absl::optional<
- std::pair<FirstPartySetMetadata, FirstPartySetsCacheFilter::MatchInfo>>
- maybe_metadata = cookie_util::ComputeFirstPartySetMetadataMaybeAsync(
+ if (!should_add_cookie_header) {
+ OnGotFirstPartySetMetadata(FirstPartySetMetadata());
+ return;
+ }
+
+ absl::optional<FirstPartySetMetadata> metadata =
+ cookie_util::ComputeFirstPartySetMetadataMaybeAsync(
SchemefulSite(request()->url()), request()->isolation_info(),
- delegate,
+ request()->context()->cookie_store()->cookie_access_delegate(),
+ request()->force_ignore_top_frame_party_for_cookies(),
base::BindOnce(&URLRequestHttpJob::OnGotFirstPartySetMetadata,
weak_factory_.GetWeakPtr()));
- if (maybe_metadata.has_value()) {
- auto [metadata, match_info] = std::move(maybe_metadata).value();
- OnGotFirstPartySetMetadata(std::move(metadata), std::move(match_info));
- }
+ if (metadata.has_value())
+ OnGotFirstPartySetMetadata(std::move(metadata.value()));
}
void URLRequestHttpJob::OnGotFirstPartySetMetadata(
- FirstPartySetMetadata first_party_set_metadata,
- FirstPartySetsCacheFilter::MatchInfo match_info) {
+ FirstPartySetMetadata first_party_set_metadata) {
first_party_set_metadata_ = std::move(first_party_set_metadata);
+
+ if (!request()->network_delegate()) {
+ OnGotFirstPartySetCacheFilterMatchInfo(
+ net::FirstPartySetsCacheFilter::MatchInfo());
+ return;
+ }
+ absl::optional<FirstPartySetsCacheFilter::MatchInfo> match_info =
+ request()
+ ->network_delegate()
+ ->GetFirstPartySetsCacheFilterMatchInfoMaybeAsync(
+ SchemefulSite(request()->url()),
+ base::BindOnce(
+ &URLRequestHttpJob::OnGotFirstPartySetCacheFilterMatchInfo,
+ weak_factory_.GetWeakPtr()));
+
+ if (match_info.has_value())
+ OnGotFirstPartySetCacheFilterMatchInfo(std::move(match_info.value()));
+}
+
+void URLRequestHttpJob::OnGotFirstPartySetCacheFilterMatchInfo(
+ FirstPartySetsCacheFilter::MatchInfo match_info) {
request_info_.fps_cache_filter = match_info.clear_at_run_id;
request_info_.browser_run_id = match_info.browser_run_id;
@@ -733,7 +764,11 @@ void URLRequestHttpJob::AddCookieHeaderAndStart() {
request_->site_for_cookies(), request_->initiator(),
is_main_frame_navigation, force_ignore_site_for_cookies);
- CookieOptions options = CreateCookieOptions(same_site_context);
+ bool is_in_nontrivial_first_party_set =
+ first_party_set_metadata_.frame_entry().has_value();
+ CookieOptions options = CreateCookieOptions(
+ same_site_context, first_party_set_metadata_.context(),
+ request_->isolation_info(), is_in_nontrivial_first_party_set);
cookie_store->GetCookieListWithOptionsAsync(
request_->url(), options,
@@ -963,7 +998,11 @@ void URLRequestHttpJob::SaveCookiesAndNotifyHeadersComplete(int result) {
request_->initiator(), is_main_frame_navigation,
force_ignore_site_for_cookies);
- CookieOptions options = CreateCookieOptions(same_site_context);
+ bool is_in_nontrivial_first_party_set =
+ first_party_set_metadata_.frame_entry().has_value();
+ CookieOptions options = CreateCookieOptions(
+ same_site_context, first_party_set_metadata_.context(),
+ request_->isolation_info(), is_in_nontrivial_first_party_set);
// Set all cookies, without waiting for them to be set. Any subsequent
// read will see the combined result of all cookie operation.
diff --git a/net/url_request/url_request_http_job.h b/net/url_request/url_request_http_job.h
index 943ed021a633e7d9ad33487108f4fd55c33805d0..433d317ba37c6bfb9ce1847f06cc9ff26e05bc82 100644
--- a/net/url_request/url_request_http_job.h
+++ b/net/url_request/url_request_http_job.h
@@ -215,7 +215,11 @@ class NET_EXPORT_PRIVATE URLRequestHttpJob : public URLRequestJob {
// Called after getting the FirstPartySetMetadata during Start for this job.
void OnGotFirstPartySetMetadata(
- FirstPartySetMetadata first_party_set_metadata,
+ FirstPartySetMetadata first_party_set_metadata);
+
+ // Called after getting the FirstPartySetsCacheFilter match info during Start
+ // for this job.
+ void OnGotFirstPartySetCacheFilterMatchInfo(
FirstPartySetsCacheFilter::MatchInfo match_info);
// Returns true iff this request leg should include the Cookie header. Note
diff --git a/services/network/cookie_access_delegate_impl.cc b/services/network/cookie_access_delegate_impl.cc
index 5e0d27953bf8d8770ad72559183ea5f56258cfa0..9d8c6c16d97fb1f4e7393656d40907b457d89818 100644
--- a/services/network/cookie_access_delegate_impl.cc
+++ b/services/network/cookie_access_delegate_impl.cc
@@ -13,7 +13,6 @@
#include "net/cookies/cookie_constants.h"
#include "net/cookies/cookie_util.h"
#include "net/first_party_sets/first_party_set_metadata.h"
-#include "net/first_party_sets/first_party_sets_cache_filter.h"
#include "services/network/public/cpp/is_potentially_trustworthy.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -61,20 +60,16 @@ bool CookieAccessDelegateImpl::ShouldIgnoreSameSiteRestrictions(
return false;
}
-absl::optional<std::pair<net::FirstPartySetMetadata,
- net::FirstPartySetsCacheFilter::MatchInfo>>
+absl::optional<net::FirstPartySetMetadata>
CookieAccessDelegateImpl::ComputeFirstPartySetMetadataMaybeAsync(
const net::SchemefulSite& site,
const net::SchemefulSite* top_frame_site,
- base::OnceCallback<void(net::FirstPartySetMetadata,
- net::FirstPartySetsCacheFilter::MatchInfo)>
- callback) const {
- if (!first_party_sets_access_delegate_) {
- return std::make_pair(net::FirstPartySetMetadata(),
- net::FirstPartySetsCacheFilter::MatchInfo());
- }
+ const std::set<net::SchemefulSite>& party_context,
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const {
+ if (!first_party_sets_access_delegate_)
+ return {net::FirstPartySetMetadata()};
return first_party_sets_access_delegate_->ComputeMetadata(
- site, top_frame_site, std::move(callback));
+ site, top_frame_site, party_context, std::move(callback));
}
absl::optional<FirstPartySetsAccessDelegate::EntriesResult>
diff --git a/services/network/cookie_access_delegate_impl.h b/services/network/cookie_access_delegate_impl.h
index 72a96c033d0c3eb3555cff718c66d7775cf4800c..50c3a309db86e5f044e2bfc429ca82fc6586d084 100644
--- a/services/network/cookie_access_delegate_impl.h
+++ b/services/network/cookie_access_delegate_impl.h
@@ -5,7 +5,10 @@
#ifndef SERVICES_NETWORK_COOKIE_ACCESS_DELEGATE_IMPL_H_
#define SERVICES_NETWORK_COOKIE_ACCESS_DELEGATE_IMPL_H_
+#include <set>
+
#include "base/component_export.h"
+#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
@@ -13,7 +16,6 @@
#include "net/cookies/cookie_access_delegate.h"
#include "net/cookies/cookie_constants.h"
#include "net/first_party_sets/first_party_set_metadata.h"
-#include "net/first_party_sets/first_party_sets_cache_filter.h"
#include "services/network/cookie_settings.h"
#include "services/network/first_party_sets/first_party_sets_access_delegate.h"
#include "services/network/public/mojom/cookie_manager.mojom.h"
@@ -53,15 +55,13 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) CookieAccessDelegateImpl
bool ShouldIgnoreSameSiteRestrictions(
const GURL& url,
const net::SiteForCookies& site_for_cookies) const override;
- [[nodiscard]] absl::optional<
- std::pair<net::FirstPartySetMetadata,
- net::FirstPartySetsCacheFilter::MatchInfo>>
+ [[nodiscard]] absl::optional<net::FirstPartySetMetadata>
ComputeFirstPartySetMetadataMaybeAsync(
const net::SchemefulSite& site,
const net::SchemefulSite* top_frame_site,
- base::OnceCallback<void(net::FirstPartySetMetadata,
- net::FirstPartySetsCacheFilter::MatchInfo)>
- callback) const override;
+ const std::set<net::SchemefulSite>& party_context,
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback)
+ const override;
[[nodiscard]] absl::optional<FirstPartySetsAccessDelegate::EntriesResult>
FindFirstPartySetEntries(
const base::flat_set<net::SchemefulSite>& sites,
diff --git a/services/network/cookie_manager.cc b/services/network/cookie_manager.cc
index e5e410525d8a6ffe8f653fee3de4be1eaca504a9..7c11eb0558368aa2d94cf4e4f15d5b09f665719e 100644
--- a/services/network/cookie_manager.cc
+++ b/services/network/cookie_manager.cc
@@ -141,8 +141,8 @@ void CookieManager::SetCanonicalCookie(const net::CanonicalCookie& cookie,
cookie.Name(), cookie.Value(), cookie.Domain(), cookie.Path(),
cookie.CreationDate(), adjusted_expiry_date, cookie.LastAccessDate(),
cookie.LastUpdateDate(), cookie.IsSecure(), cookie.IsHttpOnly(),
- cookie.SameSite(), cookie.Priority(), cookie_partition_key,
- cookie.SourceScheme(), cookie.SourcePort());
+ cookie.SameSite(), cookie.Priority(), cookie.IsSameParty(),
+ cookie_partition_key, cookie.SourceScheme(), cookie.SourcePort());
if (!cookie_ptr) {
std::move(callback).Run(
net::CookieAccessResult(net::CookieInclusionStatus(
diff --git a/services/network/first_party_sets/first_party_sets_access_delegate.cc b/services/network/first_party_sets/first_party_sets_access_delegate.cc
index ed35e2dc6f5b0e2867cfdc5fb118e0dd45324a13..c07f0dc2d8a146cf187b204db4f2a9bceca6ceac 100644
--- a/services/network/first_party_sets/first_party_sets_access_delegate.cc
+++ b/services/network/first_party_sets/first_party_sets_access_delegate.cc
@@ -65,24 +65,20 @@ void FirstPartySetsAccessDelegate::SetEnabled(bool enabled) {
enabled_ = enabled;
}
-absl::optional<std::pair<net::FirstPartySetMetadata,
- net::FirstPartySetsCacheFilter::MatchInfo>>
+absl::optional<net::FirstPartySetMetadata>
FirstPartySetsAccessDelegate::ComputeMetadata(
const net::SchemefulSite& site,
const net::SchemefulSite* top_frame_site,
- base::OnceCallback<void(net::FirstPartySetMetadata,
- net::FirstPartySetsCacheFilter::MatchInfo)>
- callback) {
+ const std::set<net::SchemefulSite>& party_context,
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!enabled_) {
- return std::make_pair(net::FirstPartySetMetadata(),
- net::FirstPartySetsCacheFilter::MatchInfo());
+ return {net::FirstPartySetMetadata()};
}
if (!ready_event_.has_value()) {
if (!wait_for_init_) {
- return std::make_pair(net::FirstPartySetMetadata(),
- net::FirstPartySetsCacheFilter::MatchInfo());
+ return {net::FirstPartySetMetadata()};
}
// base::Unretained() is safe because `this` owns `pending_queries_` and
// `pending_queries_` will not run the enqueued callbacks after `this` is
@@ -90,29 +86,12 @@ FirstPartySetsAccessDelegate::ComputeMetadata(
EnqueuePendingQuery(base::BindOnce(
&FirstPartySetsAccessDelegate::ComputeMetadataAndInvoke,
base::Unretained(this), site, base::OptionalFromPtr(top_frame_site),
- std::move(callback)));
+ party_context, std::move(callback)));
return absl::nullopt;
}
- net::FirstPartySetsCacheFilter::MatchInfo match_info(
- cache_filter()->GetMatchInfo(site));
-
- absl::optional<net::FirstPartySetMetadata> metadata =
- manager_->ComputeMetadata(
- site, top_frame_site, *context_config(),
- base::BindOnce(
- [](base::OnceCallback<void(
- net::FirstPartySetMetadata,
- net::FirstPartySetsCacheFilter::MatchInfo)> callback,
- net::FirstPartySetsCacheFilter::MatchInfo info,
- net::FirstPartySetMetadata metadata) {
- std::move(callback).Run(std::move(metadata), std::move(info));
- },
- std::move(callback), match_info));
-
- return metadata.has_value() ? absl::make_optional(std::make_pair(
- std::move(metadata).value(), match_info))
- : absl::nullopt;
+ return manager_->ComputeMetadata(site, top_frame_site, party_context,
+ *context_config(), std::move(callback));
}
absl::optional<FirstPartySetsAccessDelegate::EntriesResult>
@@ -141,13 +120,37 @@ FirstPartySetsAccessDelegate::FindEntries(
return manager_->FindEntries(sites, *context_config(), std::move(callback));
}
+absl::optional<net::FirstPartySetsCacheFilter::MatchInfo>
+FirstPartySetsAccessDelegate::GetCacheFilterMatchInfo(
+ const net::SchemefulSite& site,
+ base::OnceCallback<void(net::FirstPartySetsCacheFilter::MatchInfo)>
+ callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (!enabled_)
+ return {net::FirstPartySetsCacheFilter::MatchInfo()};
+
+ if (!ready_event_.has_value()) {
+ if (!wait_for_init_) {
+ return {net::FirstPartySetsCacheFilter::MatchInfo()};
+ }
+ // base::Unretained() is safe because `this` owns `pending_queries_` and
+ // `pending_queries_` will not run the enqueued callbacks after `this` is
+ // destroyed.
+ EnqueuePendingQuery(base::BindOnce(
+ &FirstPartySetsAccessDelegate::GetCacheFilterMatchInfoAndInvoke,
+ base::Unretained(this), site, std::move(callback)));
+ return absl::nullopt;
+ }
+
+ return cache_filter()->GetMatchInfo(site);
+}
+
void FirstPartySetsAccessDelegate::ComputeMetadataAndInvoke(
const net::SchemefulSite& site,
const absl::optional<net::SchemefulSite> top_frame_site,
- base::OnceCallback<void(net::FirstPartySetMetadata,
- net::FirstPartySetsCacheFilter::MatchInfo)>
- callback) const {
- using CallbackType = decltype(callback);
+ const std::set<net::SchemefulSite>& party_context,
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(context_config());
// NB: since `ComputeMetadata` returns early if the delegate is disabled,
@@ -155,26 +158,17 @@ void FirstPartySetsAccessDelegate::ComputeMetadataAndInvoke(
// enabled when the query was received. However, the delegate may have been
// disabled between then and now, so we have no guarantees re: `enabled_` now.
- std::pair<CallbackType, CallbackType> callbacks =
- base::SplitOnceCallback(std::move(callback));
-
- net::FirstPartySetsCacheFilter::MatchInfo match_info(
- cache_filter()->GetMatchInfo(site));
+ std::pair<base::OnceCallback<void(net::FirstPartySetMetadata)>,
+ base::OnceCallback<void(net::FirstPartySetMetadata)>>
+ callbacks = base::SplitOnceCallback(std::move(callback));
absl::optional<net::FirstPartySetMetadata> sync_result =
- manager_->ComputeMetadata(
- site, base::OptionalToPtr(top_frame_site), *context_config(),
- base::BindOnce(
- [](CallbackType callback,
- net::FirstPartySetsCacheFilter::MatchInfo match_info,
- net::FirstPartySetMetadata metadata) {
- std::move(callback).Run(std::move(metadata), match_info);
- },
- std::move(callbacks.first), match_info));
-
- if (sync_result.has_value()) {
- std::move(callbacks.second).Run(std::move(sync_result.value()), match_info);
- }
+ manager_->ComputeMetadata(site, base::OptionalToPtr(top_frame_site),
+ party_context, *context_config(),
+ std::move(callbacks.first));
+
+ if (sync_result.has_value())
+ std::move(callbacks.second).Run(std::move(sync_result.value()));
}
void FirstPartySetsAccessDelegate::FindEntriesAndInvoke(
@@ -201,6 +195,20 @@ void FirstPartySetsAccessDelegate::FindEntriesAndInvoke(
std::move(callbacks.second).Run(sync_result.value());
}
+void FirstPartySetsAccessDelegate::GetCacheFilterMatchInfoAndInvoke(
+ const net::SchemefulSite& site,
+ base::OnceCallback<void(net::FirstPartySetsCacheFilter::MatchInfo)>
+ callback) const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ CHECK(cache_filter());
+ // NB: since `GetCacheFilterMatchInfo` returns early if the delegate is
+ // disabled, we're guaranteed that for any queued query, the delegate must
+ // have been enabled when the query was received. However, the delegate may
+ // have been disabled between then and now, so we have no guarantees re:
+ // `enabled_` now.
+ std::move(callback).Run(cache_filter()->GetMatchInfo(site));
+}
+
void FirstPartySetsAccessDelegate::InvokePendingQueries() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(ready_event_.has_value());
diff --git a/services/network/first_party_sets/first_party_sets_access_delegate.h b/services/network/first_party_sets/first_party_sets_access_delegate.h
index d8a717465c10ed97863aec940987c1dd5814ed83..67df37ef7dfc344bff9bb569fdc58c29967aeb22 100644
--- a/services/network/first_party_sets/first_party_sets_access_delegate.h
+++ b/services/network/first_party_sets/first_party_sets_access_delegate.h
@@ -53,22 +53,17 @@ class FirstPartySetsAccessDelegate
void NotifyReady(mojom::FirstPartySetsReadyEventPtr ready_event) override;
void SetEnabled(bool enabled) override;
- // Computes the First-Party Set metadata and cache filter match info related
- // to the given context.
+ // Computes the First-Party Set metadata related to the given context.
//
// This may return a result synchronously, or asynchronously invoke `callback`
// with the result. The callback will be invoked iff the return value is
// nullopt; i.e. a result will be provided via return value or callback, but
// not both, and not neither.
- [[nodiscard]] absl::optional<
- std::pair<net::FirstPartySetMetadata,
- net::FirstPartySetsCacheFilter::MatchInfo>>
- ComputeMetadata(
+ [[nodiscard]] absl::optional<net::FirstPartySetMetadata> ComputeMetadata(
const net::SchemefulSite& site,
const net::SchemefulSite* top_frame_site,
- base::OnceCallback<void(net::FirstPartySetMetadata,
- net::FirstPartySetsCacheFilter::MatchInfo)>
- callback);
+ const std::set<net::SchemefulSite>& party_context,
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback);
// Calls FirstPartySetsManager::FindEntries either asynchronously or
// synchronously, once initialization is complete.
@@ -81,15 +76,24 @@ class FirstPartySetsAccessDelegate
const base::flat_set<net::SchemefulSite>& sites,
base::OnceCallback<void(EntriesResult)> callback);
+ // This may return a result synchronously, or asynchronously invoke `callback`
+ // with the result. The callback will be invoked iff the return value is
+ // nullopt; i.e. a result will be provided via return value or callback, but
+ // not both, and not neither.
+ [[nodiscard]] absl::optional<net::FirstPartySetsCacheFilter::MatchInfo>
+ GetCacheFilterMatchInfo(
+ const net::SchemefulSite& site,
+ base::OnceCallback<void(net::FirstPartySetsCacheFilter::MatchInfo)>
+ callback);
+
private:
// Same as `ComputeMetadata`, but plumbs the result into the callback. Must
// only be called once the instance is fully initialized.
void ComputeMetadataAndInvoke(
const net::SchemefulSite& site,
const absl::optional<net::SchemefulSite> top_frame_site,
- base::OnceCallback<void(net::FirstPartySetMetadata,
- net::FirstPartySetsCacheFilter::MatchInfo)>
- callback) const;
+ const std::set<net::SchemefulSite>& party_context,
+ base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const;
// Same as `FindEntries`, but plumbs the result into the callback. Must only
// be called once the instance is fully initialized.
@@ -97,6 +101,13 @@ class FirstPartySetsAccessDelegate
const base::flat_set<net::SchemefulSite>& sites,
base::OnceCallback<void(EntriesResult)> callback) const;
+ // Same as `GetCacheFilterMatchInfo`, but plumbs the result into the
+ // callback. Must only be called once the instance is fully initialized.
+ void GetCacheFilterMatchInfoAndInvoke(
+ const net::SchemefulSite& site,
+ base::OnceCallback<void(net::FirstPartySetsCacheFilter::MatchInfo)>
+ callback) const;
+
// Runs all pending queries. Must not be called until the instance is fully
// initialized.
void InvokePendingQueries();
diff --git a/services/network/first_party_sets/first_party_sets_manager.cc b/services/network/first_party_sets/first_party_sets_manager.cc
index 2ffd2a8be03efcf3900e7bbb4056c722e0dd9130..6cbd2bd9e09b6b7cb4fdb4d853959a1009cbf4a8 100644
--- a/services/network/first_party_sets/first_party_sets_manager.cc
+++ b/services/network/first_party_sets/first_party_sets_manager.cc
@@ -15,6 +15,7 @@
#include "base/feature_list.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
+#include "base/ranges/algorithm.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
@@ -24,6 +25,7 @@
#include "net/first_party_sets/first_party_set_entry.h"
#include "net/first_party_sets/first_party_set_metadata.h"
#include "net/first_party_sets/global_first_party_sets.h"
+#include "net/first_party_sets/same_party_context.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace network {
@@ -48,6 +50,7 @@ absl::optional<net::FirstPartySetMetadata>
FirstPartySetsManager::ComputeMetadata(
const net::SchemefulSite& site,
const net::SchemefulSite* top_frame_site,
+ const std::set<net::SchemefulSite>& party_context,
const net::FirstPartySetsContextConfig& fps_context_config,
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -59,16 +62,19 @@ FirstPartySetsManager::ComputeMetadata(
EnqueuePendingQuery(base::BindOnce(
&FirstPartySetsManager::ComputeMetadataAndInvoke,
weak_factory_.GetWeakPtr(), site, base::OptionalFromPtr(top_frame_site),
- fps_context_config.Clone(), std::move(callback), base::ElapsedTimer()));
+ party_context, fps_context_config.Clone(), std::move(callback),
+ base::ElapsedTimer()));
return absl::nullopt;
}
- return ComputeMetadataInternal(site, top_frame_site, fps_context_config);
+ return ComputeMetadataInternal(site, top_frame_site, party_context,
+ fps_context_config);
}
void FirstPartySetsManager::ComputeMetadataAndInvoke(
const net::SchemefulSite& site,
const absl::optional<net::SchemefulSite> top_frame_site,
+ const std::set<net::SchemefulSite>& party_context,
const net::FirstPartySetsContextConfig& fps_context_config,
base::OnceCallback<void(net::FirstPartySetMetadata)> callback,
base::ElapsedTimer timer) const {
@@ -78,18 +84,21 @@ void FirstPartySetsManager::ComputeMetadataAndInvoke(
UMA_HISTOGRAM_TIMES("Cookie.FirstPartySets.EnqueueingDelay.ComputeMetadata2",
timer.Elapsed());
- std::move(callback).Run(ComputeMetadataInternal(
- site, base::OptionalToPtr(top_frame_site), fps_context_config));
+ std::move(callback).Run(
+ ComputeMetadataInternal(site, base::OptionalToPtr(top_frame_site),
+ party_context, fps_context_config));
}
net::FirstPartySetMetadata FirstPartySetsManager::ComputeMetadataInternal(
const net::SchemefulSite& site,
const net::SchemefulSite* top_frame_site,
+ const std::set<net::SchemefulSite>& party_context,
const net::FirstPartySetsContextConfig& fps_context_config) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(sets_.has_value());
- return sets_->ComputeMetadata(site, top_frame_site, fps_context_config);
+ return sets_->ComputeMetadata(site, top_frame_site, party_context,
+ fps_context_config);
}
absl::optional<net::FirstPartySetEntry> FirstPartySetsManager::FindEntry(
diff --git a/services/network/first_party_sets/first_party_sets_manager.h b/services/network/first_party_sets/first_party_sets_manager.h
index 9754dd5f6b0087c6630285b1f592e43cda4ba8d6..b04a98f42fc96a5f2e85cd1bc8ea841fb170e4f2 100644
--- a/services/network/first_party_sets/first_party_sets_manager.h
+++ b/services/network/first_party_sets/first_party_sets_manager.h
@@ -15,6 +15,7 @@
#include "base/functional/callback.h"
#include "base/sequence_checker.h"
#include "base/thread_annotations.h"
+#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "net/base/schemeful_site.h"
#include "net/first_party_sets/first_party_set_entry.h"
@@ -52,6 +53,7 @@ class FirstPartySetsManager {
[[nodiscard]] absl::optional<net::FirstPartySetMetadata> ComputeMetadata(
const net::SchemefulSite& site,
const net::SchemefulSite* top_frame_site,
+ const std::set<net::SchemefulSite>& party_context,
const net::FirstPartySetsContextConfig& fps_context_config,
base::OnceCallback<void(net::FirstPartySetMetadata)> callback);
@@ -84,6 +86,7 @@ class FirstPartySetsManager {
void ComputeMetadataAndInvoke(
const net::SchemefulSite& site,
const absl::optional<net::SchemefulSite> top_frame_site,
+ const std::set<net::SchemefulSite>& party_context,
const net::FirstPartySetsContextConfig& fps_context_config,
base::OnceCallback<void(net::FirstPartySetMetadata)> callback,
base::ElapsedTimer timer) const;
@@ -93,6 +96,7 @@ class FirstPartySetsManager {
net::FirstPartySetMetadata ComputeMetadataInternal(
const net::SchemefulSite& site,
const net::SchemefulSite* top_frame_site,
+ const std::set<net::SchemefulSite>& party_context,
const net::FirstPartySetsContextConfig& fps_context_config) const;
// Returns `site`'s entry, or `nullopt` if `site` has no entry.
diff --git a/services/network/network_service_network_delegate.cc b/services/network/network_service_network_delegate.cc
index d1e91772d48c45b039e349cf76c84a49ffd2b2cd..301a15c02b6b6ded56e231116aaa18c126d1bf95 100644
--- a/services/network/network_service_network_delegate.cc
+++ b/services/network/network_service_network_delegate.cc
@@ -18,6 +18,7 @@
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/cookies/cookie_setting_override.h"
+#include "net/first_party_sets/same_party_context.h"
#include "net/url_request/clear_site_data.h"
#include "net/url_request/referrer_policy.h"
#include "net/url_request/url_request.h"
@@ -331,6 +332,16 @@ bool NetworkServiceNetworkDelegate::OnCanUseReportingClient(
origin, net::CookieSettingOverrides());
}
+absl::optional<net::FirstPartySetsCacheFilter::MatchInfo>
+NetworkServiceNetworkDelegate::
+ OnGetFirstPartySetsCacheFilterMatchInfoMaybeAsync(
+ const net::SchemefulSite& request_site,
+ base::OnceCallback<void(net::FirstPartySetsCacheFilter::MatchInfo)>
+ callback) const {
+ return network_context_->first_party_sets_access_delegate()
+ .GetCacheFilterMatchInfo(request_site, std::move(callback));
+}
+
int NetworkServiceNetworkDelegate::HandleClearSiteDataHeader(
net::URLRequest* request,
net::CompletionOnceCallback callback,
diff --git a/services/network/network_service_network_delegate.h b/services/network/network_service_network_delegate.h
index acfc4db5bf05115d8a3dcd274ba08838f7db5ee8..25c230b8d0d65c95ba6524c61ad44ee3828326f9 100644
--- a/services/network/network_service_network_delegate.h
+++ b/services/network/network_service_network_delegate.h
@@ -19,6 +19,7 @@
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace net {
+class SchemefulSite;
class CookieInclusionStatus;
} // namespace net
@@ -94,6 +95,11 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkServiceNetworkDelegate
const GURL& endpoint) const override;
bool OnCanUseReportingClient(const url::Origin& origin,
const GURL& endpoint) const override;
+ absl::optional<net::FirstPartySetsCacheFilter::MatchInfo>
+ OnGetFirstPartySetsCacheFilterMatchInfoMaybeAsync(
+ const net::SchemefulSite& request_site,
+ base::OnceCallback<void(net::FirstPartySetsCacheFilter::MatchInfo)>
+ callback) const override;
int HandleClearSiteDataHeader(
net::URLRequest* request,
diff --git a/services/network/public/cpp/cookie_manager_mojom_traits.cc b/services/network/public/cpp/cookie_manager_mojom_traits.cc
index bdf07a173b84ab6a4c3222ecbb2da84130950d06..2505b01a13c62f49ce73a539d5d452ea6ae340bd 100644
--- a/services/network/public/cpp/cookie_manager_mojom_traits.cc
+++ b/services/network/public/cpp/cookie_manager_mojom_traits.cc
@@ -586,6 +586,17 @@ bool StructTraits<network::mojom::CookieOptionsDataView, net::CookieOptions>::
else
cookie_options->unset_return_excluded_cookies();
+ net::SamePartyContext same_party_context;
+ if (!mojo_options.ReadSamePartyContext(&same_party_context))
+ return false;
+ cookie_options->set_same_party_context(same_party_context);
+
+ cookie_options->set_full_party_context_size(
+ mojo_options.full_party_context_size());
+
+ cookie_options->set_is_in_nontrivial_first_party_set(
+ mojo_options.is_in_nontrivial_first_party_set());
+
return true;
}
@@ -692,8 +703,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), std::move(last_update_time), cookie.secure(),
- cookie.httponly(), site_restrictions, priority, partition_key,
- source_scheme, cookie.source_port());
+ cookie.httponly(), site_restrictions, priority, cookie.same_party(),
+ partition_key, source_scheme, cookie.source_port());
if (!cc)
return false;
*out = *cc;
diff --git a/services/network/public/cpp/cookie_manager_mojom_traits.h b/services/network/public/cpp/cookie_manager_mojom_traits.h
index 3f7d6369a4e107b71f9c20fe5e212a8ea7d45701..d562b702b0f5a87017268e80d5941585609ccc3b 100644
--- a/services/network/public/cpp/cookie_manager_mojom_traits.h
+++ b/services/network/public/cpp/cookie_manager_mojom_traits.h
@@ -16,6 +16,8 @@
#include "net/cookies/cookie_inclusion_status.h"
#include "net/cookies/cookie_options.h"
#include "net/cookies/cookie_partition_key_collection.h"
+#include "net/first_party_sets/first_party_set_entry.h"
+#include "net/first_party_sets/same_party_context.h"
#include "services/network/public/cpp/cookie_manager_shared_mojom_traits.h"
#include "services/network/public/mojom/cookie_manager.mojom-forward.h"
#include "services/network/public/mojom/cookie_manager.mojom.h"
@@ -194,6 +196,18 @@ struct StructTraits<network::mojom::CookieOptionsDataView, net::CookieOptions> {
return o.return_excluded_cookies();
}
+ static net::SamePartyContext same_party_context(const net::CookieOptions& o) {
+ return o.same_party_context();
+ }
+
+ static uint32_t full_party_context_size(const net::CookieOptions& o) {
+ return o.full_party_context_size();
+ }
+
+ static bool is_in_nontrivial_first_party_set(const net::CookieOptions& o) {
+ return o.is_in_nontrivial_first_party_set();
+ }
+
static bool Read(network::mojom::CookieOptionsDataView mojo_options,
net::CookieOptions* cookie_options);
};
@@ -270,6 +284,9 @@ struct StructTraits<network::mojom::CanonicalCookieDataView,
static net::CookieSourceScheme source_scheme(const net::CanonicalCookie& c) {
return c.SourceScheme();
}
+ static bool same_party(const net::CanonicalCookie& c) {
+ return c.IsSameParty();
+ }
static const absl::optional<net::CookiePartitionKey>& partition_key(
const net::CanonicalCookie& c) {
return c.PartitionKey();
diff --git a/services/network/public/cpp/first_party_sets_mojom_traits.cc b/services/network/public/cpp/first_party_sets_mojom_traits.cc
index b5d5d26e7d2362ba2a9d17be393cb70cb001b827..4d1e584278722eb449012ef4f2f8f2162223711f 100644
--- a/services/network/public/cpp/first_party_sets_mojom_traits.cc
+++ b/services/network/public/cpp/first_party_sets_mojom_traits.cc
@@ -18,6 +18,7 @@
#include "net/first_party_sets/first_party_sets_cache_filter.h"
#include "net/first_party_sets/first_party_sets_context_config.h"
#include "net/first_party_sets/global_first_party_sets.h"
+#include "net/first_party_sets/same_party_context.h"
#include "services/network/public/cpp/schemeful_site_mojom_traits.h"
#include "services/network/public/mojom/first_party_sets.mojom-shared.h"
@@ -83,10 +84,55 @@ bool StructTraits<network::mojom::FirstPartySetEntryDataView,
return true;
}
+bool EnumTraits<network::mojom::SamePartyCookieContextType,
+ net::SamePartyContext::Type>::
+ FromMojom(network::mojom::SamePartyCookieContextType context_type,
+ net::SamePartyContext::Type* out) {
+ switch (context_type) {
+ case network::mojom::SamePartyCookieContextType::kCrossParty:
+ *out = net::SamePartyContext::Type::kCrossParty;
+ return true;
+ case network::mojom::SamePartyCookieContextType::kSameParty:
+ *out = net::SamePartyContext::Type::kSameParty;
+ return true;
+ }
+ return false;
+}
+
+network::mojom::SamePartyCookieContextType
+EnumTraits<network::mojom::SamePartyCookieContextType,
+ net::SamePartyContext::Type>::ToMojom(net::SamePartyContext::Type
+ context_type) {
+ switch (context_type) {
+ case net::SamePartyContext::Type::kCrossParty:
+ return network::mojom::SamePartyCookieContextType::kCrossParty;
+ case net::SamePartyContext::Type::kSameParty:
+ return network::mojom::SamePartyCookieContextType::kSameParty;
+ }
+ NOTREACHED();
+ return network::mojom::SamePartyCookieContextType::kCrossParty;
+}
+
+bool StructTraits<network::mojom::SamePartyContextDataView,
+ net::SamePartyContext>::
+ Read(network::mojom::SamePartyContextDataView context,
+ net::SamePartyContext* out) {
+ net::SamePartyContext::Type context_type;
+ if (!context.ReadContextType(&context_type))
+ return false;
+
+ *out = net::SamePartyContext(context_type);
+ return true;
+}
+
bool StructTraits<network::mojom::FirstPartySetMetadataDataView,
net::FirstPartySetMetadata>::
Read(network::mojom::FirstPartySetMetadataDataView metadata,
net::FirstPartySetMetadata* out_metadata) {
+ net::SamePartyContext context;
+ if (!metadata.ReadContext(&context))
+ return false;
+
absl::optional<net::FirstPartySetEntry> frame_entry;
if (!metadata.ReadFrameEntry(&frame_entry))
return false;
@@ -95,8 +141,9 @@ bool StructTraits<network::mojom::FirstPartySetMetadataDataView,
if (!metadata.ReadTopFrameEntry(&top_frame_entry))
return false;
- *out_metadata = net::FirstPartySetMetadata(
- base::OptionalToPtr(frame_entry), base::OptionalToPtr(top_frame_entry));
+ *out_metadata =
+ net::FirstPartySetMetadata(context, base::OptionalToPtr(frame_entry),
+ base::OptionalToPtr(top_frame_entry));
return true;
}
@@ -127,29 +174,8 @@ bool StructTraits<network::mojom::GlobalFirstPartySetsDataView,
if (!sets.ReadManualConfig(&manual_config))
return false;
- base::flat_map<net::SchemefulSite, net::SchemefulSite> manual_aliases;
- if (!sets.ReadManualAliases(&manual_aliases)) {
- return false;
- }
-
- // The manual_config must contain both the alias overrides and their
- // corresponding canonical overrides, none of which may be deletions.
- if (!base::ranges::all_of(manual_aliases, [&](const auto& pair) {
- absl::optional<net::FirstPartySetEntryOverride> aliased_override =
- manual_config.FindOverride(pair.first);
- absl::optional<net::FirstPartySetEntryOverride> canonical_override =
- manual_config.FindOverride(pair.second);
- return aliased_override.has_value() &&
- !aliased_override->IsDeletion() &&
- canonical_override.has_value() &&
- !canonical_override->IsDeletion();
- })) {
- return false;
- }
-
- *out_sets = net::GlobalFirstPartySets(
- std::move(public_sets_version), std::move(entries), std::move(aliases),
- std::move(manual_config), std::move(manual_aliases));
+ *out_sets = net::GlobalFirstPartySets(std::move(public_sets_version), entries,
+ aliases, std::move(manual_config));
return true;
}
diff --git a/services/network/public/cpp/first_party_sets_mojom_traits.h b/services/network/public/cpp/first_party_sets_mojom_traits.h
index 8a03b2f3216fdce84c868d71188b8a702b51ad61..644aab23aef7fb37c573add9e4180b743c755a12 100644
--- a/services/network/public/cpp/first_party_sets_mojom_traits.h
+++ b/services/network/public/cpp/first_party_sets_mojom_traits.h
@@ -16,6 +16,7 @@
#include "net/first_party_sets/first_party_sets_cache_filter.h"
#include "net/first_party_sets/first_party_sets_context_config.h"
#include "net/first_party_sets/global_first_party_sets.h"
+#include "net/first_party_sets/same_party_context.h"
#include "services/network/public/mojom/first_party_sets.mojom-shared.h"
namespace mojo {
@@ -61,10 +62,38 @@ struct COMPONENT_EXPORT(FIRST_PARTY_SETS_MOJOM_TRAITS)
net::FirstPartySetEntry* out);
};
+template <>
+struct COMPONENT_EXPORT(FIRST_PARTY_SETS_MOJOM_TRAITS)
+ EnumTraits<network::mojom::SamePartyCookieContextType,
+ net::SamePartyContext::Type> {
+ static network::mojom::SamePartyCookieContextType ToMojom(
+ net::SamePartyContext::Type context_type);
+
+ static bool FromMojom(network::mojom::SamePartyCookieContextType context_type,
+ net::SamePartyContext::Type* out);
+};
+
+template <>
+struct COMPONENT_EXPORT(FIRST_PARTY_SETS_MOJOM_TRAITS)
+ StructTraits<network::mojom::SamePartyContextDataView,
+ net::SamePartyContext> {
+ static net::SamePartyContext::Type context_type(
+ const net::SamePartyContext& s) {
+ return s.context_type();
+ }
+
+ static bool Read(network::mojom::SamePartyContextDataView bundle,
+ net::SamePartyContext* out);
+};
+
template <>
struct COMPONENT_EXPORT(FIRST_PARTY_SETS_MOJOM_TRAITS)
StructTraits<network::mojom::FirstPartySetMetadataDataView,
net::FirstPartySetMetadata> {
+ static net::SamePartyContext context(const net::FirstPartySetMetadata& m) {
+ return m.context();
+ }
+
static absl::optional<net::FirstPartySetEntry> frame_entry(
const net::FirstPartySetMetadata& m) {
return m.frame_entry();
@@ -103,11 +132,6 @@ struct COMPONENT_EXPORT(FIRST_PARTY_SETS_MOJOM_TRAITS)
return sets.manual_config_;
}
- static const base::flat_map<net::SchemefulSite, net::SchemefulSite>&
- manual_aliases(const net::GlobalFirstPartySets& sets) {
- return sets.manual_aliases_;
- }
-
static bool Read(network::mojom::GlobalFirstPartySetsDataView sets,
net::GlobalFirstPartySets* out_sets);
};
diff --git a/services/network/public/cpp/isolation_info_mojom_traits.cc b/services/network/public/cpp/isolation_info_mojom_traits.cc
index cc91befdc7da5e88eac6cea0f05eef0707bb4b04..a5a3d0af67c958766bacc8a02cacf490d3c5b5e4 100644
--- a/services/network/public/cpp/isolation_info_mojom_traits.cc
+++ b/services/network/public/cpp/isolation_info_mojom_traits.cc
@@ -53,6 +53,7 @@ bool StructTraits<network::mojom::IsolationInfoDataView, net::IsolationInfo>::
absl::optional<base::UnguessableToken> nonce;
net::SiteForCookies site_for_cookies;
net::IsolationInfo::RequestType request_type;
+ absl::optional<std::vector<net::SchemefulSite>> mojo_party_context;
if (!data.ReadTopFrameOrigin(&top_frame_origin)) {
network::debug::SetDeserializationCrashKeyString("isolation_top_origin");
@@ -63,14 +64,23 @@ bool StructTraits<network::mojom::IsolationInfoDataView, net::IsolationInfo>::
return false;
}
if (!data.ReadNonce(&nonce) || !data.ReadSiteForCookies(&site_for_cookies) ||
- !data.ReadRequestType(&request_type)) {
+ !data.ReadRequestType(&request_type) ||
+ !data.ReadPartyContext(&mojo_party_context)) {
return false;
}
+ absl::optional<std::set<net::SchemefulSite>> party_context;
+ if (mojo_party_context.has_value()) {
+ party_context = std::set<net::SchemefulSite>(mojo_party_context->begin(),
+ mojo_party_context->end());
+ if (party_context->size() != mojo_party_context->size())
+ return false;
+ }
+
absl::optional<net::IsolationInfo> isolation_info =
net::IsolationInfo::CreateIfConsistent(request_type, top_frame_origin,
frame_origin, site_for_cookies,
- nonce);
+ std::move(party_context), nonce);
if (!isolation_info) {
network::debug::SetDeserializationCrashKeyString("isolation_inconsistent");
return false;
diff --git a/services/network/public/cpp/isolation_info_mojom_traits.h b/services/network/public/cpp/isolation_info_mojom_traits.h
index 40c5582de6832132b9e32de65cdffb9d58b99b36..1d41304d38061f7fb1b219a2289af5e41cbd1353 100644
--- a/services/network/public/cpp/isolation_info_mojom_traits.h
+++ b/services/network/public/cpp/isolation_info_mojom_traits.h
@@ -57,6 +57,11 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
return input.site_for_cookies();
}
+ static const absl::optional<std::set<net::SchemefulSite>>& party_context(
+ const net::IsolationInfo& input) {
+ return input.party_context_;
+ }
+
static bool Read(network::mojom::IsolationInfoDataView data,
net::IsolationInfo* out);
};
diff --git a/services/network/public/mojom/BUILD.gn b/services/network/public/mojom/BUILD.gn
index 4cb2d01d09a2c0ba3acb3672b20b543cbb033aca..cacca86a2e8638d3e12d2a36f1404480e1ac1173 100644
--- a/services/network/public/mojom/BUILD.gn
+++ b/services/network/public/mojom/BUILD.gn
@@ -1015,6 +1015,14 @@ mojom("mojom_first_party_sets") {
mojom = "network.mojom.FirstPartySetEntry"
cpp = "::net::FirstPartySetEntry"
},
+ {
+ mojom = "network.mojom.SamePartyCookieContextType"
+ cpp = "::net::SamePartyContext::Type"
+ },
+ {
+ mojom = "network.mojom.SamePartyContext"
+ cpp = "::net::SamePartyContext"
+ },
{
mojom = "network.mojom.FirstPartySetMetadata"
cpp = "::net::FirstPartySetMetadata"
diff --git a/services/network/public/mojom/cookie_manager.mojom b/services/network/public/mojom/cookie_manager.mojom
index de434341bd6328f5876fb8057d652582dbbf4802..011f7b0e95bdbb2f3a370211cc38ba547d881540 100644
--- a/services/network/public/mojom/cookie_manager.mojom
+++ b/services/network/public/mojom/cookie_manager.mojom
@@ -166,6 +166,12 @@ struct CookieOptions {
CookieSameSiteContext same_site_cookie_context;
bool update_access_time = true;
bool return_excluded_cookies = false;
+ SamePartyContext same_party_context;
+ // The size of the isolation_info.party_context plus the top-frame site for
+ // logging purposes.
+ uint32 full_party_context_size = 0;
+ // Whether the site is a member of a nontrivial First-Party Set.
+ bool is_in_nontrivial_first_party_set = false;
};
// See net/cookies/canonical_cookie.{h,cc} for documentation.
@@ -184,6 +190,7 @@ struct CanonicalCookie {
CookieSameSite site_restrictions = NO_RESTRICTION;
CookiePriority priority = MEDIUM;
CookieSourceScheme source_scheme = kUnset;
+ bool same_party = false;
CookiePartitionKey? partition_key;
// -1 because of url::PORT_UNSPECIFIED
// url/third_party/mozilla/url_parse.h
diff --git a/services/network/public/mojom/first_party_sets.mojom b/services/network/public/mojom/first_party_sets.mojom
index 875138dee43ec8739c35fbab27e27ca0fc502e69..150fed986ded1c82ca3b965c0218193dc938d7a1 100644
--- a/services/network/public/mojom/first_party_sets.mojom
+++ b/services/network/public/mojom/first_party_sets.mojom
@@ -27,9 +27,25 @@ struct FirstPartySetEntry {
SiteIndex? site_index;
};
+// Computed for every cookie access attempt but is only relevant for SameParty
+// cookies.
+enum SamePartyCookieContextType {
+ // The opposite to kSameParty. Should be the default value.
+ kCrossParty,
+ // If the request URL is in the same First-Party Sets as the top-frame site
+ // and each member of the isolation_info.party_context.
+ kSameParty,
+};
+
+// Keep defaults in here in sync with net/cookies/same_party_context.cc.
+struct SamePartyContext {
+ SamePartyCookieContextType context_type = kCrossParty;
+};
+
// This struct must match the class fields defined in
// //net/first_party_sets/first_party_set_metadata.h.
struct FirstPartySetMetadata {
+ SamePartyContext context;
// absl::nullopt indicates that the frame's site is not associated with any
// First-Party Set.
FirstPartySetEntry? frame_entry;
@@ -83,11 +99,7 @@ struct GlobalFirstPartySets {
// The mapping from site alias to canonical site from public sets.
map<SchemefulSite, SchemefulSite> aliases;
- // The config induced by the manually-supplied set. This config contains all
- // relevant ccTLD aliases.
+ // The config induced by the manually-supplied set.
FirstPartySetsContextConfig manual_config;
-
- // The aliases contained in the manually-supplied set.
- map<SchemefulSite, SchemefulSite> manual_aliases;
};
diff --git a/services/network/public/mojom/isolation_info.mojom b/services/network/public/mojom/isolation_info.mojom
index 60b726cce8f05a8d0a89a310d00b467be519badc..407ea92cb29712fd89f7c40c6bb210900da8987d 100644
--- a/services/network/public/mojom/isolation_info.mojom
+++ b/services/network/public/mojom/isolation_info.mojom
@@ -26,4 +26,5 @@ struct IsolationInfo {
url.mojom.Origin? frame_origin;
mojo_base.mojom.UnguessableToken? nonce;
SiteForCookies site_for_cookies;
+ array<SchemefulSite>? party_context;
};
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index e6c2bb7599d1606725c982db98255a04ed456419..1de4e2666492196bb5dcd5a45632fe0928cc0a82 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -1013,7 +1013,7 @@ interface NetworkContext {
// document's frame)), or a request origin when |role| is
// RestrictedCookieManagerRole::NETWORK (a network request).
//
- // |isolation_info| contains info for SameSite cookie queries.
+ // |isolation_info| contains info for SameSite and SameParty cookie queries.
// Must be fully populated.
//
// If |role| == SCRIPT, this interface can be safely handed out to a process
diff --git a/services/network/restricted_cookie_manager.cc b/services/network/restricted_cookie_manager.cc
index b5b48a0ce69c7bbe7ce61028fc5d832875e59b7c..4d1d95d8721b59587240247775bf13522e5fc4e2 100644
--- a/services/network/restricted_cookie_manager.cc
+++ b/services/network/restricted_cookie_manager.cc
@@ -109,11 +109,20 @@ constexpr base::TimeDelta kCookiesAccessedTimeout = base::Milliseconds(100);
constexpr size_t kMaxCookieCacheCount = 32u;
constexpr size_t kIncreasedMaxCookieCacheCount = 100u;
+// TODO(cfredric): the `force_ignore_top_frame_party` param being false prevents
+// `document.cookie` access for same-party scripts embedded in an extension
+// frame. It would be better if we allowed that similarly to how we allow
+// SameParty cookies for requests in same-party contexts embedded in top-level
+// extension frames.
+const bool kForceIgnoreTopFrameParty = false;
+
net::CookieOptions MakeOptionsForSet(
mojom::RestrictedCookieManagerRole role,
const GURL& url,
const net::SiteForCookies& site_for_cookies,
- const CookieSettings& cookie_settings) {
+ const net::IsolationInfo& isolation_info,
+ const CookieSettings& cookie_settings,
+ const net::FirstPartySetMetadata& first_party_set_metadata) {
net::CookieOptions options;
bool force_ignore_site_for_cookies =
cookie_settings.ShouldIgnoreSameSiteRestrictions(url, site_for_cookies);
@@ -129,6 +138,14 @@ net::CookieOptions MakeOptionsForSet(
net::cookie_util::ComputeSameSiteContextForSubresource(
url, site_for_cookies, force_ignore_site_for_cookies));
}
+ options.set_same_party_context(first_party_set_metadata.context());
+ if (isolation_info.party_context().has_value()) {
+ // Count the top-frame site since it's not in the party_context.
+ options.set_full_party_context_size(isolation_info.party_context()->size() +
+ 1);
+ }
+ options.set_is_in_nontrivial_first_party_set(
+ first_party_set_metadata.frame_entry().has_value());
return options;
}
@@ -137,7 +154,9 @@ net::CookieOptions MakeOptionsForGet(
mojom::RestrictedCookieManagerRole role,
const GURL& url,
const net::SiteForCookies& site_for_cookies,
- const CookieSettings& cookie_settings) {
+ const net::IsolationInfo& isolation_info,
+ const CookieSettings& cookie_settings,
+ const net::FirstPartySetMetadata& first_party_set_metadata) {
// TODO(https://crbug.com/925311): Wire initiator here.
net::CookieOptions options;
bool force_ignore_site_for_cookies =
@@ -155,6 +174,14 @@ net::CookieOptions MakeOptionsForGet(
net::cookie_util::ComputeSameSiteContextForSubresource(
url, site_for_cookies, force_ignore_site_for_cookies));
}
+ options.set_same_party_context(first_party_set_metadata.context());
+ if (isolation_info.party_context().has_value()) {
+ // Count the top-frame site since it's not in the party_context.
+ options.set_full_party_context_size(isolation_info.party_context()->size() +
+ 1);
+ }
+ options.set_is_in_nontrivial_first_party_set(
+ first_party_set_metadata.frame_entry().has_value());
return options;
}
@@ -196,21 +223,13 @@ void RestrictedCookieManager::ComputeFirstPartySetMetadata(
std::pair<base::OnceCallback<void(net::FirstPartySetMetadata)>,
base::OnceCallback<void(net::FirstPartySetMetadata)>>
callbacks = base::SplitOnceCallback(std::move(callback));
- absl::optional<std::pair<net::FirstPartySetMetadata,
- net::FirstPartySetsCacheFilter::MatchInfo>>
- metadata_and_match_info =
- net::cookie_util::ComputeFirstPartySetMetadataMaybeAsync(
- /*request_site=*/net::SchemefulSite(origin), isolation_info,
- cookie_store->cookie_access_delegate(),
- base::BindOnce([](net::FirstPartySetMetadata metadata,
- net::FirstPartySetsCacheFilter::MatchInfo
- match_info) {
- return metadata;
- }).Then(std::move(callbacks.first)));
- if (metadata_and_match_info.has_value()) {
- std::move(callbacks.second)
- .Run(std::move(metadata_and_match_info.value().first));
- }
+ absl::optional<net::FirstPartySetMetadata> metadata =
+ net::cookie_util::ComputeFirstPartySetMetadataMaybeAsync(
+ /*request_site=*/net::SchemefulSite(origin), isolation_info,
+ cookie_store->cookie_access_delegate(), kForceIgnoreTopFrameParty,
+ std::move(callbacks.first));
+ if (metadata.has_value())
+ std::move(callbacks.second).Run(std::move(metadata.value()));
}
bool CookieWithAccessResultComparer::operator()(
@@ -342,7 +361,8 @@ class RestrictedCookieManager::Listener : public base::LinkNode<Listener> {
bool has_storage_access,
const absl::optional<net::CookiePartitionKey>& cookie_partition_key,
net::CookieOptions options,
- mojo::PendingRemote<mojom::CookieChangeListener> mojo_listener)
+ mojo::PendingRemote<mojom::CookieChangeListener> mojo_listener,
+ bool same_party_attribute_enabled)
: cookie_store_(cookie_store),
restricted_cookie_manager_(restricted_cookie_manager),
url_(url),
@@ -350,7 +370,8 @@ class RestrictedCookieManager::Listener : public base::LinkNode<Listener> {
top_frame_origin_(top_frame_origin),
has_storage_access_(has_storage_access),
options_(options),
- mojo_listener_(std::move(mojo_listener)) {
+ mojo_listener_(std::move(mojo_listener)),
+ same_party_attribute_enabled_(same_party_attribute_enabled) {
// TODO(pwnall): add a constructor w/options to net::CookieChangeDispatcher.
cookie_store_subscription_ =
cookie_store->GetChangeDispatcher().AddCallbackForUrl(
@@ -386,11 +407,16 @@ class RestrictedCookieManager::Listener : public base::LinkNode<Listener> {
// CookieChangeDispatcher doesn't check for inclusion against `options_`, so
// we need to double-check that.
+ net::CookieSamePartyStatus same_party_status =
+ net::cookie_util::GetSamePartyStatus(change.cookie, options_,
+ same_party_attribute_enabled_);
+
if (!change.cookie
.IncludeForRequestURL(
url_, options_,
net::CookieAccessParams{change.access_result.access_semantics,
- delegate_treats_url_as_trustworthy})
+ delegate_treats_url_as_trustworthy,
+ same_party_status})
.status.IsInclude()) {
return;
}
@@ -442,6 +468,8 @@ class RestrictedCookieManager::Listener : public base::LinkNode<Listener> {
mojo::Remote<mojom::CookieChangeListener> mojo_listener_;
+ bool same_party_attribute_enabled_;
+
SEQUENCE_CHECKER(sequence_checker_);
};
@@ -468,6 +496,8 @@ RestrictedCookieManager::RestrictedCookieManager(
cookie_partition_key_collection_(
net::CookiePartitionKeyCollection::FromOptional(
cookie_partition_key_)),
+ same_party_attribute_enabled_(base::FeatureList::IsEnabled(
+ net::features::kSamePartyAttributeEnabled)),
receiver_(this),
metrics_updater_(metrics_updater),
max_cookie_cache_count_(
@@ -594,7 +624,8 @@ void RestrictedCookieManager::GetAllForUrl(
// TODO(morlovich): Try to validate site_for_cookies as well.
net::CookieOptions net_options =
- MakeOptionsForGet(role_, url, site_for_cookies, cookie_settings());
+ MakeOptionsForGet(role_, url, site_for_cookies, isolation_info_,
+ cookie_settings(), first_party_set_metadata_);
// TODO(https://crbug.com/977040): remove set_return_excluded_cookies() once
// removing deprecation warnings.
net_options.set_return_excluded_cookies();
@@ -855,8 +886,8 @@ void RestrictedCookieManager::SetCanonicalCookie(
net::CanonicalCookie::FromStorage(
cookie.Name(), cookie.Value(), cookie.Domain(), cookie.Path(), now,
cookie.ExpiryDate(), now, now, cookie.IsSecure(), cookie.IsHttpOnly(),
- cookie.SameSite(), cookie.Priority(), cookie_partition_key,
- source_scheme, origin_.port());
+ cookie.SameSite(), cookie.Priority(), cookie.IsSameParty(),
+ cookie_partition_key, source_scheme, origin_.port());
DCHECK(sanitized_cookie);
// FromStorage() uses a less strict version of IsCanonical(), we need to check
// the stricter version as well here.
@@ -867,7 +898,8 @@ void RestrictedCookieManager::SetCanonicalCookie(
net::CanonicalCookie cookie_copy = *sanitized_cookie;
net::CookieOptions options =
- MakeOptionsForSet(role_, url, site_for_cookies, cookie_settings());
+ MakeOptionsForSet(role_, url, site_for_cookies, isolation_info_,
+ cookie_settings(), first_party_set_metadata_);
net::CookieAccessResult cookie_access_result(status);
cookie_store_->SetCanonicalCookieAsync(
@@ -925,11 +957,12 @@ void RestrictedCookieManager::AddChangeListener(
}
net::CookieOptions net_options =
- MakeOptionsForGet(role_, url, site_for_cookies, cookie_settings());
+ MakeOptionsForGet(role_, url, site_for_cookies, isolation_info_,
+ cookie_settings(), first_party_set_metadata_);
auto listener = std::make_unique<Listener>(
cookie_store_, this, url, site_for_cookies, top_frame_origin,
has_storage_access, cookie_partition_key_, net_options,
- std::move(mojo_listener));
+ std::move(mojo_listener), same_party_attribute_enabled_);
listener->mojo_listener().set_disconnect_handler(
base::BindOnce(&RestrictedCookieManager::RemoveChangeListener,
diff --git a/services/network/restricted_cookie_manager.h b/services/network/restricted_cookie_manager.h
index 6e32b7e8c32e03fc5de0c6ddba9e8e65ccc790f9..b0e3bdd3246e2ee64781f44679c98e9989a88df4 100644
--- a/services/network/restricted_cookie_manager.h
+++ b/services/network/restricted_cookie_manager.h
@@ -337,6 +337,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) RestrictedCookieManager
// update filtering.
CookieAccessesByURLAndSite recent_cookie_accesses_;
+ bool same_party_attribute_enabled_;
+
// This class can optionally bind its Receiver. If that's the case it's stored
// done with this variable.
mojo::Receiver<mojom::RestrictedCookieManager> receiver_;
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index 87c4c342355df9c5c7a5a01c095fc0d81365cb49..57ce6818a788acc036a3c89f030eda6cc2ebb305 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -291,7 +291,7 @@ bool ShouldNotifyAboutCookie(net::CookieInclusionStatus status) {
status.HasExclusionReason(
net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES) ||
status.HasExclusionReason(
- net::CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT) ||
+ net::CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY) ||
status.HasExclusionReason(
net::CookieInclusionStatus::EXCLUDE_DOMAIN_NON_ASCII);
}
@@ -636,6 +636,9 @@ URLLoader::URLLoader(
DCHECK(!url_request_->isolation_info().IsEmpty());
}
+ if (ShouldForceIgnoreTopFramePartyForCookies())
+ url_request_->set_force_ignore_top_frame_party_for_cookies(true);
+
// When a service worker forwards a navigation request it uses the
// service worker's IsolationInfo. This causes the cookie code to fail
// to send SameSite=Lax cookies for main-frame navigations passed through
@@ -2846,6 +2849,36 @@ bool URLLoader::ShouldForceIgnoreSiteForCookies(
return false;
}
+bool URLLoader::ShouldForceIgnoreTopFramePartyForCookies() const {
+ const net::IsolationInfo& isolation_info = url_request_->isolation_info();
+ const absl::optional<url::Origin>& top_frame_origin =
+ isolation_info.top_frame_origin();
+
+ if (!top_frame_origin || top_frame_origin->opaque())
+ return false;
+
+ const absl::optional<std::set<net::SchemefulSite>>& party_context =
+ isolation_info.party_context();
+ if (!party_context)
+ return false;
+
+ // The top frame origin must have access to the request URL.
+ if (cors::OriginAccessList::AccessState::kAllowed !=
+ origin_access_list_->CheckAccessState(*top_frame_origin,
+ url_request_->url())) {
+ return false;
+ }
+
+ // The top frame origin must have access to each site in the party_context.
+ return base::ranges::all_of(
+ *party_context,
+ [this, &top_frame_origin](const net::SchemefulSite& site) {
+ return origin_access_list_->CheckAccessState(*top_frame_origin,
+ site.GetURL()) ==
+ cors::OriginAccessList::AccessState::kAllowed;
+ });
+}
+
void URLLoader::SetRequestCredentials(const GURL& url) {
bool coep_allow_credentials = CoepAllowCredentials(url);
diff --git a/services/network/url_loader.h b/services/network/url_loader.h
index f06a802a31f3fa66d687d532532b29dc27651d14..9ee2dc0581e492b7d1395cbe0a4c24ca455c7f6a 100644
--- a/services/network/url_loader.h
+++ b/services/network/url_loader.h
@@ -549,6 +549,10 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
// Whether `force_ignore_site_for_cookies` should be set on net::URLRequest.
bool ShouldForceIgnoreSiteForCookies(const ResourceRequest& request);
+ // Whether `force_ignore_top_frame_party_for_cookies` should be set on
+ // net::URLRequest.
+ bool ShouldForceIgnoreTopFramePartyForCookies() const;
+
// Applies Private Network Access checks to the current request.
//
// Helper for `OnConnected()`.
diff --git a/third_party/blink/common/storage_key/storage_key.cc b/third_party/blink/common/storage_key/storage_key.cc
index 5b863520514c1cb5011c6afa08d231a4047282e9..2712538e887b39035ac0b2718a98c5ee812087f9 100644
--- a/third_party/blink/common/storage_key/storage_key.cc
+++ b/third_party/blink/common/storage_key/storage_key.cc
@@ -788,7 +788,8 @@ const net::IsolationInfo StorageKey::ToPartialNetIsolationInfo() const {
: url::Origin::Create(top_level_site_.GetURL());
return net::IsolationInfo::Create(net::IsolationInfo::RequestType::kOther,
top_frame_origin, origin_,
- ToNetSiteForCookies(), nonce_);
+ ToNetSiteForCookies(),
+ /*party_context=*/absl::nullopt, nonce_);
}
// static
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index 5c830ad4623ccb59d71d3f842e45927140597a95..025d11f055ac609a3889050b08aa0881a55933f2 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -5858,7 +5858,7 @@ domain Network
# Cookie Priority
experimental CookiePriority priority
# True if cookie is SameParty.
- experimental deprecated boolean sameParty
+ experimental boolean sameParty
# Cookie source scheme type.
experimental CookieSourceScheme sourceScheme
# Cookie source port. Valid values are {-1, [1, 65535]}, -1 indicates an unspecified port.
diff --git a/third_party/blink/renderer/modules/cookie_store/cookie_store.cc b/third_party/blink/renderer/modules/cookie_store/cookie_store.cc
index ba3ed0252770c90b83721752356d3e1146fcd9f5..47c4b4022517bd2b147b18e999159a10790dcfc2 100644
--- a/third_party/blink/renderer/modules/cookie_store/cookie_store.cc
+++ b/third_party/blink/renderer/modules/cookie_store/cookie_store.cc
@@ -167,7 +167,7 @@ std::unique_ptr<net::CanonicalCookie> ToCanonicalCookie(
path.Utf8(), base::Time() /*creation*/, expires,
base::Time() /*last_access*/, true /*secure*/, false /*http_only*/,
same_site, net::CookiePriority::COOKIE_PRIORITY_DEFAULT,
- cookie_partition_key, &status_out);
+ /*same_party=*/false, cookie_partition_key, &status_out);
// TODO(crbug.com/1310444): Improve serialization validation comments and
// associate them with ExceptionState codes.