0

Add new PublicSets class.

This lets us share a common query-backend implementation between the
network service and the browser process, since both need to perform queries for various reasons.

Bug: 1358959
Change-Id: I58f9af2ce5cb39a83e62f691f9564cb288e3def3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3869050
Commit-Queue: Chris Fredrickson <cfredric@chromium.org>
Auto-Submit: Chris Fredrickson <cfredric@chromium.org>
Reviewed-by: Will Harris <wfh@chromium.org>
Reviewed-by: Matt Menke <mmenke@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1044557}
This commit is contained in:
Chris Fredrickson
2022-09-08 15:20:37 +00:00
committed by Chromium LUCI CQ
parent 37885e0318
commit 878d06b45d
23 changed files with 597 additions and 218 deletions

@@ -29,7 +29,7 @@
#include "content/public/common/content_client.h" #include "content/public/common/content_client.h"
#include "net/base/schemeful_site.h" #include "net/base/schemeful_site.h"
#include "net/first_party_sets/first_party_set_entry.h" #include "net/first_party_sets/first_party_set_entry.h"
#include "services/network/public/mojom/first_party_sets.mojom.h" #include "net/first_party_sets/public_sets.h"
#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/abseil-cpp/absl/types/optional.h"
namespace content { namespace content {
@@ -74,19 +74,20 @@ void UpdateCustomizationMap(
void AddIfPolicySetOverlaps( void AddIfPolicySetOverlaps(
const net::SchemefulSite& site, const net::SchemefulSite& site,
size_t policy_set_index, size_t policy_set_index,
const FlattenedSets& existing_sets, const net::PublicSets& existing_sets,
base::flat_map<net::SchemefulSite, base::flat_set<size_t>>& base::flat_map<net::SchemefulSite, base::flat_set<size_t>>&
policy_set_overlaps) { policy_set_overlaps) {
// Check `site` for membership in `existing_sets`. // Check `site` for membership in `existing_sets`.
if (auto it = existing_sets.find(site); it != existing_sets.end()) { if (auto entry = existing_sets.FindEntry(site, /*config=*/nullptr);
entry.has_value()) {
// Add the index of `site`'s policy set to the list of policy set indices // Add the index of `site`'s policy set to the list of policy set indices
// that also overlap with site_owner. // that also overlap with site_owner.
policy_set_overlaps[it->second.primary()].insert(policy_set_index); policy_set_overlaps[entry->primary()].insert(policy_set_index);
} }
} }
std::vector<SingleSet> NormalizeAdditionSets( std::vector<SingleSet> NormalizeAdditionSets(
const network::mojom::PublicFirstPartySetsPtr& public_sets, const net::PublicSets& public_sets,
const std::vector<SingleSet>& addition_sets) { const std::vector<SingleSet>& addition_sets) {
// Create a mapping from an owner site in `existing_sets` to all policy sets // Create a mapping from an owner site in `existing_sets` to all policy sets
// that intersect with the set that it owns. // that intersect with the set that it owns.
@@ -94,7 +95,7 @@ std::vector<SingleSet> NormalizeAdditionSets(
policy_set_overlaps; policy_set_overlaps;
for (size_t set_idx = 0; set_idx < addition_sets.size(); set_idx++) { for (size_t set_idx = 0; set_idx < addition_sets.size(); set_idx++) {
for (const auto& site_and_entry : addition_sets[set_idx]) { for (const auto& site_and_entry : addition_sets[set_idx]) {
AddIfPolicySetOverlaps(site_and_entry.first, set_idx, public_sets->sets, AddIfPolicySetOverlaps(site_and_entry.first, set_idx, public_sets,
policy_set_overlaps); policy_set_overlaps);
} }
} }
@@ -174,7 +175,7 @@ void FirstPartySetsHandlerImpl::GetCustomizationForPolicy(
callback) { callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
PolicyCustomization customization; PolicyCustomization customization;
if (!public_sets_.is_null()) { if (public_sets_.has_value()) {
std::move(callback).Run(GetCustomizationForPolicyInternal(policy)); std::move(callback).Run(GetCustomizationForPolicyInternal(policy));
return; return;
} }
@@ -191,7 +192,7 @@ void FirstPartySetsHandlerImpl::GetCustomizationForPolicy(
FirstPartySetsHandlerImpl::PolicyCustomization FirstPartySetsHandlerImpl::PolicyCustomization
FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations( FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations(
const network::mojom::PublicFirstPartySetsPtr& public_sets, const net::PublicSets& public_sets,
const FirstPartySetParser::ParsedPolicySetLists& policy) { const FirstPartySetParser::ParsedPolicySetLists& policy) {
// Maps a site to its new entry if it has one. // Maps a site to its new entry if it has one.
base::flat_map<net::SchemefulSite, absl::optional<net::FirstPartySetEntry>> base::flat_map<net::SchemefulSite, absl::optional<net::FirstPartySetEntry>>
@@ -216,10 +217,11 @@ FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations(
base::flat_map<net::SchemefulSite, net::FirstPartySetEntry> base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>
addition_intersected_owners; addition_intersected_owners;
for (const auto& [new_member, new_entry] : flattened_additions) { for (const auto& [new_member, new_entry] : flattened_additions) {
if (const auto entry = public_sets->sets.find(new_member); if (const auto entry =
entry != public_sets->sets.end()) { public_sets.FindEntry(new_member, /*config=*/nullptr);
entry.has_value()) {
// Found an overlap with the existing list of sets. // Found an overlap with the existing list of sets.
addition_intersected_owners.emplace(entry->second.primary(), new_entry); addition_intersected_owners.emplace(entry->primary(), new_entry);
} }
} }
@@ -229,13 +231,12 @@ FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations(
for (const auto& [member, set_entry] : flattened_replacements) { for (const auto& [member, set_entry] : flattened_replacements) {
if (member == set_entry.primary()) if (member == set_entry.primary())
continue; continue;
if (auto entry = public_sets->sets.find(member); if (auto existing_entry = public_sets.FindEntry(member, /*config=*/nullptr);
entry != public_sets->sets.end() && entry->second.primary() != member) { existing_entry.has_value() && existing_entry->primary() != member) {
const net::FirstPartySetEntry& existing_entry = entry->second; if (!addition_intersected_owners.contains(existing_entry->primary()) &&
if (!addition_intersected_owners.contains(existing_entry.primary()) && !flattened_additions.contains(existing_entry->primary()) &&
!flattened_additions.contains(existing_entry.primary()) && !flattened_replacements.contains(existing_entry->primary())) {
!flattened_replacements.contains(existing_entry.primary())) { potential_singletons[existing_entry->primary()].insert(member);
potential_singletons[existing_entry.primary()].insert(member);
} }
} }
} }
@@ -245,8 +246,8 @@ FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations(
// that those members are involved in). // that those members are involved in).
base::flat_set<net::SchemefulSite> replaced_existing_owners; base::flat_set<net::SchemefulSite> replaced_existing_owners;
for (const auto& [site, unused_owner] : flattened_replacements) { for (const auto& [site, unused_owner] : flattened_replacements) {
if (const auto entry = public_sets->sets.find(site); if (const auto entry = public_sets.FindEntry(site, /*config=*/nullptr);
entry != public_sets->sets.end() && entry->second.primary() == site) { entry.has_value() && entry->primary() == site) {
// Site was an owner in the existing sets. // Site was an owner in the existing sets.
bool inserted = replaced_existing_owners.emplace(site).second; bool inserted = replaced_existing_owners.emplace(site).second;
DCHECK(inserted); DCHECK(inserted);
@@ -256,7 +257,7 @@ FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations(
// Find out which potential singletons are actually singletons; delete // Find out which potential singletons are actually singletons; delete
// members whose owners left; and reparent the sets that intersected with // members whose owners left; and reparent the sets that intersected with
// an addition set. // an addition set.
for (const auto& [member, set_entry] : public_sets->sets) { for (const auto& [member, set_entry] : public_sets.entries()) {
// Reparent all sites in any intersecting addition sets. // Reparent all sites in any intersecting addition sets.
if (auto entry = addition_intersected_owners.find(set_entry.primary()); if (auto entry = addition_intersected_owners.find(set_entry.primary());
entry != addition_intersected_owners.end() && entry != addition_intersected_owners.end() &&
@@ -311,11 +312,11 @@ FirstPartySetsHandlerImpl::FirstPartySetsHandlerImpl(
FirstPartySetsHandlerImpl::~FirstPartySetsHandlerImpl() = default; FirstPartySetsHandlerImpl::~FirstPartySetsHandlerImpl() = default;
absl::optional<network::mojom::PublicFirstPartySetsPtr> absl::optional<net::PublicSets> FirstPartySetsHandlerImpl::GetSets(
FirstPartySetsHandlerImpl::GetSets(SetsReadyOnceCallback callback) { SetsReadyOnceCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(IsEnabled()); DCHECK(IsEnabled());
if (!public_sets_.is_null()) if (public_sets_.has_value())
return public_sets_->Clone(); return public_sets_->Clone();
if (!callback.is_null()) { if (!callback.is_null()) {
@@ -343,7 +344,7 @@ void FirstPartySetsHandlerImpl::Init(const base::FilePath& user_data_dir,
sets_loader_->SetComponentSets(base::File()); sets_loader_->SetComponentSets(base::File());
} }
} else { } else {
SetCompleteSets(network::mojom::PublicFirstPartySets::New()); SetCompleteSets(net::PublicSets());
} }
} }
@@ -374,7 +375,7 @@ void FirstPartySetsHandlerImpl::ResetForTesting() {
// this is a static singleton. // this is a static singleton.
base::Unretained(this))); base::Unretained(this)));
on_sets_ready_callbacks_.clear(); on_sets_ready_callbacks_.clear();
public_sets_ = nullptr; public_sets_ = absl::nullopt;
db_helper_.Reset(); db_helper_.Reset();
} }
@@ -388,11 +389,9 @@ void FirstPartySetsHandlerImpl::GetPersistedPublicSetsForTesting(
.Then(std::move(callback)); .Then(std::move(callback));
} }
void FirstPartySetsHandlerImpl::SetCompleteSets( void FirstPartySetsHandlerImpl::SetCompleteSets(net::PublicSets public_sets) {
network::mojom::PublicFirstPartySetsPtr public_sets) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(public_sets_.is_null()); DCHECK(!public_sets_.has_value());
DCHECK(!public_sets.is_null());
public_sets_ = std::move(public_sets); public_sets_ = std::move(public_sets);
ClearSiteDataOnChangedSets(); ClearSiteDataOnChangedSets();
@@ -427,22 +426,21 @@ void FirstPartySetsHandlerImpl::InvokePendingQueries() {
on_sets_ready_callbacks_.shrink_to_fit(); on_sets_ready_callbacks_.shrink_to_fit();
} }
network::mojom::PublicFirstPartySetsPtr FirstPartySetsHandlerImpl::GetSetsSync() net::PublicSets FirstPartySetsHandlerImpl::GetSetsSync() const {
const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!public_sets_.is_null()); DCHECK(public_sets_.has_value());
return public_sets_->Clone(); return public_sets_->Clone();
} }
void FirstPartySetsHandlerImpl::ClearSiteDataOnChangedSets() const { void FirstPartySetsHandlerImpl::ClearSiteDataOnChangedSets() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!public_sets_.is_null()); DCHECK(public_sets_.has_value());
if (!db_helper_.is_null()) { if (!db_helper_.is_null()) {
// TODO(shuuran@chromium.org): Implement site state clearing. // TODO(shuuran@chromium.org): Implement site state clearing.
db_helper_ db_helper_
.AsyncCall(&FirstPartySetsHandlerDatabaseHelper::PersistPublicSets) .AsyncCall(&FirstPartySetsHandlerDatabaseHelper::PersistPublicSets)
.WithArgs(public_sets_->sets); .WithArgs(public_sets_->entries());
} }
} }
@@ -457,7 +455,7 @@ FirstPartySetsHandlerImpl::GetCustomizationForPolicyInternal(
// Provide empty customization if the policy is malformed. // Provide empty customization if the policy is malformed.
return parsed_policy.has_value() return parsed_policy.has_value()
? FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations( ? FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations(
public_sets_, parsed_policy.value()) public_sets_.value(), parsed_policy.value())
: FirstPartySetsHandlerImpl::PolicyCustomization(); : FirstPartySetsHandlerImpl::PolicyCustomization();
} }

@@ -27,7 +27,7 @@
#include "content/public/browser/first_party_sets_handler.h" #include "content/public/browser/first_party_sets_handler.h"
#include "net/base/schemeful_site.h" #include "net/base/schemeful_site.h"
#include "net/first_party_sets/first_party_set_entry.h" #include "net/first_party_sets/first_party_set_entry.h"
#include "services/network/public/mojom/first_party_sets.mojom.h" #include "net/first_party_sets/public_sets.h"
#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/abseil-cpp/absl/types/optional.h"
namespace content { namespace content {
@@ -43,8 +43,7 @@ class CONTENT_EXPORT FirstPartySetsHandlerImpl : public FirstPartySetsHandler {
public: public:
using FlattenedSets = using FlattenedSets =
base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>; base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>;
using SetsReadyOnceCallback = using SetsReadyOnceCallback = base::OnceCallback<void(net::PublicSets)>;
base::OnceCallback<void(network::mojom::PublicFirstPartySetsPtr)>;
using PolicyCustomization = FirstPartySetsHandler::PolicyCustomization; using PolicyCustomization = FirstPartySetsHandler::PolicyCustomization;
static FirstPartySetsHandlerImpl* GetInstance(); static FirstPartySetsHandlerImpl* GetInstance();
@@ -77,7 +76,7 @@ class CONTENT_EXPORT FirstPartySetsHandlerImpl : public FirstPartySetsHandler {
// data is not ready yet. // data is not ready yet.
// //
// Must not be called if First-Party Sets is disabled. // Must not be called if First-Party Sets is disabled.
[[nodiscard]] absl::optional<network::mojom::PublicFirstPartySetsPtr> GetSets( [[nodiscard]] absl::optional<net::PublicSets> GetSets(
SetsReadyOnceCallback callback); SetsReadyOnceCallback callback);
// FirstPartySetsHandler // FirstPartySetsHandler
@@ -107,7 +106,7 @@ class CONTENT_EXPORT FirstPartySetsHandlerImpl : public FirstPartySetsHandler {
// to update the browser's list of First-Party Sets to respect a profile's // to update the browser's list of First-Party Sets to respect a profile's
// setting for the per-profile FirstPartySetsOverrides policy. // setting for the per-profile FirstPartySetsOverrides policy.
static PolicyCustomization ComputeEnterpriseCustomizations( static PolicyCustomization ComputeEnterpriseCustomizations(
const network::mojom::PublicFirstPartySetsPtr& public_sets, const net::PublicSets& public_sets,
const FirstPartySetParser::ParsedPolicySetLists& policy); const FirstPartySetParser::ParsedPolicySetLists& policy);
private: private:
@@ -117,7 +116,7 @@ class CONTENT_EXPORT FirstPartySetsHandlerImpl : public FirstPartySetsHandler {
bool embedder_will_provide_public_sets); bool embedder_will_provide_public_sets);
// Sets the public First-Party Sets data. Must be called exactly once. // Sets the public First-Party Sets data. Must be called exactly once.
void SetCompleteSets(network::mojom::PublicFirstPartySetsPtr public_sets); void SetCompleteSets(net::PublicSets public_sets);
// Sets `db_helper_`, which will initialize the underlying First-Party Sets // Sets `db_helper_`, which will initialize the underlying First-Party Sets
// database under `user_data_dir`. Must be called exactly once. // database under `user_data_dir`. Must be called exactly once.
@@ -126,10 +125,11 @@ class CONTENT_EXPORT FirstPartySetsHandlerImpl : public FirstPartySetsHandler {
// Invokes any pending queries. // Invokes any pending queries.
void InvokePendingQueries(); void InvokePendingQueries();
// Returns the list of public First-Party Sets. // Returns the list of public First-Party Sets. This clones the underlying
// data.
// //
// Must be called after the list has been initialized. // Must be called after the list has been initialized.
network::mojom::PublicFirstPartySetsPtr GetSetsSync() const; net::PublicSets GetSetsSync() const;
// TODO(shuuran@chromium.org): Implement the code to clear site state. // TODO(shuuran@chromium.org): Implement the code to clear site state.
void ClearSiteDataOnChangedSets() const; void ClearSiteDataOnChangedSets() const;
@@ -144,8 +144,8 @@ class CONTENT_EXPORT FirstPartySetsHandlerImpl : public FirstPartySetsHandler {
// The public First-Party Sets, after parsing and validation. // The public First-Party Sets, after parsing and validation.
// //
// This is nullptr until all of the required inputs have been received. // This is nullopt until all of the required inputs have been received.
network::mojom::PublicFirstPartySetsPtr public_sets_ absl::optional<net::PublicSets> public_sets_
GUARDED_BY_CONTEXT(sequence_checker_); GUARDED_BY_CONTEXT(sequence_checker_);
bool enabled_ GUARDED_BY_CONTEXT(sequence_checker_); bool enabled_ GUARDED_BY_CONTEXT(sequence_checker_);

@@ -18,7 +18,7 @@
#include "content/public/browser/first_party_sets_handler.h" #include "content/public/browser/first_party_sets_handler.h"
#include "net/base/schemeful_site.h" #include "net/base/schemeful_site.h"
#include "net/first_party_sets/first_party_set_entry.h" #include "net/first_party_sets/first_party_set_entry.h"
#include "services/network/public/mojom/first_party_sets.mojom.h" #include "net/first_party_sets/public_sets.h"
#include "testing/gmock/include/gmock/gmock-matchers.h" #include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
@@ -45,9 +45,9 @@ MATCHER_P(SerializesTo, want, "") {
} }
MATCHER_P(PublicSetsAre, sets_matcher, "") { MATCHER_P(PublicSetsAre, sets_matcher, "") {
const network::mojom::PublicFirstPartySetsPtr& public_sets = arg; const net::PublicSets& public_sets = arg;
const base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>& sets = const base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>& sets =
public_sets->sets; public_sets.entries();
return testing::ExplainMatchResult(sets_matcher, sets, result_listener); return testing::ExplainMatchResult(sets_matcher, sets, result_listener);
} }
@@ -107,20 +107,13 @@ FirstPartySetParser::ParsedPolicySetLists MakeParsedPolicyFromMap(
return result; return result;
} }
network::mojom::PublicFirstPartySetsPtr GetSetsAndWait() { net::PublicSets GetSetsAndWait() {
base::test::TestFuture<network::mojom::PublicFirstPartySetsPtr> future; base::test::TestFuture<net::PublicSets> future;
absl::optional<network::mojom::PublicFirstPartySetsPtr> result = absl::optional<net::PublicSets> result =
FirstPartySetsHandlerImpl::GetInstance()->GetSets(future.GetCallback()); FirstPartySetsHandlerImpl::GetInstance()->GetSets(future.GetCallback());
return result.has_value() ? std::move(result).value() : future.Take(); return result.has_value() ? std::move(result).value() : future.Take();
} }
network::mojom::PublicFirstPartySetsPtr MakePublicFirstPartySets(
FlattenedSets sets) {
network::mojom::PublicFirstPartySetsPtr public_sets =
network::mojom::PublicFirstPartySets::New();
public_sets->sets = std::move(sets);
return public_sets;
}
} // namespace } // namespace
TEST(FirstPartySetsHandlerImpl, ValidateEnterprisePolicy_ValidPolicy) { TEST(FirstPartySetsHandlerImpl, ValidateEnterprisePolicy_ValidPolicy) {
@@ -365,7 +358,7 @@ TEST_F(FirstPartySetsHandlerImplEnabledTest,
->SetEmbedderWillProvidePublicSetsForTesting(true); ->SetEmbedderWillProvidePublicSetsForTesting(true);
// Call GetSets before the sets are ready, and before Init has been called. // Call GetSets before the sets are ready, and before Init has been called.
base::test::TestFuture<network::mojom::PublicFirstPartySetsPtr> future; base::test::TestFuture<net::PublicSets> future;
EXPECT_EQ( EXPECT_EQ(
FirstPartySetsHandlerImpl::GetInstance()->GetSets(future.GetCallback()), FirstPartySetsHandlerImpl::GetInstance()->GetSets(future.GetCallback()),
absl::nullopt); absl::nullopt);
@@ -526,20 +519,25 @@ TEST_F(FirstPartySetsHandlerGetCustomizationForPolicyTest,
} }
TEST(FirstPartySetsProfilePolicyCustomizations, EmptyPolicySetLists) { TEST(FirstPartySetsProfilePolicyCustomizations, EmptyPolicySetLists) {
EXPECT_THAT( EXPECT_THAT(FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations(
FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations( net::PublicSets(
MakePublicFirstPartySets(MakeFlattenedSetsFromMap( /*entries=*/MakeFlattenedSetsFromMap(
{{"https://primary1.test", {"https://associatedsite1.test"}}})), {{"https://primary1.test",
MakeParsedPolicyFromMap({}, {})), {"https://associatedsite1.test"}}}),
FirstPartySetsHandlerImpl::PolicyCustomization()); /*aliases=*/{}),
MakeParsedPolicyFromMap({}, {})),
FirstPartySetsHandlerImpl::PolicyCustomization());
} }
TEST(FirstPartySetsProfilePolicyCustomizations, TEST(FirstPartySetsProfilePolicyCustomizations,
Replacements_NoIntersection_NoRemoval) { Replacements_NoIntersection_NoRemoval) {
PolicyCustomization customization = PolicyCustomization customization =
FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations( FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations(
MakePublicFirstPartySets(MakeFlattenedSetsFromMap( net::PublicSets(
{{"https://primary1.test", {"https://associatedsite1.test"}}})), /*entries=*/MakeFlattenedSetsFromMap(
{{"https://primary1.test",
{"https://associatedsite1.test"}}}),
/*aliases=*/{}),
MakeParsedPolicyFromMap( MakeParsedPolicyFromMap(
/*replacements=*/{{"https://primary2.test", /*replacements=*/{{"https://primary2.test",
{"https://associatedsite2.test"}}}, {"https://associatedsite2.test"}}},
@@ -562,10 +560,12 @@ TEST(FirstPartySetsProfilePolicyCustomizations,
Replacements_ReplacesExistingAssociatedSite_RemovedFromFormerSet) { Replacements_ReplacesExistingAssociatedSite_RemovedFromFormerSet) {
PolicyCustomization customization = PolicyCustomization customization =
FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations( FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations(
MakePublicFirstPartySets( net::PublicSets(
MakeFlattenedSetsFromMap({{"https://primary1.test", /*entries=*/MakeFlattenedSetsFromMap(
{"https://associatedsite1a.test", {{"https://primary1.test",
"https://associatedsite1b.test"}}})), {"https://associatedsite1a.test",
"https://associatedsite1b.test"}}}),
/*aliases=*/{}),
MakeParsedPolicyFromMap( MakeParsedPolicyFromMap(
/*replacements=*/{{"https://primary2.test", /*replacements=*/{{"https://primary2.test",
{"https://associatedsite1b.test"}}}, {"https://associatedsite1b.test"}}},
@@ -588,10 +588,12 @@ TEST(FirstPartySetsProfilePolicyCustomizations,
Replacements_ReplacesExistingPrimary_RemovesFormerAssociatedSites) { Replacements_ReplacesExistingPrimary_RemovesFormerAssociatedSites) {
PolicyCustomization customization = PolicyCustomization customization =
FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations( FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations(
MakePublicFirstPartySets( net::PublicSets(
MakeFlattenedSetsFromMap({{"https://primary1.test", /*entries=*/MakeFlattenedSetsFromMap(
{"https://associatedsite1a.test", {{"https://primary1.test",
"https://associatedsite1b.test"}}})), {"https://associatedsite1a.test",
"https://associatedsite1b.test"}}}),
/*aliases=*/{}),
MakeParsedPolicyFromMap( MakeParsedPolicyFromMap(
/*replacements=*/{{"https://primary1.test", /*replacements=*/{{"https://primary1.test",
{"https://associatedsite2.test"}}}, {"https://associatedsite2.test"}}},
@@ -617,8 +619,11 @@ TEST(FirstPartySetsProfilePolicyCustomizations,
Replacements_ReplacesExistingAssociatedSite_RemovesSingletons) { Replacements_ReplacesExistingAssociatedSite_RemovesSingletons) {
PolicyCustomization customization = PolicyCustomization customization =
FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations( FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations(
MakePublicFirstPartySets(MakeFlattenedSetsFromMap( net::PublicSets(
{{"https://primary1.test", {"https://associatedsite1.test"}}})), /*entries=*/MakeFlattenedSetsFromMap(
{{"https://primary1.test",
{"https://associatedsite1.test"}}}),
/*aliases=*/{}),
MakeParsedPolicyFromMap( MakeParsedPolicyFromMap(
/*replacements=*/{{"https://primary3.test", /*replacements=*/{{"https://primary3.test",
{"https://associatedsite1.test"}}}, {"https://associatedsite1.test"}}},
@@ -642,8 +647,11 @@ TEST(FirstPartySetsProfilePolicyCustomizations,
Additions_NoIntersection_AddsWithoutUpdating) { Additions_NoIntersection_AddsWithoutUpdating) {
PolicyCustomization customization = PolicyCustomization customization =
FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations( FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations(
MakePublicFirstPartySets(MakeFlattenedSetsFromMap( net::PublicSets(
{{"https://primary1.test", {"https://associatedsite1.test"}}})), /*entries=*/MakeFlattenedSetsFromMap(
{{"https://primary1.test",
{"https://associatedsite1.test"}}}),
/*aliases=*/{}),
MakeParsedPolicyFromMap( MakeParsedPolicyFromMap(
/*replacements=*/{}, /*replacements=*/{},
/*additions=*/{{"https://primary2.test", /*additions=*/{{"https://primary2.test",
@@ -668,8 +676,11 @@ TEST(
Additions_PolicyPrimaryIsExistingAssociatedSite_PolicySetAbsorbsExistingSet) { Additions_PolicyPrimaryIsExistingAssociatedSite_PolicySetAbsorbsExistingSet) {
PolicyCustomization customization = PolicyCustomization customization =
FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations( FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations(
MakePublicFirstPartySets(MakeFlattenedSetsFromMap( net::PublicSets(
{{"https://primary1.test", {"https://associatedsite2.test"}}})), /*entries=*/MakeFlattenedSetsFromMap(
{{"https://primary1.test",
{"https://associatedsite2.test"}}}),
/*aliases=*/{}),
MakeParsedPolicyFromMap( MakeParsedPolicyFromMap(
/*replacements=*/{}, /*replacements=*/{},
/*additions=*/{{"https://associatedsite2.test", /*additions=*/{{"https://associatedsite2.test",
@@ -704,10 +715,12 @@ TEST(
Additions_PolicyPrimaryIsExistingPrimary_PolicySetAbsorbsExistingAssociatedSites) { Additions_PolicyPrimaryIsExistingPrimary_PolicySetAbsorbsExistingAssociatedSites) {
PolicyCustomization customization = PolicyCustomization customization =
FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations( FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations(
MakePublicFirstPartySets( net::PublicSets(
MakeFlattenedSetsFromMap({{"https://primary1.test", /*entries=*/MakeFlattenedSetsFromMap(
{"https://associatedsite1.test", {{"https://primary1.test",
"https://associatedsite3.test"}}})), {"https://associatedsite1.test",
"https://associatedsite3.test"}}}),
/*aliases=*/{}),
MakeParsedPolicyFromMap( MakeParsedPolicyFromMap(
/*replacements=*/{}, /*replacements=*/{},
/*additions=*/{{"https://primary1.test", /*additions=*/{{"https://primary1.test",
@@ -748,8 +761,10 @@ TEST(FirstPartySetsProfilePolicyCustomizations,
// sets are unaffected. // sets are unaffected.
EXPECT_THAT( EXPECT_THAT(
FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations( FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations(
MakePublicFirstPartySets(MakeFlattenedSetsFromMap( net::PublicSets(
{{"https://primary1.test", {"https://primary2.test"}}})), /*entries=*/MakeFlattenedSetsFromMap(
{{"https://primary1.test", {"https://primary2.test"}}}),
/*aliases=*/{}),
FirstPartySetParser::ParsedPolicySetLists( FirstPartySetParser::ParsedPolicySetLists(
/*replacement_list=*/{}, /*replacement_list=*/{},
{ {
@@ -825,8 +840,10 @@ TEST(FirstPartySetsProfilePolicyCustomizations,
// sets are unaffected. // sets are unaffected.
EXPECT_THAT( EXPECT_THAT(
FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations( FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations(
MakePublicFirstPartySets(MakeFlattenedSetsFromMap( net::PublicSets(
{{"https://primary2.test", {"https://primary1.test"}}})), /*entries=*/MakeFlattenedSetsFromMap(
{{"https://primary2.test", {"https://primary1.test"}}}),
/*aliases=*/{}),
FirstPartySetParser::ParsedPolicySetLists( FirstPartySetParser::ParsedPolicySetLists(
/*replacement_list=*/{}, /*replacement_list=*/{},
{ {
@@ -891,10 +908,12 @@ TEST(FirstPartySetsProfilePolicyCustomizations,
ReplacementsAndAdditions_SetListsOverlapWithSameExistingSet) { ReplacementsAndAdditions_SetListsOverlapWithSameExistingSet) {
PolicyCustomization customization = PolicyCustomization customization =
FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations( FirstPartySetsHandlerImpl::ComputeEnterpriseCustomizations(
MakePublicFirstPartySets( net::PublicSets(
MakeFlattenedSetsFromMap({{"https://primary1.test", /*entries=*/MakeFlattenedSetsFromMap(
{"https://associatedsite1.test", {{"https://primary1.test",
"https://associatedsite2.test"}}})), {"https://associatedsite1.test",
"https://associatedsite2.test"}}}),
/*aliases=*/{}),
MakeParsedPolicyFromMap( MakeParsedPolicyFromMap(
/*replacements=*/{{"https://primary0.test", /*replacements=*/{{"https://primary0.test",
{"https://associatedsite1.test"}}}, {"https://associatedsite1.test"}}},

@@ -6,6 +6,7 @@
#include <iterator> #include <iterator>
#include <set> #include <set>
#include <sstream>
#include <utility> #include <utility>
#include <vector> #include <vector>
@@ -21,7 +22,7 @@
#include "content/browser/first_party_sets/local_set_declaration.h" #include "content/browser/first_party_sets/local_set_declaration.h"
#include "net/base/schemeful_site.h" #include "net/base/schemeful_site.h"
#include "net/first_party_sets/first_party_set_entry.h" #include "net/first_party_sets/first_party_set_entry.h"
#include "services/network/public/mojom/first_party_sets.mojom.h" #include "net/first_party_sets/public_sets.h"
#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/abseil-cpp/absl/types/optional.h"
namespace content { namespace content {
@@ -156,11 +157,8 @@ void FirstPartySetsLoader::MaybeFinishLoading() {
if (!HasAllInputs()) if (!HasAllInputs())
return; return;
ApplyManuallySpecifiedSet(); ApplyManuallySpecifiedSet();
network::mojom::PublicFirstPartySetsPtr public_sets = std::move(on_load_complete_)
network::mojom::PublicFirstPartySets::New(); .Run(net::PublicSets(std::move(sets_), std::move(aliases_)));
public_sets->sets = std::move(sets_);
public_sets->aliases = std::move(aliases_);
std::move(on_load_complete_).Run(std::move(public_sets));
} }
bool FirstPartySetsLoader::HasAllInputs() const { bool FirstPartySetsLoader::HasAllInputs() const {

@@ -13,7 +13,7 @@
#include "content/browser/first_party_sets/first_party_set_parser.h" #include "content/browser/first_party_sets/first_party_set_parser.h"
#include "content/browser/first_party_sets/local_set_declaration.h" #include "content/browser/first_party_sets/local_set_declaration.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
#include "services/network/public/mojom/first_party_sets.mojom-forward.h" #include "net/first_party_sets/public_sets.h"
#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/abseil-cpp/absl/types/optional.h"
namespace content { namespace content {
@@ -25,8 +25,7 @@ namespace content {
// `SetManuallySpecifiedSet`. // `SetManuallySpecifiedSet`.
class CONTENT_EXPORT FirstPartySetsLoader { class CONTENT_EXPORT FirstPartySetsLoader {
public: public:
using LoadCompleteOnceCallback = using LoadCompleteOnceCallback = base::OnceCallback<void(net::PublicSets)>;
base::OnceCallback<void(network::mojom::PublicFirstPartySetsPtr)>;
using FlattenedSets = FirstPartySetParser::SetsMap; using FlattenedSets = FirstPartySetParser::SetsMap;
using SingleSet = FirstPartySetParser::SingleSet; using SingleSet = FirstPartySetParser::SingleSet;

@@ -21,7 +21,7 @@
#include "content/browser/first_party_sets/local_set_declaration.h" #include "content/browser/first_party_sets/local_set_declaration.h"
#include "net/base/schemeful_site.h" #include "net/base/schemeful_site.h"
#include "net/first_party_sets/first_party_set_entry.h" #include "net/first_party_sets/first_party_set_entry.h"
#include "services/network/public/mojom/first_party_sets.mojom.h" #include "net/first_party_sets/public_sets.h"
#include "testing/gmock/include/gmock/gmock-matchers.h" #include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
@@ -45,9 +45,9 @@ MATCHER_P(SerializesTo, want, "") {
} }
MATCHER_P(PublicSetsAre, sets_matcher, "") { MATCHER_P(PublicSetsAre, sets_matcher, "") {
const network::mojom::PublicFirstPartySetsPtr& public_sets = arg; const net::PublicSets& public_sets = arg;
const base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>& sets = const base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>& sets =
public_sets->sets; public_sets.entries();
return testing::ExplainMatchResult(sets_matcher, sets, result_listener); return testing::ExplainMatchResult(sets_matcher, sets, result_listener);
} }
@@ -70,13 +70,11 @@ class FirstPartySetsLoaderTest : public ::testing::Test {
FirstPartySetsLoader& loader() { return loader_; } FirstPartySetsLoader& loader() { return loader_; }
network::mojom::PublicFirstPartySetsPtr WaitAndGetResult() { net::PublicSets WaitAndGetResult() { return future_.Take(); }
return future_.Take();
}
private: private:
base::test::TaskEnvironment env_; base::test::TaskEnvironment env_;
base::test::TestFuture<network::mojom::PublicFirstPartySetsPtr> future_; base::test::TestFuture<net::PublicSets> future_;
FirstPartySetsLoader loader_; FirstPartySetsLoader loader_;
}; };

@@ -52,6 +52,7 @@
#include "mojo/public/cpp/bindings/remote.h" #include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "net/base/features.h" #include "net/base/features.h"
#include "net/first_party_sets/public_sets.h"
#include "net/log/net_log_util.h" #include "net/log/net_log_util.h"
#include "sandbox/policy/features.h" #include "sandbox/policy/features.h"
#include "services/cert_verifier/cert_verifier_service_factory.h" #include "services/cert_verifier/cert_verifier_service_factory.h"
@@ -621,13 +622,11 @@ network::mojom::NetworkService* GetNetworkService() {
} }
if (FirstPartySetsHandlerImpl::GetInstance()->IsEnabled()) { if (FirstPartySetsHandlerImpl::GetInstance()->IsEnabled()) {
if (absl::optional<network::mojom::PublicFirstPartySetsPtr> sets = if (absl::optional<net::PublicSets> sets =
FirstPartySetsHandlerImpl::GetInstance()->GetSets( FirstPartySetsHandlerImpl::GetInstance()->GetSets(
base::BindOnce( base::BindOnce([](net::PublicSets sets) {
[](network::mojom::PublicFirstPartySetsPtr sets) { GetNetworkService()->SetFirstPartySets(std::move(sets));
GetNetworkService()->SetFirstPartySets( }));
std::move(sets));
}));
sets.has_value()) { sets.has_value()) {
g_network_service_remote->get()->SetFirstPartySets( g_network_service_remote->get()->SetFirstPartySets(
std::move(sets.value())); std::move(sets.value()));

@@ -544,6 +544,8 @@ component("net") {
"first_party_sets/first_party_set_metadata.h", "first_party_sets/first_party_set_metadata.h",
"first_party_sets/first_party_sets_context_config.cc", "first_party_sets/first_party_sets_context_config.cc",
"first_party_sets/first_party_sets_context_config.h", "first_party_sets/first_party_sets_context_config.h",
"first_party_sets/public_sets.cc",
"first_party_sets/public_sets.h",
"first_party_sets/same_party_context.cc", "first_party_sets/same_party_context.cc",
"first_party_sets/same_party_context.h", "first_party_sets/same_party_context.h",
"http/alternative_service.cc", "http/alternative_service.cc",
@@ -4156,6 +4158,7 @@ test("net_unittests") {
"extras/sqlite/sqlite_persistent_cookie_store_unittest.cc", "extras/sqlite/sqlite_persistent_cookie_store_unittest.cc",
"filter/filter_source_stream_unittest.cc", "filter/filter_source_stream_unittest.cc",
"filter/gzip_source_stream_unittest.cc", "filter/gzip_source_stream_unittest.cc",
"first_party_sets/public_sets_unittest.cc",
"http/alternative_service_unittest.cc", "http/alternative_service_unittest.cc",
"http/bidirectional_stream_unittest.cc", "http/bidirectional_stream_unittest.cc",
"http/broken_alternative_services_unittest.cc", "http/broken_alternative_services_unittest.cc",

@@ -0,0 +1,90 @@
// Copyright 2022 The Chromium Authors. All rights reserved.
// 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/public_sets.h"
#include <tuple>
#include "net/base/schemeful_site.h"
#include "net/first_party_sets/first_party_set_entry.h"
#include "net/first_party_sets/first_party_sets_context_config.h"
namespace net {
namespace {
// Converts WS to HTTP, and WSS to HTTPS.
SchemefulSite NormalizeScheme(const SchemefulSite& site) {
SchemefulSite normalized_site = site;
normalized_site.ConvertWebSocketToHttp();
return normalized_site;
}
} // namespace
PublicSets::PublicSets() = default;
PublicSets::PublicSets(
base::flat_map<SchemefulSite, FirstPartySetEntry> entries,
base::flat_map<SchemefulSite, SchemefulSite> aliases)
: entries_(std::move(entries)), aliases_(std::move(aliases)) {}
PublicSets::PublicSets(PublicSets&&) = default;
PublicSets& PublicSets::operator=(PublicSets&&) = default;
PublicSets::~PublicSets() = default;
bool PublicSets::operator==(const PublicSets& other) const {
return std::tie(entries_, aliases_) ==
std::tie(other.entries_, other.aliases_);
}
bool PublicSets::operator!=(const PublicSets& other) const {
return !(*this == other);
}
PublicSets PublicSets::Clone() const {
return PublicSets(entries_, aliases_);
}
absl::optional<FirstPartySetEntry> PublicSets::FindEntry(
const SchemefulSite& site,
const FirstPartySetsContextConfig* fps_context_config) const {
SchemefulSite normalized_site = NormalizeScheme(site);
// Check if `normalized_site` can be found in the customizations first.
// If not, fall back to look up in `entries_`.
if (fps_context_config) {
if (const auto config_it =
fps_context_config->customizations().find(normalized_site);
config_it != fps_context_config->customizations().end()) {
return config_it->second;
}
}
const auto canonical_it = aliases_.find(normalized_site);
const SchemefulSite& canonical_site =
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;
}
return absl::nullopt;
}
std::ostream& operator<<(std::ostream& os, const PublicSets& ps) {
os << "entries = {";
for (const auto& [site, entry] : ps.entries()) {
os << "{" << site.Serialize() << ": " << entry << "}, ";
}
os << "}, aliases = {";
for (const auto& [alias, canonical] : ps.aliases()) {
os << "{" << alias.Serialize() << ": " << canonical.Serialize() << "}, ";
}
os << "}";
return os;
}
} // namespace net

@@ -0,0 +1,67 @@
// Copyright 2022 The Chromium Authors. All rights reserved.
// 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_PUBLIC_SETS_H_
#define NET_FIRST_PARTY_SETS_PUBLIC_SETS_H_
#include "base/containers/flat_map.h"
#include "net/base/net_export.h"
#include "net/base/schemeful_site.h"
#include "net/first_party_sets/first_party_set_entry.h"
namespace net {
class FirstPartySetsContextConfig;
// This class holds all of the info associated with the public First-Party
// Sets, after they've been parsed. This is suitable for plumbing from the
// browser process to the network service, or for answering queries.
class NET_EXPORT PublicSets {
public:
PublicSets();
PublicSets(base::flat_map<SchemefulSite, FirstPartySetEntry> entries,
base::flat_map<SchemefulSite, SchemefulSite> aliases);
PublicSets(PublicSets&&);
PublicSets& operator=(PublicSets&&);
~PublicSets();
bool operator==(const PublicSets& other) const;
bool operator!=(const PublicSets& other) const;
const base::flat_map<SchemefulSite, FirstPartySetEntry>& entries() const {
return entries_;
}
const base::flat_map<SchemefulSite, SchemefulSite>& aliases() const {
return aliases_;
}
// Creates a clone of this instance.
PublicSets Clone() const;
// Returns the entry corresponding to the given `site`, if one exists.
// Respects any customization/overlay specified by `config`. This is
// semi-agnostic to scheme: it just cares whether the scheme is secure or
// insecure.
absl::optional<FirstPartySetEntry> FindEntry(
const SchemefulSite& site,
const FirstPartySetsContextConfig* config) const;
private:
// Represents the mapping of site -> entry, where keys are sites within sets,
// and values are entries of the sets.
base::flat_map<SchemefulSite, FirstPartySetEntry> entries_;
// The site aliases. Used to normalize a given SchemefulSite into its
// canonical representative, before looking it up in `entries_`.
base::flat_map<SchemefulSite, SchemefulSite> aliases_;
};
NET_EXPORT std::ostream& operator<<(std::ostream& os, const PublicSets& ps);
} // namespace net
#endif // NET_FIRST_PARTY_SETS_FIRST_PARTY_SET_ENTRY_H_

@@ -0,0 +1,167 @@
// Copyright 2022 The Chromium Authors. All rights reserved.
// 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/public_sets.h"
#include <set>
#include <string>
#include "base/containers/flat_map.h"
#include "net/base/schemeful_site.h"
#include "net/first_party_sets/first_party_set_entry.h"
#include "net/first_party_sets/first_party_sets_context_config.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
using ::testing::Optional;
namespace net {
class PublicSetsTest : public ::testing::Test {
public:
PublicSetsTest() = default;
FirstPartySetsContextConfig* config() { return &fps_context_config_; }
private:
FirstPartySetsContextConfig fps_context_config_;
};
TEST_F(PublicSetsTest, FindEntry_Nonexistent) {
SchemefulSite example(GURL("https://example.test"));
EXPECT_THAT(PublicSets().FindEntry(example, config()), absl::nullopt);
}
TEST_F(PublicSetsTest, FindEntry_Exists) {
SchemefulSite example(GURL("https://example.test"));
SchemefulSite decoy_site(GURL("https://decoy.test"));
FirstPartySetEntry entry(example, SiteType::kPrimary, absl::nullopt);
FirstPartySetEntry decoy_entry(example, SiteType::kAssociated, 1);
EXPECT_THAT(PublicSets(
{
{example, entry},
{decoy_site, decoy_entry},
},
{})
.FindEntry(example, config()),
Optional(entry));
}
TEST_F(PublicSetsTest, FindEntry_ExistsWhenNormalized) {
SchemefulSite https_example(GURL("https://example.test"));
SchemefulSite wss_example(GURL("wss://example.test"));
FirstPartySetEntry entry(https_example, SiteType::kPrimary, absl::nullopt);
EXPECT_THAT(PublicSets(
{
{https_example, entry},
},
{})
.FindEntry(wss_example, config()),
Optional(entry));
}
TEST_F(PublicSetsTest, FindEntry_ExistsViaOverride) {
SchemefulSite example(GURL("https://example.test"));
FirstPartySetEntry public_entry(example, SiteType::kPrimary, absl::nullopt);
FirstPartySetEntry override_entry(example, SiteType::kAssociated, 1);
config()->SetCustomizations({{example, override_entry}});
EXPECT_THAT(PublicSets(
{
{example, public_entry},
},
{})
.FindEntry(example, config()),
Optional(override_entry));
}
TEST_F(PublicSetsTest, FindEntry_RemovedViaOverride) {
SchemefulSite example(GURL("https://example.test"));
FirstPartySetEntry public_entry(example, SiteType::kPrimary, absl::nullopt);
config()->SetCustomizations({{example, absl::nullopt}});
EXPECT_THAT(PublicSets(
{
{example, public_entry},
},
{})
.FindEntry(example, config()),
absl::nullopt);
}
TEST_F(PublicSetsTest, FindEntry_ExistsViaAlias) {
SchemefulSite example(GURL("https://example.test"));
SchemefulSite example_cctld(GURL("https://example.cctld"));
FirstPartySetEntry entry(example, SiteType::kPrimary, absl::nullopt);
EXPECT_THAT(PublicSets(
{
{example, entry},
},
{{example_cctld, example}})
.FindEntry(example_cctld, config()),
Optional(entry));
}
TEST_F(PublicSetsTest, FindEntry_ExistsViaOverrideWithDecoyAlias) {
SchemefulSite example(GURL("https://example.test"));
SchemefulSite example_cctld(GURL("https://example.cctld"));
FirstPartySetEntry public_entry(example, SiteType::kPrimary, absl::nullopt);
FirstPartySetEntry override_entry(example, SiteType::kAssociated, 1);
config()->SetCustomizations({{example_cctld, override_entry}});
EXPECT_THAT(PublicSets(
{
{example, public_entry},
},
{{example_cctld, example}})
.FindEntry(example_cctld, config()),
Optional(override_entry));
}
TEST_F(PublicSetsTest, FindEntry_RemovedViaOverrideWithDecoyAlias) {
SchemefulSite example(GURL("https://example.test"));
SchemefulSite example_cctld(GURL("https://example.cctld"));
FirstPartySetEntry public_entry(example, SiteType::kPrimary, absl::nullopt);
config()->SetCustomizations({{example_cctld, absl::nullopt}});
EXPECT_THAT(PublicSets(
{
{example, public_entry},
},
{{example_cctld, example}})
.FindEntry(example_cctld, config()),
absl::nullopt);
}
TEST_F(PublicSetsTest, FindEntry_AliasesIgnoredForConfig) {
SchemefulSite example(GURL("https://example.test"));
SchemefulSite example_cctld(GURL("https://example.cctld"));
FirstPartySetEntry public_entry(example, SiteType::kPrimary, absl::nullopt);
FirstPartySetEntry override_entry(example, SiteType::kAssociated, 1);
config()->SetCustomizations({{example, override_entry}});
// FindEntry should ignore aliases when using the customizations. Public
// aliases only apply to sites in the public sets.
EXPECT_THAT(PublicSets(
{
{example, public_entry},
},
{{example_cctld, example}})
.FindEntry(example_cctld, config()),
public_entry);
}
} // namespace net

@@ -16,8 +16,8 @@
#include "net/base/schemeful_site.h" #include "net/base/schemeful_site.h"
#include "net/first_party_sets/first_party_set_entry.h" #include "net/first_party_sets/first_party_set_entry.h"
#include "net/first_party_sets/first_party_set_metadata.h" #include "net/first_party_sets/first_party_set_metadata.h"
#include "net/first_party_sets/public_sets.h"
#include "net/first_party_sets/same_party_context.h" #include "net/first_party_sets/same_party_context.h"
#include "services/network/public/mojom/first_party_sets.mojom.h"
#include "services/network/public/mojom/first_party_sets_access_delegate.mojom.h" #include "services/network/public/mojom/first_party_sets_access_delegate.mojom.h"
#include "testing/gmock/include/gmock/gmock-matchers.h" #include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
@@ -60,14 +60,6 @@ mojom::FirstPartySetsReadyEventPtr CreateFirstPartySetsReadyEvent(
return ready_event; return ready_event;
} }
mojom::PublicFirstPartySetsPtr CreatePublicFirstPartySets(
FirstPartySetsAccessDelegate::FlattenedSets sets) {
mojom::PublicFirstPartySetsPtr public_sets =
mojom::PublicFirstPartySets::New();
public_sets->sets = sets;
return public_sets;
}
} // namespace } // namespace
// No-op FirstPartySetsAccessDelegate should just pass queries to // No-op FirstPartySetsAccessDelegate should just pass queries to
@@ -80,18 +72,23 @@ class NoopFirstPartySetsAccessDelegateTest : public ::testing::Test {
/*receiver=*/mojo::NullReceiver(), /*receiver=*/mojo::NullReceiver(),
/*params=*/nullptr, /*params=*/nullptr,
&first_party_sets_manager_) { &first_party_sets_manager_) {
first_party_sets_manager_.SetCompleteSets(CreatePublicFirstPartySets({ first_party_sets_manager_.SetCompleteSets(net::PublicSets(
{kSet1Member1, /*entries=*/
net::FirstPartySetEntry(kSet1Owner, net::SiteType::kAssociated, 0)}, {
{kSet1Member2, {kSet1Member1, net::FirstPartySetEntry(
net::FirstPartySetEntry(kSet1Owner, net::SiteType::kAssociated, 1)}, kSet1Owner, net::SiteType::kAssociated, 0)},
{kSet1Owner, net::FirstPartySetEntry( {kSet1Member2, net::FirstPartySetEntry(
kSet1Owner, net::SiteType::kPrimary, absl::nullopt)}, kSet1Owner, net::SiteType::kAssociated, 1)},
{kSet2Member1, {kSet1Owner,
net::FirstPartySetEntry(kSet2Owner, net::SiteType::kAssociated, 0)}, net::FirstPartySetEntry(kSet1Owner, net::SiteType::kPrimary,
{kSet2Owner, net::FirstPartySetEntry( absl::nullopt)},
kSet2Owner, net::SiteType::kPrimary, absl::nullopt)}, {kSet2Member1, net::FirstPartySetEntry(
})); kSet2Owner, net::SiteType::kAssociated, 0)},
{kSet2Owner,
net::FirstPartySetEntry(kSet2Owner, net::SiteType::kPrimary,
absl::nullopt)},
},
/*aliases=*/{}));
} }
FirstPartySetsAccessDelegate& delegate() { return delegate_; } FirstPartySetsAccessDelegate& delegate() { return delegate_; }
@@ -132,18 +129,23 @@ class FirstPartySetsAccessDelegateTest : public ::testing::Test {
delegate_(delegate_remote_.BindNewPipeAndPassReceiver(), delegate_(delegate_remote_.BindNewPipeAndPassReceiver(),
CreateFirstPartySetsAccessDelegateParams(enabled), CreateFirstPartySetsAccessDelegateParams(enabled),
&first_party_sets_manager_) { &first_party_sets_manager_) {
first_party_sets_manager_.SetCompleteSets(CreatePublicFirstPartySets({ first_party_sets_manager_.SetCompleteSets(net::PublicSets(
{kSet1Member1, /*entries=*/
net::FirstPartySetEntry(kSet1Owner, net::SiteType::kAssociated, 0)}, {
{kSet1Member2, {kSet1Member1, net::FirstPartySetEntry(
net::FirstPartySetEntry(kSet1Owner, net::SiteType::kAssociated, 1)}, kSet1Owner, net::SiteType::kAssociated, 0)},
{kSet1Owner, net::FirstPartySetEntry( {kSet1Member2, net::FirstPartySetEntry(
kSet1Owner, net::SiteType::kPrimary, absl::nullopt)}, kSet1Owner, net::SiteType::kAssociated, 1)},
{kSet2Member1, {kSet1Owner,
net::FirstPartySetEntry(kSet2Owner, net::SiteType::kAssociated, 0)}, net::FirstPartySetEntry(kSet1Owner, net::SiteType::kPrimary,
{kSet2Owner, net::FirstPartySetEntry( absl::nullopt)},
kSet2Owner, net::SiteType::kPrimary, absl::nullopt)}, {kSet2Member1, net::FirstPartySetEntry(
})); kSet2Owner, net::SiteType::kAssociated, 0)},
{kSet2Owner,
net::FirstPartySetEntry(kSet2Owner, net::SiteType::kPrimary,
absl::nullopt)},
},
/*aliases=*/{}));
} }
net::FirstPartySetMetadata ComputeMetadataAndWait( net::FirstPartySetMetadata ComputeMetadataAndWait(

@@ -24,8 +24,8 @@
#include "net/base/schemeful_site.h" #include "net/base/schemeful_site.h"
#include "net/first_party_sets/first_party_set_entry.h" #include "net/first_party_sets/first_party_set_entry.h"
#include "net/first_party_sets/first_party_set_metadata.h" #include "net/first_party_sets/first_party_set_metadata.h"
#include "net/first_party_sets/public_sets.h"
#include "net/first_party_sets/same_party_context.h" #include "net/first_party_sets/same_party_context.h"
#include "services/network/public/mojom/first_party_sets.mojom.h"
#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/abseil-cpp/absl/types/optional.h"
namespace network { namespace network {
@@ -45,7 +45,7 @@ FirstPartySetsManager::FirstPartySetsManager(bool enabled)
enabled ? std::make_unique<base::circular_deque<base::OnceClosure>>() enabled ? std::make_unique<base::circular_deque<base::OnceClosure>>()
: nullptr) { : nullptr) {
if (!enabled) if (!enabled)
SetCompleteSets(mojom::PublicFirstPartySets::New()); SetCompleteSets(net::PublicSets());
} }
FirstPartySetsManager::~FirstPartySetsManager() { FirstPartySetsManager::~FirstPartySetsManager() {
@@ -154,29 +154,9 @@ absl::optional<net::FirstPartySetEntry> FirstPartySetsManager::FindEntry(
DCHECK(sets_.has_value()); DCHECK(sets_.has_value());
const base::ElapsedTimer timer; const base::ElapsedTimer timer;
net::SchemefulSite normalized_site = site; absl::optional<net::FirstPartySetEntry> entry =
normalized_site.ConvertWebSocketToHttp(); is_enabled() ? sets_->FindEntry(site, &fps_context_config)
: absl::nullopt;
absl::optional<net::FirstPartySetEntry> entry;
if (is_enabled()) {
// Check if `normalized_site` can be found in the customizations first.
// If not, fall back to look up in `sets_`.
if (const auto customizations_it =
fps_context_config.customizations().find(normalized_site);
customizations_it != fps_context_config.customizations().end()) {
entry = customizations_it->second;
} else {
const auto canonical_it = aliases_.find(normalized_site);
const net::SchemefulSite& canonical_site = canonical_it == aliases_.end()
? normalized_site
: canonical_it->second;
if (const auto sets_it = sets_->find(canonical_site);
sets_it != sets_->end()) {
entry = sets_it->second;
}
}
}
UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
"Cookie.FirstPartySets.FindOwner.Latency", timer.Elapsed(), "Cookie.FirstPartySets.FindOwner.Latency", timer.Elapsed(),
@@ -260,13 +240,11 @@ void FirstPartySetsManager::InvokePendingQueries() {
pending_queries_ = nullptr; pending_queries_ = nullptr;
} }
void FirstPartySetsManager::SetCompleteSets( void FirstPartySetsManager::SetCompleteSets(net::PublicSets public_sets) {
mojom::PublicFirstPartySetsPtr public_sets) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (sets_.has_value()) if (sets_.has_value())
return; return;
sets_ = std::move(public_sets->sets); sets_ = std::move(public_sets);
aliases_ = std::move(public_sets->aliases);
InvokePendingQueries(); InvokePendingQueries();
} }

@@ -21,7 +21,7 @@
#include "net/first_party_sets/first_party_set_entry.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_set_metadata.h"
#include "net/first_party_sets/first_party_sets_context_config.h" #include "net/first_party_sets/first_party_sets_context_config.h"
#include "services/network/public/mojom/first_party_sets.mojom.h" #include "net/first_party_sets/public_sets.h"
#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/abseil-cpp/absl/types/optional.h"
namespace network { namespace network {
@@ -63,7 +63,7 @@ class FirstPartySetsManager {
// //
// Only the first call to SetCompleteSets can have any effect; subsequent // Only the first call to SetCompleteSets can have any effect; subsequent
// invocations are ignored. // invocations are ignored.
void SetCompleteSets(mojom::PublicFirstPartySetsPtr public_sets); void SetCompleteSets(net::PublicSets public_sets);
// Sets the enabled_ attribute for testing. // Sets the enabled_ attribute for testing.
void SetEnabledForTesting(bool enabled); void SetEnabledForTesting(bool enabled);
@@ -146,18 +146,11 @@ class FirstPartySetsManager {
// initialized. // initialized.
void InvokePendingQueries(); void InvokePendingQueries();
// Represents the mapping of site -> site, where keys are members of sets, and // The actual public sets data.
// values are owners of the sets. Owners are explicitly represented as members
// of the set.
// //
// Optional because it is unset until all of the required inputs have been // Optional because it is unset until the data has been received from the
// received. // browser process.
absl::optional<FlattenedSets> sets_ GUARDED_BY_CONTEXT(sequence_checker_); absl::optional<net::PublicSets> sets_ GUARDED_BY_CONTEXT(sequence_checker_);
// The site aliases. Used to normalize a given SchemefulSite into its
// canonical representative, before looking it up in `sets_`.
base::flat_map<net::SchemefulSite, net::SchemefulSite> aliases_
GUARDED_BY_CONTEXT(sequence_checker_);
bool enabled_ GUARDED_BY_CONTEXT(sequence_checker_) = false; bool enabled_ GUARDED_BY_CONTEXT(sequence_checker_) = false;

@@ -14,8 +14,8 @@
#include "net/cookies/cookie_constants.h" #include "net/cookies/cookie_constants.h"
#include "net/first_party_sets/first_party_set_entry.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_set_metadata.h"
#include "net/first_party_sets/public_sets.h"
#include "net/first_party_sets/same_party_context.h" #include "net/first_party_sets/same_party_context.h"
#include "services/network/public/mojom/first_party_sets.mojom.h"
#include "testing/gmock/include/gmock/gmock-matchers.h" #include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
@@ -46,11 +46,7 @@ class FirstPartySetsManagerTest : public ::testing::Test {
const base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>& const base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>&
content, content,
const base::flat_map<net::SchemefulSite, net::SchemefulSite>& aliases) { const base::flat_map<net::SchemefulSite, net::SchemefulSite>& aliases) {
network::mojom::PublicFirstPartySetsPtr public_sets = manager_.SetCompleteSets(net::PublicSets(content, aliases));
network::mojom::PublicFirstPartySets::New();
public_sets->sets = content;
public_sets->aliases = aliases;
manager_.SetCompleteSets(std::move(public_sets));
} }
net::FirstPartySetMetadata ComputeMetadataAndWait( net::FirstPartySetMetadata ComputeMetadataAndWait(

@@ -51,6 +51,7 @@
#include "net/dns/public/doh_provider_entry.h" #include "net/dns/public/doh_provider_entry.h"
#include "net/dns/system_dns_config_change_notifier.h" #include "net/dns/system_dns_config_change_notifier.h"
#include "net/dns/test_dns_config_service.h" #include "net/dns/test_dns_config_service.h"
#include "net/first_party_sets/public_sets.h"
#include "net/http/http_auth_handler_factory.h" #include "net/http/http_auth_handler_factory.h"
#include "net/log/file_net_log_observer.h" #include "net/log/file_net_log_observer.h"
#include "net/log/net_log.h" #include "net/log/net_log.h"
@@ -73,7 +74,6 @@
#include "services/network/public/cpp/load_info_util.h" #include "services/network/public/cpp/load_info_util.h"
#include "services/network/public/cpp/network_switches.h" #include "services/network/public/cpp/network_switches.h"
#include "services/network/public/cpp/parsed_headers.h" #include "services/network/public/cpp/parsed_headers.h"
#include "services/network/public/mojom/first_party_sets.mojom.h"
#include "services/network/public/mojom/key_pinning.mojom.h" #include "services/network/public/mojom/key_pinning.mojom.h"
#include "services/network/public/mojom/network_service_test.mojom.h" #include "services/network/public/mojom/network_service_test.mojom.h"
#include "services/network/url_loader.h" #include "services/network/url_loader.h"
@@ -790,7 +790,7 @@ void NetworkService::BindTestInterface(
} }
} }
void NetworkService::SetFirstPartySets(mojom::PublicFirstPartySetsPtr sets) { void NetworkService::SetFirstPartySets(net::PublicSets sets) {
first_party_sets_manager_->SetCompleteSets(std::move(sets)); first_party_sets_manager_->SetCompleteSets(std::move(sets));
} }

@@ -32,6 +32,7 @@
#include "net/dns/host_resolver.h" #include "net/dns/host_resolver.h"
#include "net/dns/public/dns_over_https_config.h" #include "net/dns/public/dns_over_https_config.h"
#include "net/dns/public/secure_dns_mode.h" #include "net/dns/public/secure_dns_mode.h"
#include "net/first_party_sets/public_sets.h"
#include "net/http/transport_security_state.h" #include "net/http/transport_security_state.h"
#include "net/log/net_log.h" #include "net/log/net_log.h"
#include "net/log/trace_net_log_observer.h" #include "net/log/trace_net_log_observer.h"
@@ -41,7 +42,6 @@
#include "services/network/network_change_manager.h" #include "services/network/network_change_manager.h"
#include "services/network/network_quality_estimator_manager.h" #include "services/network/network_quality_estimator_manager.h"
#include "services/network/public/cpp/network_service_buildflags.h" #include "services/network/public/cpp/network_service_buildflags.h"
#include "services/network/public/mojom/first_party_sets.mojom.h"
#include "services/network/public/mojom/host_resolver.mojom.h" #include "services/network/public/mojom/host_resolver.mojom.h"
#include "services/network/public/mojom/key_pinning.mojom.h" #include "services/network/public/mojom/key_pinning.mojom.h"
#include "services/network/public/mojom/net_log.mojom.h" #include "services/network/public/mojom/net_log.mojom.h"
@@ -212,7 +212,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService
#endif #endif
void BindTestInterface( void BindTestInterface(
mojo::PendingReceiver<mojom::NetworkServiceTest> receiver) override; mojo::PendingReceiver<mojom::NetworkServiceTest> receiver) override;
void SetFirstPartySets(mojom::PublicFirstPartySetsPtr sets) override; void SetFirstPartySets(net::PublicSets sets) override;
void SetExplicitlyAllowedPorts(const std::vector<uint16_t>& ports) override; void SetExplicitlyAllowedPorts(const std::vector<uint16_t>& ports) override;
// Returns an HttpAuthHandlerFactory for the given NetworkContext. // Returns an HttpAuthHandlerFactory for the given NetworkContext.

@@ -4,12 +4,14 @@
#include "services/network/public/cpp/first_party_sets_mojom_traits.h" #include "services/network/public/cpp/first_party_sets_mojom_traits.h"
#include "base/containers/flat_map.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/types/optional_util.h" #include "base/types/optional_util.h"
#include "mojo/public/cpp/bindings/enum_traits.h" #include "mojo/public/cpp/bindings/enum_traits.h"
#include "net/base/schemeful_site.h" #include "net/base/schemeful_site.h"
#include "net/first_party_sets/first_party_set_entry.h" #include "net/first_party_sets/first_party_set_entry.h"
#include "net/first_party_sets/first_party_set_metadata.h" #include "net/first_party_sets/first_party_set_metadata.h"
#include "net/first_party_sets/public_sets.h"
#include "net/first_party_sets/same_party_context.h" #include "net/first_party_sets/same_party_context.h"
#include "services/network/public/cpp/schemeful_site_mojom_traits.h" #include "services/network/public/cpp/schemeful_site_mojom_traits.h"
#include "services/network/public/mojom/first_party_sets.mojom-shared.h" #include "services/network/public/mojom/first_party_sets.mojom-shared.h"
@@ -140,4 +142,21 @@ bool StructTraits<network::mojom::FirstPartySetMetadataDataView,
return true; return true;
} }
bool StructTraits<network::mojom::PublicFirstPartySetsDataView,
net::PublicSets>::
Read(network::mojom::PublicFirstPartySetsDataView public_sets,
net::PublicSets* out_public_sets) {
base::flat_map<net::SchemefulSite, net::FirstPartySetEntry> entries;
if (!public_sets.ReadSets(&entries))
return false;
base::flat_map<net::SchemefulSite, net::SchemefulSite> aliases;
if (!public_sets.ReadAliases(&aliases))
return false;
*out_public_sets = net::PublicSets(entries, aliases);
return true;
}
} // namespace mojo } // namespace mojo

@@ -5,10 +5,12 @@
#ifndef SERVICES_NETWORK_PUBLIC_CPP_FIRST_PARTY_SETS_MOJOM_TRAITS_H_ #ifndef SERVICES_NETWORK_PUBLIC_CPP_FIRST_PARTY_SETS_MOJOM_TRAITS_H_
#define SERVICES_NETWORK_PUBLIC_CPP_FIRST_PARTY_SETS_MOJOM_TRAITS_H_ #define SERVICES_NETWORK_PUBLIC_CPP_FIRST_PARTY_SETS_MOJOM_TRAITS_H_
#include "base/containers/flat_map.h"
#include "mojo/public/cpp/bindings/enum_traits.h" #include "mojo/public/cpp/bindings/enum_traits.h"
#include "net/base/schemeful_site.h" #include "net/base/schemeful_site.h"
#include "net/first_party_sets/first_party_set_entry.h" #include "net/first_party_sets/first_party_set_entry.h"
#include "net/first_party_sets/first_party_set_metadata.h" #include "net/first_party_sets/first_party_set_metadata.h"
#include "net/first_party_sets/public_sets.h"
#include "net/first_party_sets/same_party_context.h" #include "net/first_party_sets/same_party_context.h"
#include "services/network/public/mojom/first_party_sets.mojom-shared.h" #include "services/network/public/mojom/first_party_sets.mojom-shared.h"
@@ -101,6 +103,24 @@ struct COMPONENT_EXPORT(FIRST_PARTY_SETS_MOJOM_TRAITS)
net::FirstPartySetMetadata* out); net::FirstPartySetMetadata* out);
}; };
template <>
struct COMPONENT_EXPORT(FIRST_PARTY_SETS_MOJOM_TRAITS)
StructTraits<network::mojom::PublicFirstPartySetsDataView,
net::PublicSets> {
static const base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>&
sets(const net::PublicSets& p) {
return p.entries();
}
static const base::flat_map<net::SchemefulSite, net::SchemefulSite>& aliases(
const net::PublicSets& p) {
return p.aliases();
}
static bool Read(network::mojom::PublicFirstPartySetsDataView public_sets,
net::PublicSets* out_public_sets);
};
} // namespace mojo } // namespace mojo
#endif // SERVICES_NETWORK_PUBLIC_CPP_FIRST_PARTY_SETS_MOJOM_TRAITS_H_ #endif // SERVICES_NETWORK_PUBLIC_CPP_FIRST_PARTY_SETS_MOJOM_TRAITS_H_

@@ -4,11 +4,13 @@
#include "services/network/public/cpp/first_party_sets_mojom_traits.h" #include "services/network/public/cpp/first_party_sets_mojom_traits.h"
#include "base/containers/flat_map.h"
#include "base/test/gtest_util.h" #include "base/test/gtest_util.h"
#include "mojo/public/cpp/test_support/test_utils.h" #include "mojo/public/cpp/test_support/test_utils.h"
#include "net/base/schemeful_site.h" #include "net/base/schemeful_site.h"
#include "net/first_party_sets/first_party_set_entry.h" #include "net/first_party_sets/first_party_set_entry.h"
#include "net/first_party_sets/first_party_set_metadata.h" #include "net/first_party_sets/first_party_set_metadata.h"
#include "net/first_party_sets/public_sets.h"
#include "services/network/public/mojom/first_party_sets.mojom.h" #include "services/network/public/mojom/first_party_sets.mojom.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h" #include "url/gurl.h"
@@ -115,5 +117,32 @@ TEST(FirstPartySetsTraitsTest, Roundtrips_FirstPartySetMetadata) {
EXPECT_EQ(round_tripped, make_metadata()); EXPECT_EQ(round_tripped, make_metadata());
} }
TEST(FirstPartySetsTraitsTest, RoundTrips_PublicFirstPartySets) {
net::SchemefulSite a(GURL("https://a.test"));
net::SchemefulSite b(GURL("https://b.test"));
net::SchemefulSite b_cctld(GURL("https://b.cctld"));
net::SchemefulSite c(GURL("https://c.test"));
const net::PublicSets original(
{
{a,
net::FirstPartySetEntry(a, net::SiteType::kPrimary, absl::nullopt)},
{b, net::FirstPartySetEntry(a, net::SiteType::kAssociated, 0)},
{c,
net::FirstPartySetEntry(a, net::SiteType::kService, absl::nullopt)},
},
{{b_cctld, b}});
net::PublicSets round_tripped;
EXPECT_TRUE(
mojo::test::SerializeAndDeserialize<network::mojom::PublicFirstPartySets>(
original, round_tripped));
EXPECT_EQ(original, round_tripped);
EXPECT_FALSE(round_tripped.entries().empty());
EXPECT_FALSE(round_tripped.aliases().empty());
}
} // namespace } // namespace
} // namespace network } // namespace network

@@ -776,6 +776,11 @@ mojom("mojom_first_party_sets") {
cpp = "::net::FirstPartySetMetadata" cpp = "::net::FirstPartySetMetadata"
move_only = true move_only = true
}, },
{
mojom = "network.mojom.PublicFirstPartySets"
cpp = "::net::PublicSets"
move_only = true
},
] ]
traits_headers = [ traits_headers = [
"//services/network/public/cpp/first_party_sets_mojom_traits.h", "//services/network/public/cpp/first_party_sets_mojom_traits.h",

@@ -53,9 +53,8 @@ struct FirstPartySetMetadata {
FirstPartySetEntry? top_frame_entry; FirstPartySetEntry? top_frame_entry;
}; };
// This struct holds all of the info associated with the public First-Party // This struct must match the class fields defined in
// Sets, after they've been parsed. This is suitable for plumbing from the // //net/first_party_sets/public_sets.h.
// browser process to the network service.
struct PublicFirstPartySets { struct PublicFirstPartySets {
// The mapping from site to FPS entry. // The mapping from site to FPS entry.
map<SchemefulSite, FirstPartySetEntry> sets; map<SchemefulSite, FirstPartySetEntry> sets;

@@ -34,13 +34,13 @@
#include "net/cookies/site_for_cookies.h" #include "net/cookies/site_for_cookies.h"
#include "net/cookies/test_cookie_access_delegate.h" #include "net/cookies/test_cookie_access_delegate.h"
#include "net/first_party_sets/first_party_set_metadata.h" #include "net/first_party_sets/first_party_set_metadata.h"
#include "net/first_party_sets/public_sets.h"
#include "net/first_party_sets/same_party_context.h" #include "net/first_party_sets/same_party_context.h"
#include "services/network/cookie_access_delegate_impl.h" #include "services/network/cookie_access_delegate_impl.h"
#include "services/network/cookie_settings.h" #include "services/network/cookie_settings.h"
#include "services/network/first_party_sets/first_party_sets_access_delegate.h" #include "services/network/first_party_sets/first_party_sets_access_delegate.h"
#include "services/network/public/mojom/cookie_access_observer.mojom.h" #include "services/network/public/mojom/cookie_access_observer.mojom.h"
#include "services/network/public/mojom/cookie_manager.mojom.h" #include "services/network/public/mojom/cookie_manager.mojom.h"
#include "services/network/public/mojom/first_party_sets.mojom.h"
#include "services/network/test/test_network_context_client.h" #include "services/network/test/test_network_context_client.h"
#include "testing/gmock/include/gmock/gmock-matchers.h" #include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
@@ -461,19 +461,19 @@ class SamePartyEnabledRestrictedCookieManagerTest
.BindNewPipeAndPassReceiver(), .BindNewPipeAndPassReceiver(),
CreateFirstPartySetsAccessDelegateParams(), CreateFirstPartySetsAccessDelegateParams(),
&first_party_sets_manager_) { &first_party_sets_manager_) {
network::mojom::PublicFirstPartySetsPtr public_sets = first_party_sets_manager_.SetCompleteSets(net::PublicSets(
network::mojom::PublicFirstPartySets::New(); /*entries=*/
public_sets->sets = { {
{net::SchemefulSite(GURL("https://example.com")), {net::SchemefulSite(GURL("https://example.com")),
net::FirstPartySetEntry( net::FirstPartySetEntry(
net::SchemefulSite(GURL("https://example.com")), net::SchemefulSite(GURL("https://example.com")),
net::SiteType::kPrimary, absl::nullopt)}, net::SiteType::kPrimary, absl::nullopt)},
{net::SchemefulSite(GURL("https://member1.com")), {net::SchemefulSite(GURL("https://member1.com")),
net::FirstPartySetEntry( net::FirstPartySetEntry(
net::SchemefulSite(GURL("https://example.com")), net::SchemefulSite(GURL("https://example.com")),
net::SiteType::kAssociated, 0)}, net::SiteType::kAssociated, 0)},
}; },
first_party_sets_manager_.SetCompleteSets(std::move(public_sets)); /*aliases=*/{}));
first_party_sets_access_delegate_remote_->NotifyReady( first_party_sets_access_delegate_remote_->NotifyReady(
mojom::FirstPartySetsReadyEvent::New()); mojom::FirstPartySetsReadyEvent::New());
auto cookie_access_delegate = std::make_unique<CookieAccessDelegateImpl>( auto cookie_access_delegate = std::make_unique<CookieAccessDelegateImpl>(