|
@@ -0,0 +1,5410 @@
|
|
|
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
|
+From: VerteDinde <[email protected]>
|
|
|
+Date: Mon, 13 Nov 2023 21:47:22 -0800
|
|
|
+Subject: fix: 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.
|
|
|
+
|
|
|
+diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
|
|
|
+index 9ab4bb62b9f7e2e74e5624ba280aec08a680df2f..dcb0de28c7d649f017246ef5d6840ef308c69c28 100644
|
|
|
+--- a/chrome/browser/about_flags.cc
|
|
|
++++ b/chrome/browser/about_flags.cc
|
|
|
+@@ -9001,6 +9001,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.cc b/chrome/browser/chrome_content_browser_client.cc
|
|
|
+index eb7b5332f5e4c70e14b2816dbb662d35e7016e05..87e26b19c4ed16132813899b5c0cb282d1cf74fb 100644
|
|
|
+--- a/chrome/browser/chrome_content_browser_client.cc
|
|
|
++++ b/chrome/browser/chrome_content_browser_client.cc
|
|
|
+@@ -7897,8 +7897,7 @@ bool ChromeContentBrowserClient::ShouldDisableOriginAgentClusterDefault(
|
|
|
+
|
|
|
+ bool ChromeContentBrowserClient::WillProvidePublicFirstPartySets() {
|
|
|
+ #if BUILDFLAG(ENABLE_COMPONENT_UPDATER)
|
|
|
+- return !is_minimal_mode_ &&
|
|
|
+- !base::CommandLine::ForCurrentProcess()->HasSwitch(
|
|
|
++ return !base::CommandLine::ForCurrentProcess()->HasSwitch(
|
|
|
+ switches::kDisableComponentUpdate) &&
|
|
|
+ base::FeatureList::IsEnabled(features::kFirstPartySets);
|
|
|
+ #else
|
|
|
+@@ -8195,10 +8194,6 @@ bool ChromeContentBrowserClient::
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+-void ChromeContentBrowserClient::SetIsMinimalMode(bool minimal) {
|
|
|
+- is_minimal_mode_ = minimal;
|
|
|
+-}
|
|
|
+-
|
|
|
+ #if !BUILDFLAG(IS_ANDROID)
|
|
|
+ void ChromeContentBrowserClient::BindVideoEffectsManager(
|
|
|
+ const std::string& device_id,
|
|
|
+diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
|
|
|
+index d3451e33c645abebd1a38c633e16543a82a29a58..fae1e57305b861abf97bad15123801be9ee71bc2 100644
|
|
|
+--- a/chrome/browser/chrome_content_browser_client.h
|
|
|
++++ b/chrome/browser/chrome_content_browser_client.h
|
|
|
+@@ -952,8 +952,6 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
|
|
|
+ bool ShouldAllowBackForwardCacheForCacheControlNoStorePage(
|
|
|
+ content::BrowserContext* browser_context) override;
|
|
|
+
|
|
|
+- void SetIsMinimalMode(bool minimal) override;
|
|
|
+-
|
|
|
+ #if !BUILDFLAG(IS_ANDROID)
|
|
|
+ void BindVideoEffectsManager(
|
|
|
+ const std::string& device_id,
|
|
|
+@@ -1116,10 +1114,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 af69cae172317e657ed069b4fb65162919d9f2d3..b0d202ff7047cc57644e675c46f48d4f5c9465c0 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");
|
|
|
+@@ -155,8 +155,8 @@ void FirstPartySetsComponentInstallerPolicy::ComponentReady(
|
|
|
+ if (install_dir.empty() || GetConfigPathInstance().has_value())
|
|
|
+ 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);
|
|
|
+@@ -200,12 +200,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/first_party_sets/first_party_sets_policy_service.cc b/chrome/browser/first_party_sets/first_party_sets_policy_service.cc
|
|
|
+index 869638cc9700b7253d574bf7075bd48d7539082a..12589a819c216213ea237f2ff397569420e2cbec 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
|
|
|
+@@ -131,6 +131,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()) {
|
|
|
+@@ -142,17 +143,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 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());
|
|
|
+@@ -163,7 +165,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 9bc786819114dc1f12e590afa3323f067c785fad..4a1915904119bd2b0a7027ffd5046404123a0311 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
|
|
|
+@@ -50,6 +50,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
|
|
|
+@@ -168,6 +169,7 @@ class FirstPartySetsPolicyService : public KeyedService {
|
|
|
+ void ComputeFirstPartySetMetadataInternal(
|
|
|
+ const net::SchemefulSite& 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 895098c0bd46209a030a4be5f15509f6081859b9..f603f9a34aea1229f568aea1ebd0a1a9675fb64b 100644
|
|
|
+--- a/chrome/browser/flag-metadata.json
|
|
|
++++ b/chrome/browser/flag-metadata.json
|
|
|
+@@ -2672,6 +2672,11 @@
|
|
|
+ "owners": [ "[email protected]", "[email protected]" ],
|
|
|
+ "expiry_milestone": 130
|
|
|
+ },
|
|
|
++ {
|
|
|
++ "name": "enable-first-party-sets",
|
|
|
++ "owners": [ "[email protected]" ],
|
|
|
++ "expiry_milestone": 120
|
|
|
++ },
|
|
|
+ {
|
|
|
+ "name": "enable-follow-IPH-exp-params",
|
|
|
+ "owners": [ "[email protected]", "[email protected]" ],
|
|
|
+diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
|
|
|
+index 0d17970001d18960ee11fba6b3a5cd0ab275994b..6cdc7d1d1e1d5e9d1577172152869d673935b9a3 100644
|
|
|
+--- a/chrome/browser/flag_descriptions.cc
|
|
|
++++ b/chrome/browser/flag_descriptions.cc
|
|
|
+@@ -386,6 +386,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 kSHA1ServerSignatureName[] = "Allow SHA-1 server signatures in TLS.";
|
|
|
+ const char kSHA1ServerSignatureDescription[] =
|
|
|
+ "When enabled, Chrome will allow the use of SHA-1 in signatures from the "
|
|
|
+diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
|
|
|
+index 64e4e09d02a1dbb7bf017cb07b5a065a39f449d7..499ce1f77019e775120b34e00e01f95c5609001c 100644
|
|
|
+--- a/chrome/browser/flag_descriptions.h
|
|
|
++++ b/chrome/browser/flag_descriptions.h
|
|
|
+@@ -506,6 +506,9 @@ extern const char kUseDnsHttpsSvcbAlpnDescription[];
|
|
|
+ extern const char kEditContextName[];
|
|
|
+ extern const char kEditContextDescription[];
|
|
|
+
|
|
|
++extern const char kEnableFirstPartySetsName[];
|
|
|
++extern const char kEnableFirstPartySetsDescription[];
|
|
|
++
|
|
|
+ extern const char kSHA1ServerSignatureName[];
|
|
|
+ extern const char kSHA1ServerSignatureDescription[];
|
|
|
+
|
|
|
+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 ce5b56d772a81eb8cbad354bf53c8b53c459239f..be3f50d95024d1ef84857d047f0b1208710e72da 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
|
|
|
+@@ -298,7 +298,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 e004114e17b2b8f6ca80c6e1e8711c6d1b15264b..7f157bd3fb974d711ba22fe211c9b2d33a4720e0 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
|
|
|
+@@ -94,7 +94,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/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc
|
|
|
+index 5b6c92952de30bb9a80b9595ab57344323484eea..caa5767ca6d042022c562006629d19dc8c3fdaac 100644
|
|
|
+--- a/content/app/content_main_runner_impl.cc
|
|
|
++++ b/content/app/content_main_runner_impl.cc
|
|
|
+@@ -60,8 +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/first_party_sets/local_set_declaration.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"
|
|
|
+@@ -1256,14 +1254,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(), LocalSetDeclaration());
|
|
|
+- }
|
|
|
+
|
|
|
+ discardable_shared_memory_manager_ =
|
|
|
+ std::make_unique<discardable_memory::DiscardableSharedMemoryManager>();
|
|
|
+diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
|
|
|
+index 0757d84fc6da0be30d2497dae36b0170a33808f7..713190fa1b037df00c2f5e9761572873ea1a3538 100644
|
|
|
+--- a/content/browser/BUILD.gn
|
|
|
++++ b/content/browser/BUILD.gn
|
|
|
+@@ -999,9 +999,8 @@ 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_site_data_remover.cc",
|
|
|
+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/first_party_sets/first_party_sets_handler_impl_instance.cc b/content/browser/first_party_sets/first_party_sets_handler_impl.cc
|
|
|
+similarity index 75%
|
|
|
+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 0855f5f8d6d092de96e6b1dc7c2e49402351ea5b..caae433e3d14eae35c73873c6a1fcab74d3dcb2e 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 <string>
|
|
|
+@@ -18,7 +18,6 @@
|
|
|
+ #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_site_data_remover.h"
|
|
|
+ #include "content/browser/first_party_sets/local_set_declaration.h"
|
|
|
+@@ -79,16 +78,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) {
|
|
|
+@@ -113,19 +111,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;
|
|
|
+ }
|
|
|
+@@ -138,49 +134,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) {}
|
|
|
+
|
|
|
+-absl::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)));
|
|
|
+ }
|
|
|
+@@ -188,33 +192,35 @@ FirstPartySetsHandlerImplInstance::GetSets(
|
|
|
+ return absl::nullopt;
|
|
|
+ }
|
|
|
+
|
|
|
+-void FirstPartySetsHandlerImplInstance::Init(
|
|
|
+- const base::FilePath& user_data_dir,
|
|
|
+- const 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;
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -222,7 +228,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(absl::optional<std::pair<net::GlobalFirstPartySets,
|
|
|
+@@ -241,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(absl::optional<bool>)> callback) {
|
|
|
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
|
+@@ -257,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());
|
|
|
+@@ -282,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());
|
|
|
+@@ -315,11 +318,9 @@ void FirstPartySetsHandlerImplInstance::InvokePendingQueries() {
|
|
|
+ queue.pop_front();
|
|
|
+ std::move(callback).Run();
|
|
|
+ }
|
|
|
+- on_sets_ready_callbacks_.reset();
|
|
|
+ }
|
|
|
+
|
|
|
+-absl::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 +331,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 +360,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 +392,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 +406,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 +432,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 +470,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 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 +505,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 absl::optional<base::ElapsedTimer>& timer) const {
|
|
|
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
|
+@@ -522,22 +521,16 @@ FirstPartySetsHandlerImplInstance::GetContextConfigForPolicyInternal(
|
|
|
+ timer->Elapsed());
|
|
|
+ }
|
|
|
+
|
|
|
+- if (!enabled_) {
|
|
|
+- return net::FirstPartySetsContextConfig();
|
|
|
+- }
|
|
|
+-
|
|
|
+ auto [parsed, warnings] =
|
|
|
+ FirstPartySetParser::ParseSetsFromEnterprisePolicy(policy);
|
|
|
+
|
|
|
+ return parsed.has_value()
|
|
|
+- ? global_sets_.value().ComputeConfig(
|
|
|
+- /*replacement_sets=*/parsed.value().replacements,
|
|
|
+- /*addition_sets=*/
|
|
|
+- parsed.value().additions)
|
|
|
++ ? 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 9696bbb0281be8502c78d19de3ca7b9090f8771c..aec4e931eb4e21a660577432d12488c1316e2f2c 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
|
|
|
+@@ -5,25 +5,64 @@
|
|
|
+ #ifndef CONTENT_BROWSER_FIRST_PARTY_SETS_FIRST_PARTY_SETS_HANDLER_IMPL_H_
|
|
|
+ #define CONTENT_BROWSER_FIRST_PARTY_SETS_FIRST_PARTY_SETS_HANDLER_IMPL_H_
|
|
|
+
|
|
|
++#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 "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).
|
|
|
+@@ -32,9 +71,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 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 absl::optional if it's already
|
|
|
+@@ -49,7 +93,163 @@ class CONTENT_EXPORT FirstPartySetsHandlerImpl : public FirstPartySetsHandler {
|
|
|
+ // If First-Party Sets is disabled, this returns a populated optional with an
|
|
|
+ // empty GlobalFirstPartySets instance.
|
|
|
+ [[nodiscard]] virtual absl::optional<net::GlobalFirstPartySets> GetSets(
|
|
|
+- base::OnceCallback<void(net::GlobalFirstPartySets)> callback) = 0;
|
|
|
++ 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
|
|
|
+deleted file mode 100644
|
|
|
+index a4f5090c8dfffdb8fca5e1e99862b4fa29134557..0000000000000000000000000000000000000000
|
|
|
+--- a/content/browser/first_party_sets/first_party_sets_handler_impl_instance.h
|
|
|
++++ /dev/null
|
|
|
+@@ -1,221 +0,0 @@
|
|
|
+-// Copyright 2023 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_FIRST_PARTY_SETS_HANDLER_IMPL_INSTANCE_H_
|
|
|
+-#define CONTENT_BROWSER_FIRST_PARTY_SETS_FIRST_PARTY_SETS_HANDLER_IMPL_INSTANCE_H_
|
|
|
+-
|
|
|
+-#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/values.h"
|
|
|
+-#include "base/version.h"
|
|
|
+-#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 "third_party/abseil-cpp/absl/types/optional.h"
|
|
|
+-
|
|
|
+-namespace net {
|
|
|
+-class FirstPartySetEntry;
|
|
|
+-class SchemefulSite;
|
|
|
+-} // namespace net
|
|
|
+-
|
|
|
+-namespace content {
|
|
|
+-
|
|
|
+-class BrowserContext;
|
|
|
+-
|
|
|
+-// Class FirstPartySetsHandlerImplInstance 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 FirstPartySetsHandlerImplInstance
|
|
|
+- : public FirstPartySetsHandlerImpl {
|
|
|
+- public:
|
|
|
+- ~FirstPartySetsHandlerImplInstance() override;
|
|
|
+-
|
|
|
+- FirstPartySetsHandlerImplInstance(const FirstPartySetsHandlerImplInstance&) =
|
|
|
+- delete;
|
|
|
+- FirstPartySetsHandlerImplInstance& operator=(
|
|
|
+- const FirstPartySetsHandlerImplInstance&) = delete;
|
|
|
+-
|
|
|
+- // Factory method that exposes the ctor for testing.
|
|
|
+- static FirstPartySetsHandlerImplInstance CreateForTesting(
|
|
|
+- bool enabled,
|
|
|
+- bool embedder_will_provide_public_sets);
|
|
|
+-
|
|
|
+- // FirstPartySetsHandlerImpl:
|
|
|
+- void Init(const base::FilePath& user_data_dir,
|
|
|
+- const LocalSetDeclaration& local_set) override;
|
|
|
+- [[nodiscard]] absl::optional<net::GlobalFirstPartySets> GetSets(
|
|
|
+- base::OnceCallback<void(net::GlobalFirstPartySets)> callback) override;
|
|
|
+-
|
|
|
+- // 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 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
|
|
|
+- }
|
|
|
+-
|
|
|
+- private:
|
|
|
+- friend class base::NoDestructor<FirstPartySetsHandlerImplInstance>;
|
|
|
+-
|
|
|
+- FirstPartySetsHandlerImplInstance(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 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_);
|
|
|
+-
|
|
|
+- // Whether the First-Party Sets feature should behave as "enabled" or not,
|
|
|
+- // according to the embedder.
|
|
|
+- const bool enabled_ GUARDED_BY_CONTEXT(sequence_checker_);
|
|
|
+-
|
|
|
+- // A queue of tasks waiting to run once this instance has the full
|
|
|
+- // GlobalFirstPartySets instance. If `enabled_` is true, then this queue is
|
|
|
+- // non-null until `global_sets_` is non-nullopt. Otherwise, it is always
|
|
|
+- // nullptr.
|
|
|
+- std::unique_ptr<base::circular_deque<base::OnceClosure>>
|
|
|
+- on_sets_ready_callbacks_ GUARDED_BY_CONTEXT(sequence_checker_);
|
|
|
+-
|
|
|
+- // A helper object to handle loading and combining First-Party Sets from
|
|
|
+- // different sources (i.e. the command-line flag and the list provided by the
|
|
|
+- // embedder). This is nullptr if `enabled_` is false; and it is nullptr after
|
|
|
+- // `global_sets_` has been set.
|
|
|
+- 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
|
|
|
+-
|
|
|
+-#endif // CONTENT_BROWSER_FIRST_PARTY_SETS_FIRST_PARTY_SETS_HANDLER_IMPL_H_
|
|
|
+diff --git a/content/browser/first_party_sets/first_party_sets_handler_impl_instance_unittest.cc b/content/browser/first_party_sets/first_party_sets_handler_impl_instance_unittest.cc
|
|
|
+deleted file mode 100644
|
|
|
+index 41c4400326de46d2fe623aa58c8495c50aff76e7..0000000000000000000000000000000000000000
|
|
|
+--- a/content/browser/first_party_sets/first_party_sets_handler_impl_instance_unittest.cc
|
|
|
++++ /dev/null
|
|
|
+@@ -1,925 +0,0 @@
|
|
|
+-// Copyright 2023 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 <string>
|
|
|
+-#include <utility>
|
|
|
+-#include <vector>
|
|
|
+-
|
|
|
+-#include "base/files/file_path.h"
|
|
|
+-#include "base/files/file_util.h"
|
|
|
+-#include "base/files/scoped_temp_dir.h"
|
|
|
+-#include "base/functional/callback_helpers.h"
|
|
|
+-#include "base/json/json_reader.h"
|
|
|
+-#include "base/notreached.h"
|
|
|
+-#include "base/run_loop.h"
|
|
|
+-#include "base/test/bind.h"
|
|
|
+-#include "base/test/gmock_expected_support.h"
|
|
|
+-#include "base/test/metrics/histogram_tester.h"
|
|
|
+-#include "base/test/scoped_feature_list.h"
|
|
|
+-#include "base/test/task_environment.h"
|
|
|
+-#include "base/test/test_future.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 "content/public/browser/first_party_sets_handler.h"
|
|
|
+-#include "content/public/common/content_features.h"
|
|
|
+-#include "content/public/test/browser_task_environment.h"
|
|
|
+-#include "content/public/test/test_browser_context.h"
|
|
|
+-#include "net/base/schemeful_site.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/first_party_sets_context_config.h"
|
|
|
+-#include "net/first_party_sets/global_first_party_sets.h"
|
|
|
+-#include "testing/gmock/include/gmock/gmock-matchers.h"
|
|
|
+-#include "testing/gmock/include/gmock/gmock.h"
|
|
|
+-#include "testing/gtest/include/gtest/gtest.h"
|
|
|
+-#include "third_party/abseil-cpp/absl/types/optional.h"
|
|
|
+-#include "url/gurl.h"
|
|
|
+-
|
|
|
+-using ::testing::_;
|
|
|
+-using ::testing::Eq;
|
|
|
+-using ::testing::IsEmpty;
|
|
|
+-using ::testing::Not;
|
|
|
+-using ::testing::Optional;
|
|
|
+-using ::testing::Pair;
|
|
|
+-using ::testing::SizeIs;
|
|
|
+-using ::testing::UnorderedElementsAre;
|
|
|
+-
|
|
|
+-// Some of these tests overlap with FirstPartySetParser unittests, but
|
|
|
+-// overlapping test coverage isn't the worst thing.
|
|
|
+-namespace content {
|
|
|
+-
|
|
|
+-namespace {
|
|
|
+-
|
|
|
+-using ParseErrorType = FirstPartySetsHandler::ParseErrorType;
|
|
|
+-using ParseWarningType = FirstPartySetsHandler::ParseWarningType;
|
|
|
+-
|
|
|
+-constexpr char kAdditionsField[] = "additions";
|
|
|
+-constexpr char kPrimaryField[] = "primary";
|
|
|
+-constexpr char kCctldsField[] = "ccTLDs";
|
|
|
+-
|
|
|
+-constexpr char kFirstPartySetsClearSiteDataOutcomeHistogram[] =
|
|
|
+- "FirstPartySets.Initialization.ClearSiteDataOutcome";
|
|
|
+-
|
|
|
+-constexpr char kDelayedQueriesCountHistogram[] =
|
|
|
+- "Cookie.FirstPartySets.Browser.DelayedQueriesCount";
|
|
|
+-constexpr char kMostDelayedQueryDeltaHistogram[] =
|
|
|
+- "Cookie.FirstPartySets.Browser.MostDelayedQueryDelta";
|
|
|
+-
|
|
|
+-} // namespace
|
|
|
+-
|
|
|
+-TEST(FirstPartySetsHandlerImplInstance, ValidateEnterprisePolicy_ValidPolicy) {
|
|
|
+- base::Value input = base::JSONReader::Read(R"(
|
|
|
+- {
|
|
|
+- "replacements": [
|
|
|
+- {
|
|
|
+- "primary": "https://primary1.test",
|
|
|
+- "associatedSites": ["https://associatedsite1.test"]
|
|
|
+- }
|
|
|
+- ],
|
|
|
+- "additions": [
|
|
|
+- {
|
|
|
+- "primary": "https://primary2.test",
|
|
|
+- "associatedSites": ["https://associatedsite2.test"]
|
|
|
+- }
|
|
|
+- ]
|
|
|
+- }
|
|
|
+- )")
|
|
|
+- .value();
|
|
|
+- // Validation doesn't fail with an error and there are no warnings to output.
|
|
|
+- auto [success, warnings] =
|
|
|
+- FirstPartySetsHandler::ValidateEnterprisePolicy(input.GetDict());
|
|
|
+- EXPECT_TRUE(success.has_value());
|
|
|
+- EXPECT_THAT(warnings, IsEmpty());
|
|
|
+-}
|
|
|
+-
|
|
|
+-TEST(FirstPartySetsHandlerImplInstance,
|
|
|
+- ValidateEnterprisePolicy_ValidPolicyWithWarnings) {
|
|
|
+- // Some input that matches our policies schema but returns non-fatal warnings.
|
|
|
+- base::Value input = base::JSONReader::Read(R"(
|
|
|
+- {
|
|
|
+- "replacements": [],
|
|
|
+- "additions": [
|
|
|
+- {
|
|
|
+- "primary": "https://primary1.test",
|
|
|
+- "associatedSites": ["https://associatedsite1.test"],
|
|
|
+- "ccTLDs": {
|
|
|
+- "https://non-canonical.test": ["https://primary1.test"]
|
|
|
+- }
|
|
|
+- }
|
|
|
+- ]
|
|
|
+- }
|
|
|
+- )")
|
|
|
+- .value();
|
|
|
+- // Validation succeeds without errors.
|
|
|
+- auto [success, warnings] =
|
|
|
+- FirstPartySetsHandler::ValidateEnterprisePolicy(input.GetDict());
|
|
|
+- EXPECT_TRUE(success.has_value());
|
|
|
+- // Outputs metadata that can be used to surface a descriptive warning.
|
|
|
+- EXPECT_THAT(
|
|
|
+- warnings,
|
|
|
+- UnorderedElementsAre(FirstPartySetsHandler::ParseWarning(
|
|
|
+- ParseWarningType::kCctldKeyNotCanonical,
|
|
|
+- {kAdditionsField, 0, kCctldsField, "https://non-canonical.test"})));
|
|
|
+-}
|
|
|
+-
|
|
|
+-TEST(FirstPartySetsHandlerImplInstance,
|
|
|
+- ValidateEnterprisePolicy_InvalidPolicy) {
|
|
|
+- // Some input that matches our policies schema but breaks FPS invariants.
|
|
|
+- // For more test coverage, see the ParseSetsFromEnterprisePolicy unit tests.
|
|
|
+- base::Value input = base::JSONReader::Read(R"(
|
|
|
+- {
|
|
|
+- "replacements": [
|
|
|
+- {
|
|
|
+- "primary": "https://primary1.test",
|
|
|
+- "associatedSites": ["https://associatedsite1.test"]
|
|
|
+- }
|
|
|
+- ],
|
|
|
+- "additions": [
|
|
|
+- {
|
|
|
+- "primary": "https://primary1.test",
|
|
|
+- "associatedSites": ["https://associatedsite2.test"]
|
|
|
+- }
|
|
|
+- ]
|
|
|
+- }
|
|
|
+- )")
|
|
|
+- .value();
|
|
|
+- // Validation fails with an error and an appropriate ParseError is returned.
|
|
|
+- EXPECT_THAT(
|
|
|
+- FirstPartySetsHandler::ValidateEnterprisePolicy(input.GetDict()).first,
|
|
|
+- base::test::ErrorIs(FirstPartySetsHandler::ParseError(
|
|
|
+- ParseErrorType::kNonDisjointSets,
|
|
|
+- {kAdditionsField, 0, kPrimaryField})));
|
|
|
+-}
|
|
|
+-
|
|
|
+-class FirstPartySetsHandlerImplTest : public ::testing::Test {
|
|
|
+- public:
|
|
|
+- explicit FirstPartySetsHandlerImplTest(bool enabled)
|
|
|
+- : handler_(FirstPartySetsHandlerImplInstance::CreateForTesting(
|
|
|
+- /*enabled=*/enabled,
|
|
|
+- /*embedder_will_provide_public_sets=*/enabled)) {
|
|
|
+- CHECK(scoped_dir_.CreateUniqueTempDir());
|
|
|
+- CHECK(PathExists(scoped_dir_.GetPath()));
|
|
|
+- }
|
|
|
+-
|
|
|
+- base::File WritePublicSetsFile(base::StringPiece content) {
|
|
|
+- base::FilePath path =
|
|
|
+- scoped_dir_.GetPath().Append(FILE_PATH_LITERAL("sets_file.json"));
|
|
|
+- CHECK(base::WriteFile(path, content));
|
|
|
+-
|
|
|
+- return base::File(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
|
|
|
+- }
|
|
|
+-
|
|
|
+- net::GlobalFirstPartySets GetSetsAndWait(
|
|
|
+- FirstPartySetsHandlerImplInstance& handler) {
|
|
|
+- base::test::TestFuture<net::GlobalFirstPartySets> future;
|
|
|
+- absl::optional<net::GlobalFirstPartySets> result =
|
|
|
+- handler.GetSets(future.GetCallback());
|
|
|
+- return result.has_value() ? std::move(result).value() : future.Take();
|
|
|
+- }
|
|
|
+-
|
|
|
+- net::FirstPartySetsContextConfig GetContextConfigForPolicy(
|
|
|
+- const base::Value::Dict* policy) {
|
|
|
+- base::test::TestFuture<net::FirstPartySetsContextConfig> future;
|
|
|
+- handler().GetContextConfigForPolicy(policy, future.GetCallback());
|
|
|
+- return future.Take();
|
|
|
+- }
|
|
|
+-
|
|
|
+- void ClearSiteDataOnChangedSetsForContextAndWait(
|
|
|
+- FirstPartySetsHandlerImplInstance& handler,
|
|
|
+- BrowserContext* context,
|
|
|
+- const std::string& browser_context_id,
|
|
|
+- net::FirstPartySetsContextConfig context_config) {
|
|
|
+- base::RunLoop run_loop;
|
|
|
+- handler.ClearSiteDataOnChangedSetsForContext(
|
|
|
+- base::BindLambdaForTesting([&]() { return context; }),
|
|
|
+- browser_context_id, std::move(context_config),
|
|
|
+- base::BindLambdaForTesting(
|
|
|
+- [&](net::FirstPartySetsContextConfig,
|
|
|
+- net::FirstPartySetsCacheFilter) { run_loop.Quit(); }));
|
|
|
+- run_loop.Run();
|
|
|
+- }
|
|
|
+-
|
|
|
+- absl::optional<
|
|
|
+- std::pair<net::GlobalFirstPartySets, net::FirstPartySetsContextConfig>>
|
|
|
+- GetPersistedSetsAndWait(FirstPartySetsHandlerImplInstance& handler,
|
|
|
+- const std::string& browser_context_id) {
|
|
|
+- base::test::TestFuture<absl::optional<
|
|
|
+- std::pair<net::GlobalFirstPartySets, net::FirstPartySetsContextConfig>>>
|
|
|
+- future;
|
|
|
+- handler.GetPersistedSetsForTesting(browser_context_id,
|
|
|
+- future.GetCallback());
|
|
|
+- return future.Take();
|
|
|
+- }
|
|
|
+-
|
|
|
+- absl::optional<bool> HasEntryInBrowserContextsClearedAndWait(
|
|
|
+- FirstPartySetsHandlerImplInstance& handler,
|
|
|
+- const std::string& browser_context_id) {
|
|
|
+- base::test::TestFuture<absl::optional<bool>> future;
|
|
|
+- handler.HasBrowserContextClearedForTesting(browser_context_id,
|
|
|
+- future.GetCallback());
|
|
|
+- return future.Take();
|
|
|
+- }
|
|
|
+-
|
|
|
+- net::GlobalFirstPartySets GetSetsAndWait() {
|
|
|
+- return GetSetsAndWait(handler());
|
|
|
+- }
|
|
|
+-
|
|
|
+- void ClearSiteDataOnChangedSetsForContextAndWait(
|
|
|
+- BrowserContext* context,
|
|
|
+- const std::string& browser_context_id,
|
|
|
+- net::FirstPartySetsContextConfig context_config) {
|
|
|
+- ClearSiteDataOnChangedSetsForContextAndWait(
|
|
|
+- handler(), context, browser_context_id, std::move(context_config));
|
|
|
+- }
|
|
|
+-
|
|
|
+- absl::optional<
|
|
|
+- std::pair<net::GlobalFirstPartySets, net::FirstPartySetsContextConfig>>
|
|
|
+- GetPersistedSetsAndWait(const std::string& browser_context_id) {
|
|
|
+- return GetPersistedSetsAndWait(handler(), browser_context_id);
|
|
|
+- }
|
|
|
+-
|
|
|
+- base::HistogramTester& histogram_tester() { return histogram_tester_; }
|
|
|
+-
|
|
|
+- FirstPartySetsHandlerImplInstance& handler() { return handler_; }
|
|
|
+-
|
|
|
+- BrowserContext* context() { return &context_; }
|
|
|
+-
|
|
|
+- protected:
|
|
|
+- base::ScopedTempDir scoped_dir_;
|
|
|
+-
|
|
|
+- private:
|
|
|
+- BrowserTaskEnvironment env_;
|
|
|
+- TestBrowserContext context_;
|
|
|
+- base::HistogramTester histogram_tester_;
|
|
|
+- FirstPartySetsHandlerImplInstance handler_;
|
|
|
+-};
|
|
|
+-
|
|
|
+-class FirstPartySetsHandlerImplDisabledTest
|
|
|
+- : public FirstPartySetsHandlerImplTest {
|
|
|
+- public:
|
|
|
+- FirstPartySetsHandlerImplDisabledTest()
|
|
|
+- : FirstPartySetsHandlerImplTest(/*enabled=*/false) {}
|
|
|
+-};
|
|
|
+-
|
|
|
+-TEST_F(FirstPartySetsHandlerImplDisabledTest, InitMetrics) {
|
|
|
+- histogram_tester().ExpectTotalCount(kDelayedQueriesCountHistogram, 1);
|
|
|
+- histogram_tester().ExpectTotalCount(kMostDelayedQueryDeltaHistogram, 1);
|
|
|
+-}
|
|
|
+-
|
|
|
+-TEST_F(FirstPartySetsHandlerImplDisabledTest, InitImmediately) {
|
|
|
+- // Should already be able to answer queries, even before Init is called.
|
|
|
+- EXPECT_THAT(handler().GetSets(base::NullCallback()), Optional(_));
|
|
|
+-
|
|
|
+- EXPECT_EQ(GetContextConfigForPolicy(nullptr),
|
|
|
+- net::FirstPartySetsContextConfig());
|
|
|
+-
|
|
|
+- base::Value policy = base::JSONReader::Read(R"(
|
|
|
+- {
|
|
|
+- "replacements": [
|
|
|
+- {
|
|
|
+- "primary": "https://primary.test",
|
|
|
+- "associatedSites": ["https://associated.test"]
|
|
|
+- }
|
|
|
+- ]
|
|
|
+- }
|
|
|
+- )")
|
|
|
+- .value();
|
|
|
+- EXPECT_EQ(GetContextConfigForPolicy(&policy.GetDict()),
|
|
|
+- net::FirstPartySetsContextConfig());
|
|
|
+-
|
|
|
+- // The local set declaration should be ignored, since the handler is disabled.
|
|
|
+- handler().Init(
|
|
|
+- /*user_data_dir=*/{},
|
|
|
+- LocalSetDeclaration(
|
|
|
+- R"({"primary": "https://example.test",)"
|
|
|
+- R"("associatedSites": ["https://associatedsite1.test"]})"));
|
|
|
+-
|
|
|
+- // The public sets should be ignored, since the handler is disabled.
|
|
|
+- handler().SetPublicFirstPartySets(
|
|
|
+- base::Version("0.0.1"),
|
|
|
+- WritePublicSetsFile(
|
|
|
+- R"({"primary": "https://example.test", )"
|
|
|
+- R"("associatedSites": ["https://associatedsite2.test"]})"));
|
|
|
+-
|
|
|
+- EXPECT_THAT(GetSetsAndWait().FindEntries(
|
|
|
+- {
|
|
|
+- net::SchemefulSite(GURL("https://example.test")),
|
|
|
+- net::SchemefulSite(GURL("https://associatedsite1.test")),
|
|
|
+- net::SchemefulSite(GURL("https://associatedsite2.test")),
|
|
|
+- },
|
|
|
+- net::FirstPartySetsContextConfig()),
|
|
|
+- IsEmpty());
|
|
|
+-}
|
|
|
+-
|
|
|
+-class FirstPartySetsHandlerImplEnabledTest
|
|
|
+- : public FirstPartySetsHandlerImplTest {
|
|
|
+- public:
|
|
|
+- FirstPartySetsHandlerImplEnabledTest()
|
|
|
+- : FirstPartySetsHandlerImplTest(/*enabled=*/true) {}
|
|
|
+-};
|
|
|
+-
|
|
|
+-TEST_F(FirstPartySetsHandlerImplEnabledTest, EmptyDBPath) {
|
|
|
+- net::SchemefulSite example(GURL("https://example.test"));
|
|
|
+- net::SchemefulSite associated(GURL("https://associatedsite1.test"));
|
|
|
+-
|
|
|
+- handler().SetPublicFirstPartySets(base::Version("0.0.1"),
|
|
|
+- WritePublicSetsFile(""));
|
|
|
+-
|
|
|
+- // Empty `user_data_dir` will fail to load persisted sets, but that will not
|
|
|
+- // prevent `on_sets_ready` from being invoked.
|
|
|
+- handler().Init(
|
|
|
+- /*user_data_dir=*/{},
|
|
|
+- LocalSetDeclaration(
|
|
|
+- R"({"primary": "https://example.test",)"
|
|
|
+- R"("associatedSites": ["https://associatedsite1.test"]})"));
|
|
|
+-
|
|
|
+- EXPECT_THAT(
|
|
|
+- GetSetsAndWait().FindEntries({example, associated},
|
|
|
+- net::FirstPartySetsContextConfig()),
|
|
|
+- UnorderedElementsAre(
|
|
|
+- Pair(example, net::FirstPartySetEntry(
|
|
|
+- example, net::SiteType::kPrimary, absl::nullopt)),
|
|
|
+- Pair(associated, net::FirstPartySetEntry(
|
|
|
+- example, net::SiteType::kAssociated, 0))));
|
|
|
+-}
|
|
|
+-
|
|
|
+-TEST_F(FirstPartySetsHandlerImplEnabledTest,
|
|
|
+- ClearSiteDataOnChangedSetsForContext_FeatureNotEnabled) {
|
|
|
+- base::test::ScopedFeatureList features;
|
|
|
+- features.InitAndEnableFeatureWithParameters(
|
|
|
+- features::kFirstPartySets,
|
|
|
+- {{features::kFirstPartySetsClearSiteDataOnChangedSets.name, "false"}});
|
|
|
+- base::HistogramTester histogram;
|
|
|
+- net::SchemefulSite foo(GURL("https://foo.test"));
|
|
|
+- net::SchemefulSite associated(GURL("https://associatedsite.test"));
|
|
|
+-
|
|
|
+- const std::string browser_context_id = "profile";
|
|
|
+- const std::string input =
|
|
|
+- R"({"primary": "https://foo.test", )"
|
|
|
+- R"("associatedSites": ["https://associatedsite.test"]})";
|
|
|
+- ASSERT_TRUE(base::JSONReader::Read(input));
|
|
|
+- handler().SetPublicFirstPartySets(base::Version("0.0.1"),
|
|
|
+- WritePublicSetsFile(input));
|
|
|
+-
|
|
|
+- handler().Init(scoped_dir_.GetPath(), LocalSetDeclaration());
|
|
|
+- ASSERT_THAT(GetSetsAndWait().FindEntries({foo, associated},
|
|
|
+- net::FirstPartySetsContextConfig()),
|
|
|
+- UnorderedElementsAre(
|
|
|
+- Pair(foo, net::FirstPartySetEntry(
|
|
|
+- foo, net::SiteType::kPrimary, absl::nullopt)),
|
|
|
+- Pair(associated, net::FirstPartySetEntry(
|
|
|
+- foo, net::SiteType::kAssociated, 0))));
|
|
|
+-
|
|
|
+- histogram.ExpectTotalCount(kDelayedQueriesCountHistogram, 1);
|
|
|
+- histogram.ExpectTotalCount(kMostDelayedQueryDeltaHistogram, 1);
|
|
|
+-
|
|
|
+- ClearSiteDataOnChangedSetsForContextAndWait(
|
|
|
+- context(), browser_context_id, net::FirstPartySetsContextConfig());
|
|
|
+-
|
|
|
+- absl::optional<
|
|
|
+- std::pair<net::GlobalFirstPartySets, net::FirstPartySetsContextConfig>>
|
|
|
+- persisted = GetPersistedSetsAndWait(browser_context_id);
|
|
|
+- EXPECT_TRUE(persisted.has_value());
|
|
|
+- EXPECT_THAT(
|
|
|
+- persisted->first.FindEntries({foo, associated}, persisted->second),
|
|
|
+- IsEmpty());
|
|
|
+- // Should not be recorded.
|
|
|
+- histogram.ExpectTotalCount(kFirstPartySetsClearSiteDataOutcomeHistogram, 0);
|
|
|
+-}
|
|
|
+-
|
|
|
+-TEST_F(FirstPartySetsHandlerImplEnabledTest,
|
|
|
+- ClearSiteDataOnChangedSetsForContext_ManualSet_Successful) {
|
|
|
+- base::test::ScopedFeatureList features;
|
|
|
+- features.InitAndEnableFeatureWithParameters(
|
|
|
+- features::kFirstPartySets,
|
|
|
+- {{features::kFirstPartySetsClearSiteDataOnChangedSets.name, "true"}});
|
|
|
+-
|
|
|
+- net::SchemefulSite foo(GURL("https://foo.test"));
|
|
|
+- net::SchemefulSite associated(GURL("https://associatedsite.test"));
|
|
|
+- net::SchemefulSite associated2(GURL("https://associatedsite2.test"));
|
|
|
+-
|
|
|
+- const std::string browser_context_id = "profile";
|
|
|
+-
|
|
|
+- base::HistogramTester histogram;
|
|
|
+- FirstPartySetsHandlerImplInstance handler =
|
|
|
+- FirstPartySetsHandlerImplInstance::CreateForTesting(true, false);
|
|
|
+- const std::string input =
|
|
|
+- R"({"primary": "https://foo.test", )"
|
|
|
+- R"("associatedSites": ["https://associatedsite.test"]})";
|
|
|
+- ASSERT_TRUE(base::JSONReader::Read(input));
|
|
|
+-
|
|
|
+- handler.Init(scoped_dir_.GetPath(), LocalSetDeclaration(input));
|
|
|
+-
|
|
|
+- // Should not yet be recorded.
|
|
|
+- histogram.ExpectTotalCount(kFirstPartySetsClearSiteDataOutcomeHistogram, 0);
|
|
|
+- ClearSiteDataOnChangedSetsForContextAndWait(
|
|
|
+- handler, context(), browser_context_id,
|
|
|
+- net::FirstPartySetsContextConfig());
|
|
|
+-
|
|
|
+- absl::optional<
|
|
|
+- std::pair<net::GlobalFirstPartySets, net::FirstPartySetsContextConfig>>
|
|
|
+- persisted = GetPersistedSetsAndWait(handler, browser_context_id);
|
|
|
+- EXPECT_TRUE(persisted.has_value());
|
|
|
+- EXPECT_THAT(
|
|
|
+- persisted->first.FindEntries({foo, associated}, persisted->second),
|
|
|
+- UnorderedElementsAre(
|
|
|
+- Pair(foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary,
|
|
|
+- absl::nullopt)),
|
|
|
+- Pair(associated,
|
|
|
+- net::FirstPartySetEntry(foo, net::SiteType::kAssociated,
|
|
|
+- absl::nullopt))));
|
|
|
+- histogram.ExpectUniqueSample(kFirstPartySetsClearSiteDataOutcomeHistogram,
|
|
|
+- /*sample=*/true, 1);
|
|
|
+- histogram.ExpectTotalCount(kDelayedQueriesCountHistogram, 1);
|
|
|
+- histogram.ExpectTotalCount(kMostDelayedQueryDeltaHistogram, 1);
|
|
|
+-}
|
|
|
+-
|
|
|
+-TEST_F(FirstPartySetsHandlerImplEnabledTest,
|
|
|
+- ClearSiteDataOnChangedSetsForContext_PublicSetsWithDiff_Successful) {
|
|
|
+- base::test::ScopedFeatureList features;
|
|
|
+- features.InitAndEnableFeatureWithParameters(
|
|
|
+- features::kFirstPartySets,
|
|
|
+- {{features::kFirstPartySetsClearSiteDataOnChangedSets.name, "true"}});
|
|
|
+-
|
|
|
+- net::SchemefulSite foo(GURL("https://foo.test"));
|
|
|
+- net::SchemefulSite associated(GURL("https://associatedsite.test"));
|
|
|
+- net::SchemefulSite associated2(GURL("https://associatedsite2.test"));
|
|
|
+-
|
|
|
+- const std::string browser_context_id = "profile";
|
|
|
+-
|
|
|
+- {
|
|
|
+- base::HistogramTester histogram;
|
|
|
+- FirstPartySetsHandlerImplInstance handler =
|
|
|
+- FirstPartySetsHandlerImplInstance::CreateForTesting(true, true);
|
|
|
+- const std::string input =
|
|
|
+- R"({"primary": "https://foo.test", )"
|
|
|
+- R"("associatedSites": ["https://associatedsite.test"]})";
|
|
|
+- ASSERT_TRUE(base::JSONReader::Read(input));
|
|
|
+- handler.SetPublicFirstPartySets(base::Version("0.0.1"),
|
|
|
+- WritePublicSetsFile(input));
|
|
|
+-
|
|
|
+- handler.Init(scoped_dir_.GetPath(), LocalSetDeclaration());
|
|
|
+-
|
|
|
+- EXPECT_THAT(
|
|
|
+- HasEntryInBrowserContextsClearedAndWait(handler, browser_context_id),
|
|
|
+- Optional(false));
|
|
|
+-
|
|
|
+- // Should not yet be recorded.
|
|
|
+- histogram.ExpectTotalCount(kFirstPartySetsClearSiteDataOutcomeHistogram, 0);
|
|
|
+- ClearSiteDataOnChangedSetsForContextAndWait(
|
|
|
+- handler, context(), browser_context_id,
|
|
|
+- net::FirstPartySetsContextConfig());
|
|
|
+- absl::optional<
|
|
|
+- std::pair<net::GlobalFirstPartySets, net::FirstPartySetsContextConfig>>
|
|
|
+- persisted = GetPersistedSetsAndWait(handler, browser_context_id);
|
|
|
+- EXPECT_TRUE(persisted.has_value());
|
|
|
+- EXPECT_THAT(
|
|
|
+- persisted->first.FindEntries({foo, associated}, persisted->second),
|
|
|
+- UnorderedElementsAre(
|
|
|
+- Pair(foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary,
|
|
|
+- absl::nullopt)),
|
|
|
+- Pair(associated,
|
|
|
+- net::FirstPartySetEntry(foo, net::SiteType::kAssociated,
|
|
|
+- absl::nullopt))));
|
|
|
+- EXPECT_THAT(
|
|
|
+- HasEntryInBrowserContextsClearedAndWait(handler, browser_context_id),
|
|
|
+- Optional(true));
|
|
|
+-
|
|
|
+- histogram.ExpectUniqueSample(kFirstPartySetsClearSiteDataOutcomeHistogram,
|
|
|
+- /*sample=*/true, 1);
|
|
|
+-
|
|
|
+- // Make sure the database is closed properly before being opened again.
|
|
|
+- handler.SynchronouslyResetDBHelperForTesting();
|
|
|
+- }
|
|
|
+-
|
|
|
+- // Verify FPS transition clearing is working for non-empty sites-to-clear
|
|
|
+- // list.
|
|
|
+- {
|
|
|
+- base::HistogramTester histogram;
|
|
|
+- FirstPartySetsHandlerImplInstance handler =
|
|
|
+- FirstPartySetsHandlerImplInstance::CreateForTesting(true, true);
|
|
|
+- const std::string input =
|
|
|
+- R"({"primary": "https://foo.test", )"
|
|
|
+- R"("associatedSites": ["https://associatedsite2.test"]})";
|
|
|
+- ASSERT_TRUE(base::JSONReader::Read(input));
|
|
|
+- // The new public sets need to be associated with a different version.
|
|
|
+- handler.SetPublicFirstPartySets(base::Version("0.0.2"),
|
|
|
+- WritePublicSetsFile(input));
|
|
|
+-
|
|
|
+- handler.Init(scoped_dir_.GetPath(), LocalSetDeclaration());
|
|
|
+-
|
|
|
+- // Should not yet be recorded.
|
|
|
+- histogram.ExpectTotalCount(kFirstPartySetsClearSiteDataOutcomeHistogram, 0);
|
|
|
+- ClearSiteDataOnChangedSetsForContextAndWait(
|
|
|
+- handler, context(), browser_context_id,
|
|
|
+- net::FirstPartySetsContextConfig());
|
|
|
+- absl::optional<
|
|
|
+- std::pair<net::GlobalFirstPartySets, net::FirstPartySetsContextConfig>>
|
|
|
+- persisted = GetPersistedSetsAndWait(handler, browser_context_id);
|
|
|
+- EXPECT_TRUE(persisted.has_value());
|
|
|
+- EXPECT_THAT(
|
|
|
+- persisted->first.FindEntries({foo, associated2}, persisted->second),
|
|
|
+- UnorderedElementsAre(
|
|
|
+- Pair(foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary,
|
|
|
+- absl::nullopt)),
|
|
|
+- Pair(associated2,
|
|
|
+- net::FirstPartySetEntry(foo, net::SiteType::kAssociated,
|
|
|
+- absl::nullopt))));
|
|
|
+- EXPECT_THAT(
|
|
|
+- HasEntryInBrowserContextsClearedAndWait(handler, browser_context_id),
|
|
|
+- Optional(true));
|
|
|
+-
|
|
|
+- histogram.ExpectUniqueSample(kFirstPartySetsClearSiteDataOutcomeHistogram,
|
|
|
+- /*sample=*/true, 1);
|
|
|
+- }
|
|
|
+-}
|
|
|
+-
|
|
|
+-TEST_F(FirstPartySetsHandlerImplEnabledTest,
|
|
|
+- ClearSiteDataOnChangedSetsForContext_EmptyDBPath) {
|
|
|
+- base::test::ScopedFeatureList features;
|
|
|
+- features.InitAndEnableFeatureWithParameters(
|
|
|
+- features::kFirstPartySets,
|
|
|
+- {{features::kFirstPartySetsClearSiteDataOnChangedSets.name, "true"}});
|
|
|
+-
|
|
|
+- base::HistogramTester histogram;
|
|
|
+- net::SchemefulSite foo(GURL("https://foo.test"));
|
|
|
+- net::SchemefulSite associated(GURL("https://associatedsite.test"));
|
|
|
+-
|
|
|
+- const std::string browser_context_id = "profile";
|
|
|
+- const std::string input =
|
|
|
+- R"({"primary": "https://foo.test", )"
|
|
|
+- R"("associatedSites": ["https://associatedsite.test"]})";
|
|
|
+- ASSERT_TRUE(base::JSONReader::Read(input));
|
|
|
+- handler().SetPublicFirstPartySets(base::Version("0.0.1"),
|
|
|
+- WritePublicSetsFile(input));
|
|
|
+-
|
|
|
+- handler().Init(
|
|
|
+- /*user_data_dir=*/{}, LocalSetDeclaration());
|
|
|
+- ASSERT_THAT(GetSetsAndWait().FindEntries({foo, associated},
|
|
|
+- net::FirstPartySetsContextConfig()),
|
|
|
+- UnorderedElementsAre(
|
|
|
+- Pair(foo, net::FirstPartySetEntry(
|
|
|
+- foo, net::SiteType::kPrimary, absl::nullopt)),
|
|
|
+- Pair(associated, net::FirstPartySetEntry(
|
|
|
+- foo, net::SiteType::kAssociated, 0))));
|
|
|
+-
|
|
|
+- ClearSiteDataOnChangedSetsForContextAndWait(
|
|
|
+- context(), browser_context_id, net::FirstPartySetsContextConfig());
|
|
|
+-
|
|
|
+- EXPECT_EQ(GetPersistedSetsAndWait(browser_context_id), absl::nullopt);
|
|
|
+- // Should not be recorded.
|
|
|
+- histogram.ExpectTotalCount(kFirstPartySetsClearSiteDataOutcomeHistogram, 0);
|
|
|
+- histogram.ExpectTotalCount(kDelayedQueriesCountHistogram, 1);
|
|
|
+- histogram.ExpectTotalCount(kMostDelayedQueryDeltaHistogram, 1);
|
|
|
+-}
|
|
|
+-
|
|
|
+-TEST_F(FirstPartySetsHandlerImplEnabledTest,
|
|
|
+- ClearSiteDataOnChangedSetsForContext_BeforeSetsReady) {
|
|
|
+- base::test::ScopedFeatureList features;
|
|
|
+- features.InitAndEnableFeatureWithParameters(
|
|
|
+- features::kFirstPartySets,
|
|
|
+- {{features::kFirstPartySetsClearSiteDataOnChangedSets.name, "true"}});
|
|
|
+-
|
|
|
+- base::HistogramTester histogram;
|
|
|
+-
|
|
|
+- handler().Init(scoped_dir_.GetPath(), LocalSetDeclaration());
|
|
|
+-
|
|
|
+- const std::string browser_context_id = "profile";
|
|
|
+- base::test::TestFuture<net::FirstPartySetsContextConfig,
|
|
|
+- net::FirstPartySetsCacheFilter>
|
|
|
+- future;
|
|
|
+- handler().ClearSiteDataOnChangedSetsForContext(
|
|
|
+- base::BindLambdaForTesting([&]() { return context(); }),
|
|
|
+- browser_context_id, net::FirstPartySetsContextConfig(),
|
|
|
+- future.GetCallback());
|
|
|
+-
|
|
|
+- handler().SetPublicFirstPartySets(
|
|
|
+- base::Version("0.0.1"),
|
|
|
+- WritePublicSetsFile(
|
|
|
+- R"({"primary": "https://foo.test", )"
|
|
|
+- R"("associatedSites": ["https://associatedsite.test"]})"));
|
|
|
+-
|
|
|
+- EXPECT_TRUE(future.Wait());
|
|
|
+-
|
|
|
+- net::SchemefulSite foo(GURL("https://foo.test"));
|
|
|
+- net::SchemefulSite associated(GURL("https://associatedsite.test"));
|
|
|
+-
|
|
|
+- absl::optional<
|
|
|
+- std::pair<net::GlobalFirstPartySets, net::FirstPartySetsContextConfig>>
|
|
|
+- persisted = GetPersistedSetsAndWait(browser_context_id);
|
|
|
+- EXPECT_TRUE(persisted.has_value());
|
|
|
+- EXPECT_THAT(
|
|
|
+- persisted->first.FindEntries({foo, associated}, persisted->second),
|
|
|
+- UnorderedElementsAre(
|
|
|
+- Pair(foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary,
|
|
|
+- absl::nullopt)),
|
|
|
+- Pair(associated,
|
|
|
+- net::FirstPartySetEntry(foo, net::SiteType::kAssociated,
|
|
|
+- absl::nullopt))));
|
|
|
+- histogram.ExpectUniqueSample(kFirstPartySetsClearSiteDataOutcomeHistogram,
|
|
|
+- /*sample=*/true, 1);
|
|
|
+- histogram.ExpectTotalCount(kDelayedQueriesCountHistogram, 1);
|
|
|
+- histogram.ExpectTotalCount(kMostDelayedQueryDeltaHistogram, 1);
|
|
|
+-}
|
|
|
+-
|
|
|
+-TEST_F(FirstPartySetsHandlerImplEnabledTest,
|
|
|
+- GetSetsIfEnabledAndReady_AfterSetsReady) {
|
|
|
+- net::SchemefulSite example(GURL("https://example.test"));
|
|
|
+- net::SchemefulSite associated(GURL("https://associatedsite.test"));
|
|
|
+-
|
|
|
+- const std::string input =
|
|
|
+- R"({"primary": "https://example.test", )"
|
|
|
+- R"("associatedSites": ["https://associatedsite.test"]})";
|
|
|
+- ASSERT_TRUE(base::JSONReader::Read(input));
|
|
|
+- handler().SetPublicFirstPartySets(base::Version("1.2.3"),
|
|
|
+- WritePublicSetsFile(input));
|
|
|
+-
|
|
|
+- handler().Init(scoped_dir_.GetPath(), LocalSetDeclaration());
|
|
|
+-
|
|
|
+- // Wait until initialization is complete.
|
|
|
+- GetSetsAndWait();
|
|
|
+-
|
|
|
+- EXPECT_THAT(
|
|
|
+- handler()
|
|
|
+- .GetSets(base::NullCallback())
|
|
|
+- .value()
|
|
|
+- .FindEntries({example, associated},
|
|
|
+- net::FirstPartySetsContextConfig()),
|
|
|
+- UnorderedElementsAre(
|
|
|
+- Pair(example, net::FirstPartySetEntry(
|
|
|
+- example, net::SiteType::kPrimary, absl::nullopt)),
|
|
|
+- Pair(associated, net::FirstPartySetEntry(
|
|
|
+- example, net::SiteType::kAssociated, 0))));
|
|
|
+-}
|
|
|
+-
|
|
|
+-TEST_F(FirstPartySetsHandlerImplEnabledTest,
|
|
|
+- GetSetsIfEnabledAndReady_BeforeSetsReady) {
|
|
|
+- net::SchemefulSite example(GURL("https://example.test"));
|
|
|
+- net::SchemefulSite associated(GURL("https://associatedsite.test"));
|
|
|
+-
|
|
|
+- // Call GetSets before the sets are ready, and before Init has been called.
|
|
|
+- base::test::TestFuture<net::GlobalFirstPartySets> future;
|
|
|
+- EXPECT_EQ(handler().GetSets(future.GetCallback()), absl::nullopt);
|
|
|
+-
|
|
|
+- handler().Init(scoped_dir_.GetPath(), LocalSetDeclaration());
|
|
|
+-
|
|
|
+- const std::string input =
|
|
|
+- R"({"primary": "https://example.test", )"
|
|
|
+- R"("associatedSites": ["https://associatedsite.test"]})";
|
|
|
+- ASSERT_TRUE(base::JSONReader::Read(input));
|
|
|
+- handler().SetPublicFirstPartySets(base::Version("1.2.3"),
|
|
|
+- WritePublicSetsFile(input));
|
|
|
+-
|
|
|
+- EXPECT_THAT(
|
|
|
+- future.Get().FindEntries({example, associated},
|
|
|
+- net::FirstPartySetsContextConfig()),
|
|
|
+- UnorderedElementsAre(
|
|
|
+- Pair(example, net::FirstPartySetEntry(
|
|
|
+- example, net::SiteType::kPrimary, absl::nullopt)),
|
|
|
+- Pair(associated, net::FirstPartySetEntry(
|
|
|
+- example, net::SiteType::kAssociated, 0))));
|
|
|
+-
|
|
|
+- EXPECT_THAT(
|
|
|
+- handler()
|
|
|
+- .GetSets(base::NullCallback())
|
|
|
+- .value()
|
|
|
+- .FindEntries({example, associated},
|
|
|
+- net::FirstPartySetsContextConfig()),
|
|
|
+- UnorderedElementsAre(
|
|
|
+- Pair(example, net::FirstPartySetEntry(
|
|
|
+- example, net::SiteType::kPrimary, absl::nullopt)),
|
|
|
+- Pair(associated, net::FirstPartySetEntry(
|
|
|
+- example, net::SiteType::kAssociated, 0))));
|
|
|
+-}
|
|
|
+-
|
|
|
+-TEST_F(FirstPartySetsHandlerImplEnabledTest,
|
|
|
+- ComputeFirstPartySetMetadata_SynchronousResult) {
|
|
|
+- handler().Init(scoped_dir_.GetPath(), LocalSetDeclaration());
|
|
|
+-
|
|
|
+- handler().SetPublicFirstPartySets(
|
|
|
+- base::Version("1.2.3"),
|
|
|
+- WritePublicSetsFile(
|
|
|
+- R"({"primary": "https://example.test", )"
|
|
|
+- R"("associatedSites": ["https://associatedsite.test"]})"));
|
|
|
+-
|
|
|
+- // Exploit another helper to wait until the public sets file has been read.
|
|
|
+- GetSetsAndWait();
|
|
|
+-
|
|
|
+- net::SchemefulSite example(GURL("https://example.test"));
|
|
|
+- net::SchemefulSite associated(GURL("https://associatedsite.test"));
|
|
|
+-
|
|
|
+- base::test::TestFuture<net::FirstPartySetMetadata> future;
|
|
|
+- handler().ComputeFirstPartySetMetadata(example, &associated,
|
|
|
+- net::FirstPartySetsContextConfig(),
|
|
|
+- future.GetCallback());
|
|
|
+- EXPECT_TRUE(future.IsReady());
|
|
|
+- EXPECT_NE(future.Take(), net::FirstPartySetMetadata());
|
|
|
+-}
|
|
|
+-
|
|
|
+-TEST_F(FirstPartySetsHandlerImplEnabledTest,
|
|
|
+- ComputeFirstPartySetMetadata_AsynchronousResult) {
|
|
|
+- // Send query before the sets are ready.
|
|
|
+- base::test::TestFuture<net::FirstPartySetMetadata> future;
|
|
|
+- net::SchemefulSite example(GURL("https://example.test"));
|
|
|
+- net::SchemefulSite associated(GURL("https://associatedsite.test"));
|
|
|
+- handler().ComputeFirstPartySetMetadata(example, &associated,
|
|
|
+- net::FirstPartySetsContextConfig(),
|
|
|
+- future.GetCallback());
|
|
|
+- EXPECT_FALSE(future.IsReady());
|
|
|
+-
|
|
|
+- handler().Init(scoped_dir_.GetPath(), LocalSetDeclaration());
|
|
|
+-
|
|
|
+- handler().SetPublicFirstPartySets(
|
|
|
+- base::Version("1.2.3"),
|
|
|
+- WritePublicSetsFile(
|
|
|
+- R"({"primary": "https://example.test", )"
|
|
|
+- R"("associatedSites": ["https://associatedsite.test"]})"));
|
|
|
+-
|
|
|
+- EXPECT_NE(future.Get(), net::FirstPartySetMetadata());
|
|
|
+-}
|
|
|
+-
|
|
|
+-TEST_F(FirstPartySetsHandlerImplEnabledTest,
|
|
|
+- ForEachEffectiveSetEntry_BeforeSetsReady) {
|
|
|
+- net::SchemefulSite example(GURL("https://example.test"));
|
|
|
+- net::SchemefulSite associated(GURL("https://associatedsite.test"));
|
|
|
+-
|
|
|
+- // Verifies calling ForEachEffectiveSetEntry before the sets are ready returns
|
|
|
+- // false.
|
|
|
+- EXPECT_FALSE(handler().ForEachEffectiveSetEntry(
|
|
|
+- net::FirstPartySetsContextConfig(),
|
|
|
+- [&](const net::SchemefulSite& site,
|
|
|
+- const net::FirstPartySetEntry& entry) {
|
|
|
+- NOTREACHED_NORETURN();
|
|
|
+- return true;
|
|
|
+- }));
|
|
|
+-
|
|
|
+- handler().Init(scoped_dir_.GetPath(), LocalSetDeclaration());
|
|
|
+-
|
|
|
+- const std::string input =
|
|
|
+- R"({"primary": "https://example.test", )"
|
|
|
+- R"("associatedSites": ["https://associatedsite.test"]})";
|
|
|
+- ASSERT_TRUE(base::JSONReader::Read(input));
|
|
|
+- handler().SetPublicFirstPartySets(base::Version("1.2.3"),
|
|
|
+- WritePublicSetsFile(input));
|
|
|
+- // Wait for initialization is done.
|
|
|
+- GetSetsAndWait();
|
|
|
+-
|
|
|
+- std::vector<std::pair<net::SchemefulSite, net::FirstPartySetEntry>>
|
|
|
+- set_entries;
|
|
|
+- EXPECT_TRUE(handler().ForEachEffectiveSetEntry(
|
|
|
+- net::FirstPartySetsContextConfig(),
|
|
|
+- [&](const net::SchemefulSite& site,
|
|
|
+- const net::FirstPartySetEntry& entry) {
|
|
|
+- set_entries.emplace_back(site, entry);
|
|
|
+- return true;
|
|
|
+- }));
|
|
|
+- EXPECT_THAT(
|
|
|
+- set_entries,
|
|
|
+- UnorderedElementsAre(
|
|
|
+- Pair(example, net::FirstPartySetEntry(
|
|
|
+- example, net::SiteType::kPrimary, absl::nullopt)),
|
|
|
+- Pair(associated, net::FirstPartySetEntry(
|
|
|
+- example, net::SiteType::kAssociated, 0))));
|
|
|
+-}
|
|
|
+-
|
|
|
+-TEST_F(FirstPartySetsHandlerImplEnabledTest,
|
|
|
+- ForEachEffectiveSetEntry_WithNonEmptyConfig) {
|
|
|
+- net::SchemefulSite example(GURL("https://example.test"));
|
|
|
+- net::SchemefulSite associated1(GURL("https://associatedsite1.test"));
|
|
|
+- net::SchemefulSite associated2(GURL("https://associatedsite2.test"));
|
|
|
+-
|
|
|
+- handler().Init(scoped_dir_.GetPath(), LocalSetDeclaration());
|
|
|
+-
|
|
|
+- const std::string input =
|
|
|
+- R"({"primary": "https://example.test", )"
|
|
|
+- R"("associatedSites": ["https://associatedsite1.test"]})";
|
|
|
+- ASSERT_TRUE(base::JSONReader::Read(input));
|
|
|
+- handler().SetPublicFirstPartySets(base::Version("1.2.3"),
|
|
|
+- WritePublicSetsFile(input));
|
|
|
+- // Wait for initialization is done.
|
|
|
+- GetSetsAndWait();
|
|
|
+-
|
|
|
+- std::vector<std::pair<net::SchemefulSite, net::FirstPartySetEntry>>
|
|
|
+- set_entries;
|
|
|
+- // Calling ForEachEffectiveSetEntry with context config which add a new
|
|
|
+- // associated site https://associatedsite2.test to the above set.
|
|
|
+- EXPECT_TRUE(handler().ForEachEffectiveSetEntry(
|
|
|
+- net::FirstPartySetsContextConfig(
|
|
|
+- {{associated2,
|
|
|
+- net::FirstPartySetEntryOverride(net::FirstPartySetEntry(
|
|
|
+- example, net::SiteType::kAssociated, absl::nullopt))}}),
|
|
|
+- [&](const net::SchemefulSite& site,
|
|
|
+- const net::FirstPartySetEntry& entry) {
|
|
|
+- set_entries.emplace_back(site, entry);
|
|
|
+- return true;
|
|
|
+- }));
|
|
|
+- EXPECT_THAT(
|
|
|
+- set_entries,
|
|
|
+- UnorderedElementsAre(
|
|
|
+- Pair(example, net::FirstPartySetEntry(
|
|
|
+- example, net::SiteType::kPrimary, absl::nullopt)),
|
|
|
+- Pair(associated1,
|
|
|
+- net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)),
|
|
|
+- Pair(associated2,
|
|
|
+- net::FirstPartySetEntry(example, net::SiteType::kAssociated,
|
|
|
+- absl::nullopt))));
|
|
|
+-}
|
|
|
+-
|
|
|
+-class FirstPartySetsHandlerGetContextConfigForPolicyTest
|
|
|
+- : public FirstPartySetsHandlerImplEnabledTest {
|
|
|
+- public:
|
|
|
+- FirstPartySetsHandlerGetContextConfigForPolicyTest() {
|
|
|
+- handler().Init(scoped_dir_.GetPath(), LocalSetDeclaration());
|
|
|
+- }
|
|
|
+-
|
|
|
+- // Writes the public list of First-Party Sets which GetContextConfigForPolicy
|
|
|
+- // awaits.
|
|
|
+- //
|
|
|
+- // Initializes the First-Party Sets with the following relationship:
|
|
|
+- //
|
|
|
+- // [
|
|
|
+- // {
|
|
|
+- // "primary": "https://primary1.test",
|
|
|
+- // "associatedSites": ["https://associatedsite1.test",
|
|
|
+- // "https://associatedsite2.test"]
|
|
|
+- // }
|
|
|
+- // ]
|
|
|
+- void InitPublicFirstPartySets() {
|
|
|
+- net::SchemefulSite primary1(GURL("https://primary1.test"));
|
|
|
+- net::SchemefulSite associated1(GURL("https://associatedsite1.test"));
|
|
|
+- net::SchemefulSite associated2(GURL("https://associatedsite2.test"));
|
|
|
+-
|
|
|
+- const std::string input =
|
|
|
+- R"({"primary": "https://primary1.test", )"
|
|
|
+- R"("associatedSites": ["https://associatedsite1.test", "https://associatedsite2.test"]})";
|
|
|
+- ASSERT_TRUE(base::JSONReader::Read(input));
|
|
|
+- handler().SetPublicFirstPartySets(base::Version("1.2.3"),
|
|
|
+- WritePublicSetsFile(input));
|
|
|
+-
|
|
|
+- ASSERT_THAT(
|
|
|
+- GetSetsAndWait().FindEntries({primary1, associated1, associated2},
|
|
|
+- net::FirstPartySetsContextConfig()),
|
|
|
+- SizeIs(3));
|
|
|
+- }
|
|
|
+-};
|
|
|
+-
|
|
|
+-TEST_F(FirstPartySetsHandlerGetContextConfigForPolicyTest,
|
|
|
+- DefaultOverridesPolicy_DefaultContextConfigs) {
|
|
|
+- base::Value policy = base::JSONReader::Read(R"({})").value();
|
|
|
+- base::test::TestFuture<net::FirstPartySetsContextConfig> future;
|
|
|
+- handler().GetContextConfigForPolicy(&policy.GetDict(), future.GetCallback());
|
|
|
+-
|
|
|
+- InitPublicFirstPartySets();
|
|
|
+- EXPECT_EQ(future.Take(), net::FirstPartySetsContextConfig());
|
|
|
+-}
|
|
|
+-
|
|
|
+-TEST_F(FirstPartySetsHandlerGetContextConfigForPolicyTest,
|
|
|
+- MalformedOverridesPolicy_DefaultContextConfigs) {
|
|
|
+- base::Value policy = base::JSONReader::Read(R"({
|
|
|
+- "replacements": 123,
|
|
|
+- "additions": true
|
|
|
+- })")
|
|
|
+- .value();
|
|
|
+- base::test::TestFuture<net::FirstPartySetsContextConfig> future;
|
|
|
+- handler().GetContextConfigForPolicy(&policy.GetDict(), future.GetCallback());
|
|
|
+-
|
|
|
+- InitPublicFirstPartySets();
|
|
|
+- EXPECT_EQ(future.Take(), net::FirstPartySetsContextConfig());
|
|
|
+-}
|
|
|
+-
|
|
|
+-TEST_F(FirstPartySetsHandlerGetContextConfigForPolicyTest,
|
|
|
+- NonDefaultOverridesPolicy_NonDefaultContextConfigs) {
|
|
|
+- base::Value policy = base::JSONReader::Read(R"(
|
|
|
+- {
|
|
|
+- "replacements": [
|
|
|
+- {
|
|
|
+- "primary": "https://associatedsite1.test",
|
|
|
+- "associatedSites": ["https://primary3.test"]
|
|
|
+- }
|
|
|
+- ],
|
|
|
+- "additions": [
|
|
|
+- {
|
|
|
+- "primary": "https://primary2.test",
|
|
|
+- "associatedSites": ["https://associatedsite2.test"]
|
|
|
+- }
|
|
|
+- ]
|
|
|
+- }
|
|
|
+- )")
|
|
|
+- .value();
|
|
|
+- base::test::TestFuture<net::FirstPartySetsContextConfig> future;
|
|
|
+- handler().GetContextConfigForPolicy(&policy.GetDict(), future.GetCallback());
|
|
|
+-
|
|
|
+- InitPublicFirstPartySets();
|
|
|
+- // We don't care what the customizations are, here; we only care that they're
|
|
|
+- // not a no-op.
|
|
|
+- EXPECT_FALSE(future.Take().empty());
|
|
|
+- EXPECT_EQ(GetContextConfigForPolicy(nullptr),
|
|
|
+- net::FirstPartySetsContextConfig());
|
|
|
+-}
|
|
|
+-
|
|
|
+-} // namespace content
|
|
|
+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 eecd574ad30bc6e19b33eabbf2609890f72af286..ff8299ab75711411a94b6ecf54a141b1cfd548a0 100644
|
|
|
+--- a/content/browser/first_party_sets/first_party_sets_loader.cc
|
|
|
++++ b/content/browser/first_party_sets/first_party_sets_loader.cc
|
|
|
+@@ -31,6 +31,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(
|
|
|
+@@ -44,9 +57,6 @@ FirstPartySetsLoader::~FirstPartySetsLoader() {
|
|
|
+ void FirstPartySetsLoader::SetManuallySpecifiedSet(
|
|
|
+ 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",
|
|
|
+@@ -79,20 +89,6 @@ 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_);
|
|
|
+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 46b50bb18cec8562427af581f57e525ca48a5f95..0c51c9baa6fc0c43bba60dbb9e5d6df61a615374 100644
|
|
|
+--- a/content/browser/first_party_sets/first_party_sets_loader.h
|
|
|
++++ b/content/browser/first_party_sets/first_party_sets_loader.h
|
|
|
+@@ -35,7 +35,7 @@ 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.
|
|
|
++ // flag/switch.
|
|
|
+ void SetManuallySpecifiedSet(const LocalSetDeclaration& local_set);
|
|
|
+
|
|
|
+ // Asynchronously parses and stores the sets from `sets_file`, and merges with
|
|
|
+@@ -46,9 +46,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.
|
|
|
+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 dd86cf08266ba537f2443a0188d516419d35d01c..51b9c6b7b82a84bab0a7945caaadd47f697dcd5b 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
|
|
|
+@@ -162,30 +162,4 @@ TEST_F(FirstPartySetsLoaderTest, SetsManuallySpecified) {
|
|
|
+ net::SiteType::kAssociated, 0)));
|
|
|
+ }
|
|
|
+
|
|
|
+-TEST_F(FirstPartySetsLoaderTest, SetsManuallySpecified_Idempotent) {
|
|
|
+- loader().SetManuallySpecifiedSet(LocalSetDeclaration(
|
|
|
+- R"({"primary": "https://bar.test",)"
|
|
|
+- R"("associatedSites": ["https://associatedsite1.test"]})"));
|
|
|
+-
|
|
|
+- // All but the first SetManuallySpecifiedSet call should be ignored.
|
|
|
+- loader().SetManuallySpecifiedSet(LocalSetDeclaration(
|
|
|
+- R"({"primary": "https://bar.test",)"
|
|
|
+- R"("associatedSites": ["https://associatedsite2.test"]})"));
|
|
|
+-
|
|
|
+- SetComponentSets(loader(), base::Version(), "");
|
|
|
+-
|
|
|
+- const net::SchemefulSite associated1(GURL("https://associatedsite1.test"));
|
|
|
+-
|
|
|
+- EXPECT_THAT(WaitAndGetResult().FindEntries(
|
|
|
+- {
|
|
|
+- associated1,
|
|
|
+- net::SchemefulSite(GURL("https://associatedsite2.test")),
|
|
|
+- },
|
|
|
+- net::FirstPartySetsContextConfig()),
|
|
|
+- UnorderedElementsAre(Pair(
|
|
|
+- associated1, net::FirstPartySetEntry(
|
|
|
+- net::SchemefulSite(GURL("https://bar.test")),
|
|
|
+- net::SiteType::kAssociated, 0))));
|
|
|
+-}
|
|
|
+-
|
|
|
+ } // namespace content
|
|
|
+diff --git a/content/browser/media/android/media_resource_getter_impl.cc b/content/browser/media/android/media_resource_getter_impl.cc
|
|
|
+index d073eaef83888439114d5a6a110c74a3e4f4edc3..738c975dad138ad299cb74409d936d3e6cb1bdb3 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 5238480fd221e6fe2152bbe363bf0686a7dabd85..7cb17350869a2f93f22f1630a0fd253a59b4b424 100644
|
|
|
+--- a/content/browser/renderer_host/cookie_utils.cc
|
|
|
++++ b/content/browser/renderer_host/cookie_utils.cc
|
|
|
+@@ -178,6 +178,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(
|
|
|
+@@ -203,6 +205,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;
|
|
|
+@@ -247,6 +253,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(
|
|
|
+@@ -346,6 +368,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 fb9671b69b3a2c4d9270f9f2d70e502ed11be5b6..4063b7f413dd85cae4c2d48b88f246c87499b682 100644
|
|
|
+--- a/content/browser/renderer_host/render_frame_host_impl.cc
|
|
|
++++ b/content/browser/renderer_host/render_frame_host_impl.cc
|
|
|
+@@ -4123,7 +4123,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.
|
|
|
+@@ -4141,6 +4144,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);
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -4158,7 +4164,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);
|
|
|
+ }
|
|
|
+
|
|
|
+ absl::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 c526f29785e3523cb173457223a2fecc494cb5df..e6707d9c23466f943abbfa54a9e50c9b05e142c2 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
|
|
|
+@@ -217,7 +217,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 1700732bf1a9becc6b4d9613250fccb26403e217..2919285638cf5f46f6d22587fc36e47a06f0fea3 100644
|
|
|
+--- a/content/browser/worker_host/shared_worker_host.cc
|
|
|
++++ b/content/browser/worker_host/shared_worker_host.cc
|
|
|
+@@ -426,7 +426,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 4aa539bce808abef08959f547d02d3aed53959bb..0ebc898a7e94dac56bf1b580e755be6c92b150f5 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 f09599bb9723418794db23ece510a15008dd0477..63157c9823e6ee00eeff28211c53a5d99b6759e1 100644
|
|
|
+--- a/content/public/browser/content_browser_client.h
|
|
|
++++ b/content/public/browser/content_browser_client.h
|
|
|
+@@ -1905,7 +1905,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.
|
|
|
+ //
|
|
|
+@@ -2715,10 +2716,6 @@ class CONTENT_EXPORT ContentBrowserClient {
|
|
|
+ virtual bool ShouldAllowBackForwardCacheForCacheControlNoStorePage(
|
|
|
+ content::BrowserContext* browser_context);
|
|
|
+
|
|
|
+- // Set whether the browser is running in minimal mode (where most subsystems
|
|
|
+- // are left uninitialized).
|
|
|
+- virtual void SetIsMinimalMode(bool minimal) {}
|
|
|
+-
|
|
|
+ #if !BUILDFLAG(IS_ANDROID)
|
|
|
+ // Allows the embedder to correlate backend media services with profile-keyed
|
|
|
+ // effect settings.
|
|
|
+diff --git a/content/public/browser/first_party_sets_handler.h b/content/public/browser/first_party_sets_handler.h
|
|
|
+index 55dbe0afcfae7df771f17dc5ce56efd096a083a3..3e531dd05fc2268c93cb63f8f0bbaeb36e2371e2 100644
|
|
|
+--- a/content/public/browser/first_party_sets_handler.h
|
|
|
++++ b/content/public/browser/first_party_sets_handler.h
|
|
|
+@@ -197,6 +197,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/net/BUILD.gn b/net/BUILD.gn
|
|
|
+index e745a74d0446ea55c9e22cd7628ae0d6ac8a3982..eeff6d53e392f9ba90521ebcc94f7162cf53a7fa 100644
|
|
|
+--- a/net/BUILD.gn
|
|
|
++++ b/net/BUILD.gn
|
|
|
+@@ -584,6 +584,8 @@ component("net") {
|
|
|
+ "first_party_sets/first_party_sets_context_config.h",
|
|
|
+ "first_party_sets/global_first_party_sets.cc",
|
|
|
+ "first_party_sets/global_first_party_sets.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 3053df9162e31c7abeadb6e2f0b634ddda148355..159f91fc38aad31742add00ea5b1e16a0811911c 100644
|
|
|
+--- a/net/base/features.cc
|
|
|
++++ b/net/base/features.cc
|
|
|
+@@ -243,6 +243,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 af1b135ef9bf4a0dae6292a4d952187f7c345f70..a951f3a27046fa3737e28eddfe0189b6b82a4aca 100644
|
|
|
+--- a/net/base/features.h
|
|
|
++++ b/net/base/features.h
|
|
|
+@@ -297,6 +297,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 e337af60aa40bd31dd8d7549d963719278298c37..aac71c1c5d8c5892c98ee327198f0276b03e66e5 100644
|
|
|
+--- a/net/base/isolation_info.cc
|
|
|
++++ b/net/base/isolation_info.cc
|
|
|
+@@ -48,11 +48,13 @@ bool IsConsistent(IsolationInfo::RequestType request_type,
|
|
|
+ const absl::optional<url::Origin>& top_frame_origin,
|
|
|
+ const absl::optional<url::Origin>& frame_origin,
|
|
|
+ const SiteForCookies& site_for_cookies,
|
|
|
++ 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=*/absl::nullopt,
|
|
|
+ /*frame_origin=*/absl::nullopt,
|
|
|
+ SiteForCookies(),
|
|
|
+- /*nonce=*/absl::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=*/absl::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=*/absl::nullopt);
|
|
|
++ SiteForCookies(), /*nonce=*/absl::nullopt,
|
|
|
++ /*party_context=*/absl::nullopt);
|
|
|
+ }
|
|
|
+
|
|
|
+ absl::optional<IsolationInfo> IsolationInfo::Deserialize(
|
|
|
+@@ -130,11 +138,19 @@ absl::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=*/absl::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,
|
|
|
++ 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 @@ absl::optional<IsolationInfo> IsolationInfo::CreateIfConsistent(
|
|
|
+ const absl::optional<url::Origin>& top_frame_origin,
|
|
|
+ const absl::optional<url::Origin>& frame_origin,
|
|
|
+ const SiteForCookies& site_for_cookies,
|
|
|
++ 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)) {
|
|
|
++ 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 absl::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();
|
|
|
+@@ -313,7 +354,8 @@ IsolationInfo::IsolationInfo(
|
|
|
+ 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)
|
|
|
++ 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),
|
|
|
+@@ -328,9 +370,13 @@ IsolationInfo::IsolationInfo(
|
|
|
+ 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 8de58d607dcc6835027bc8f0295a2f5cc783e5f4..dc45e9354fe024609dc65e84b3c4e8b2cb53b500 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,6 +118,7 @@ class NET_EXPORT IsolationInfo {
|
|
|
+ const url::Origin& top_frame_origin,
|
|
|
+ const url::Origin& frame_origin,
|
|
|
+ const SiteForCookies& site_for_cookies,
|
|
|
++ 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
|
|
|
+@@ -132,6 +137,7 @@ class NET_EXPORT IsolationInfo {
|
|
|
+ const absl::optional<url::Origin>& top_frame_origin,
|
|
|
+ const absl::optional<url::Origin>& frame_origin,
|
|
|
+ const SiteForCookies& site_for_cookies,
|
|
|
++ 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
|
|
|
+@@ -174,6 +180,15 @@ class NET_EXPORT IsolationInfo {
|
|
|
+ // Do not use outside of testing. Returns the `frame_origin_`.
|
|
|
+ const absl::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 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);
|
|
|
++ 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.
|
|
|
+ absl::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 653f2acf2d53fdc45944271972c6a42cf69329f4..7b08eecb6d4a00797fc2b11ecb7b7d9fee2dbd1c 100644
|
|
|
+--- a/net/base/network_delegate.cc
|
|
|
++++ b/net/base/network_delegate.cc
|
|
|
+@@ -165,6 +165,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 c9c6cf72a5303f7d2848e5e09aee2c38cc3c2db4..ba2df571f61556dc1239d557fa7fafcaa6ea110d 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 {
|
|
|
+@@ -120,6 +121,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
|
|
|
+@@ -288,6 +303,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 c14f48ddf635784492c030a8a0089eacbc83b35c..a8ed45ed263ea1a7592aa48f4cd0081155ead17c 100644
|
|
|
+--- a/net/base/network_delegate_impl.cc
|
|
|
++++ b/net/base/network_delegate_impl.cc
|
|
|
+@@ -97,4 +97,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 a43507f98641a626712ccfa1549512abca908502..9bc72d4ef0ab2cb7d52ddd3cf484c2933829da58 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;
|
|
|
+@@ -99,6 +100,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 b81e1656003f7676c2f0151612cec9648ebd9cbc..2e34df420cc6aaf59d3e638af7cd0cbcfa99afc3 100644
|
|
|
+--- a/net/cookies/canonical_cookie.cc
|
|
|
++++ b/net/cookies/canonical_cookie.cc
|
|
|
+@@ -340,9 +340,11 @@ bool HasValidHostPrefixAttributes(const GURL& url,
|
|
|
+ } // 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;
|
|
|
+
|
|
|
+@@ -615,6 +617,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);
|
|
|
+@@ -880,6 +888,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=*/
|
|
|
+@@ -1200,11 +1212,56 @@ CookieAccessResult CanonicalCookie::IncludeForRequestURL(
|
|
|
+ CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE);
|
|
|
+ }
|
|
|
+
|
|
|
+- // 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 */);
|
|
|
++ 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",
|
|
|
+@@ -1374,11 +1431,59 @@ CookieAccessResult CanonicalCookie::IsSetPermittedInContext(
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+- // 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 */);
|
|
|
++ 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",
|
|
|
+@@ -1485,6 +1590,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;
|
|
|
+@@ -1731,6 +1839,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 56b919c8e965182e2e5621ee123e8afea3565e36..9dbc2a30c85c3e70e7a995e1bc8336b49e2ed7a8 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 {
|
|
|
+@@ -565,6 +570,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.
|
|
|
+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 5be49154795380ee37258a9f2d24256d406af03f..4fba69d9ea8c9e94f8f8c75536584089589cd633 100644
|
|
|
+--- a/net/cookies/cookie_inclusion_status.cc
|
|
|
++++ b/net/cookies/cookie_inclusion_status.cc
|
|
|
+@@ -244,6 +244,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,
|
|
|
+@@ -293,6 +296,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 1eefc3db602f5bb419ad3dbcb167dcd9742e1114..87ad6f7049560ac7f17a23047d983e4b17ec5bfa 100644
|
|
|
+--- a/net/cookies/cookie_inclusion_status.h
|
|
|
++++ b/net/cookies/cookie_inclusion_status.h
|
|
|
+@@ -109,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
|
|
|
+@@ -228,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
|
|
|
+ };
|
|
|
+diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
|
|
|
+index 0c3ce2e289b5944d38315790cca829e851c31e19..5c4352bb9fc1fd85373ee413b59a12967bd02710 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,
|
|
|
+@@ -1205,8 +1211,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
|
|
|
+@@ -1549,7 +1558,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 3ca2c691cfd00acf34f7648dfc6c9f6692be470a..6086953c99f55bd8a1034f0fa33ea77e4af9ec0d 100644
|
|
|
+--- a/net/cookies/cookie_monster.h
|
|
|
++++ b/net/cookies/cookie_monster.h
|
|
|
+@@ -734,6 +734,8 @@ class NET_EXPORT CookieMonster : public CookieStore {
|
|
|
+ // nonce.
|
|
|
+ size_t num_nonced_partitioned_cookie_bytes_ = 0u;
|
|
|
+
|
|
|
++ 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_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 183c1f61c1fbe94c8c85dd4f9a27695a04aad816..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 {
|
|
|
+
|
|
|
+@@ -266,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
|
|
|
+@@ -281,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 b479ab1deb4c54d14ccf87c1d923f6ab7fad6876..e2670576d72bfcc2267d8cc9b1865210d8162a4f 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"
|
|
|
+@@ -894,24 +894,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
|
|
|
+@@ -940,6 +939,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 e2e9ea3e8ae5af94b3c14df897cf0282513d67ab..a268d94feecf5e3e1c0559b75b66cefa1580ace0 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"
|
|
|
+
|
|
|
+@@ -286,27 +285,37 @@ NET_EXPORT bool IsSchemeBoundCookiesEnabled();
|
|
|
+ // 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/first_party_sets/first_party_set_metadata.cc b/net/first_party_sets/first_party_set_metadata.cc
|
|
|
+index 75f41ad79ac067f806d4bea8b687a4781778e37a..26521fa5f9b4a93f892212cbd45e77ce41fc0f29 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;
|
|
|
+@@ -26,8 +28,8 @@ FirstPartySetMetadata::~FirstPartySetMetadata() = default;
|
|
|
+
|
|
|
+ bool FirstPartySetMetadata::operator==(
|
|
|
+ const FirstPartySetMetadata& other) const {
|
|
|
+- return std::tie(frame_entry_, top_frame_entry_) ==
|
|
|
+- std::tie(other.frame_entry_, other.top_frame_entry_);
|
|
|
++ return std::tie(context_, frame_entry_, top_frame_entry_) ==
|
|
|
++ std::tie(other.context_, other.frame_entry_, other.top_frame_entry_);
|
|
|
+ }
|
|
|
+
|
|
|
+ bool FirstPartySetMetadata::operator!=(
|
|
|
+@@ -37,7 +39,8 @@ bool FirstPartySetMetadata::operator!=(
|
|
|
+
|
|
|
+ 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 29d34cd442ae19006d399b09b766c19dd5b12c76..d90a01fde8f9692825e5b7bb0c90c32b48d60e65 100644
|
|
|
+--- a/net/first_party_sets/global_first_party_sets.cc
|
|
|
++++ b/net/first_party_sets/global_first_party_sets.cc
|
|
|
+@@ -28,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) {
|
|
|
+@@ -59,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;
|
|
|
+@@ -126,9 +138,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());
|
|
|
+@@ -136,7 +150,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
|
|
|
+@@ -144,9 +158,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;
|
|
|
+@@ -172,16 +186,48 @@ 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));
|
|
|
+ }
|
|
|
+
|
|
|
++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;
|
|
|
++
|
|
|
++ 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();
|
|
|
++ };
|
|
|
++
|
|
|
++ 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());
|
|
|
+diff --git a/net/first_party_sets/global_first_party_sets.h b/net/first_party_sets/global_first_party_sets.h
|
|
|
+index f4f4e99189e0f3b8accfa884e136a127d0128bab..cc2b42c89deb47fda879a5bef2c4a7f9989c139d 100644
|
|
|
+--- a/net/first_party_sets/global_first_party_sets.h
|
|
|
++++ b/net/first_party_sets/global_first_party_sets.h
|
|
|
+@@ -83,6 +83,7 @@ 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
|
|
|
+@@ -166,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(
|
|
|
+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 b5e18cf187f1ca0618eaac4b1453fa4ffdb3bb9d..d4a5e60a60f372fccbf54ead93666f9856b972de 100644
|
|
|
+--- a/net/url_request/url_request.cc
|
|
|
++++ b/net/url_request/url_request.cc
|
|
|
+@@ -1216,7 +1216,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 acd9a595a6c83bf58153354da91cb1d23e0f7235..9668aed7e3dde807e040ab71b442d81ca7e1c9b7 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.
|
|
|
+@@ -961,6 +971,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 689818d34e56eeaa91605bfeeeb552ec86bc4b14..c8730d3c1ab22d28330152d7b58b1d99a53b9d00 100644
|
|
|
+--- a/net/url_request/url_request_http_job.cc
|
|
|
++++ b/net/url_request/url_request_http_job.cc
|
|
|
+@@ -62,7 +62,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"
|
|
|
+@@ -165,11 +165,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;
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -318,33 +329,53 @@ void URLRequestHttpJob::Start() {
|
|
|
+ request_initiator_site().value() ==
|
|
|
+ net::SchemefulSite(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;
|
|
|
+
|
|
|
+@@ -676,7 +707,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,
|
|
|
+@@ -927,7 +962,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 a629e89cef3675c4ffe1ad56e17d4d595a51e3bd..78c8fbb6bfa39535c4fc2ae49dafa5a4ad001cd5 100644
|
|
|
+--- a/net/url_request/url_request_http_job.h
|
|
|
++++ b/net/url_request/url_request_http_job.h
|
|
|
+@@ -216,7 +216,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/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 82829ecd4005812b9973fbf4bd1a1fcee7ed5d5e..f2bdb481687b5e37fcaa5f6b12c9d754fb4f653f 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"
|
|
|
+@@ -330,6 +331,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 cfcd91f7e47e4d6869c97ba1eb9dd58e5b69cfff..ea8be1d29ad4ab384df0cf451d155551a6455842 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
|
|
|
+
|
|
|
+@@ -92,6 +93,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 5269c91580bc8d9cf93c3323f7b96ac748cd5972..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;
|
|
|
+ }
|
|
|
+
|
|
|
+diff --git a/services/network/public/cpp/cookie_manager_mojom_traits.h b/services/network/public/cpp/cookie_manager_mojom_traits.h
|
|
|
+index 5531222e359de032cb45b28e3451b5622a731069..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);
|
|
|
+ };
|
|
|
+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 0c20fd9b054b6bdf989adde7d9c03f4f784215d9..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;
|
|
|
+ }
|
|
|
+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 b255f56ead022bb237296e7560c73f692a7d7ee3..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();
|
|
|
+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 530b9da45489fc8572b44e32eac6564908e983d0..adb7d544e728a4ea49653eede3c1a68cf907bebc 100644
|
|
|
+--- a/services/network/public/mojom/BUILD.gn
|
|
|
++++ b/services/network/public/mojom/BUILD.gn
|
|
|
+@@ -1030,6 +1030,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 7aa887883985c86bb6ceda023225a35d1bc07f38..ee009f2425455d4617d21af0be3e47a7b695665d 100644
|
|
|
+--- a/services/network/public/mojom/cookie_manager.mojom
|
|
|
++++ b/services/network/public/mojom/cookie_manager.mojom
|
|
|
+@@ -165,6 +165,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.
|
|
|
+diff --git a/services/network/public/mojom/first_party_sets.mojom b/services/network/public/mojom/first_party_sets.mojom
|
|
|
+index 0ea745cd2450c2d92002c3a0113295b0d4bbd40e..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;
|
|
|
+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/restricted_cookie_manager.cc b/services/network/restricted_cookie_manager.cc
|
|
|
+index 8b0e7695e78f15632bea2a49813f096802517bc0..00bda3ab02fc8586973640a3ecf644dfc64f5dd7 100644
|
|
|
+--- a/services/network/restricted_cookie_manager.cc
|
|
|
++++ b/services/network/restricted_cookie_manager.cc
|
|
|
+@@ -38,7 +38,6 @@
|
|
|
+ #include "net/cookies/cookie_util.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 "services/network/cookie_settings.h"
|
|
|
+ #include "services/network/public/cpp/features.h"
|
|
|
+ #include "services/network/public/mojom/cookie_manager.mojom.h"
|
|
|
+@@ -105,11 +104,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);
|
|
|
+@@ -125,6 +133,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;
|
|
|
+ }
|
|
|
+@@ -133,7 +149,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 =
|
|
|
+@@ -151,6 +169,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;
|
|
|
+ }
|
|
|
+@@ -169,21 +195,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()(
|
|
|
+@@ -315,7 +333,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),
|
|
|
+@@ -323,7 +342,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(
|
|
|
+@@ -359,11 +379,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;
|
|
|
+ }
|
|
|
+@@ -414,6 +439,8 @@ class RestrictedCookieManager::Listener : public base::LinkNode<Listener> {
|
|
|
+
|
|
|
+ mojo::Remote<mojom::CookieChangeListener> mojo_listener_;
|
|
|
+
|
|
|
++ bool same_party_attribute_enabled_;
|
|
|
++
|
|
|
+ SEQUENCE_CHECKER(sequence_checker_);
|
|
|
+ };
|
|
|
+
|
|
|
+@@ -440,6 +467,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_(
|
|
|
+@@ -565,7 +594,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();
|
|
|
+@@ -819,7 +849,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(
|
|
|
+@@ -871,11 +902,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 f4cab620266b2db3bb71c7974bfcb519859808d3..0ea9313a079b1063be12c5f8dd914cbaa63cdacc 100644
|
|
|
+--- a/services/network/restricted_cookie_manager.h
|
|
|
++++ b/services/network/restricted_cookie_manager.h
|
|
|
+@@ -329,6 +329,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 b0b972c5768087ded0ade3dfc15bd1c47e68bc3c..3b0c13ad5d3f07bd667abc81d36f8d2067d911c8 100644
|
|
|
+--- a/services/network/url_loader.cc
|
|
|
++++ b/services/network/url_loader.cc
|
|
|
+@@ -286,7 +286,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);
|
|
|
+ }
|
|
|
+@@ -586,6 +586,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
|
|
|
+@@ -2691,6 +2694,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 3082770fd7cd93da2578e55c4ea256edf819bf29..e3911d8b21fc5f9f436cdab5656d929596a7cb47 100644
|
|
|
+--- a/services/network/url_loader.h
|
|
|
++++ b/services/network/url_loader.h
|
|
|
+@@ -547,6 +547,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
|