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