Files
electron/patches/chromium/cherry-pick-ec42dfd3545f.patch
Keeley Hammond 9e0a182821 chore: cherry-pick ec42dfd3545f from chromium (#31331)
* chore: cherry-pick ec42dfd3545f from chromium

* chore: cherry-pick 39090918efac from chromium

* chore: reconcile FPS patch differences

Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
2021-10-11 13:03:53 +02:00

627 lines
24 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shuran Huang <shuuran@chromium.org>
Date: Fri, 24 Sep 2021 00:47:47 +0000
Subject: Add functions to pass in persisted FPSs and compute diffs.
Pass the persisted FPSs and a callback that takes a FPSs into Network
Service. The persisted FPSs is parsed and compared to the current FPSs
in the FirstPartySets class, then call the callback with the current
FPSs. The function that passes in the persisted FPSs and the callback
has not been called anywhere yet.
Bug: 1219656
Change-Id: I08c531aa08d3aeeb772c1eb9a3a453a07b0349d3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3103693
Commit-Queue: Shuran Huang <shuuran@chromium.org>
Reviewed-by: Will Harris <wfh@chromium.org>
Reviewed-by: Matt Menke <mmenke@chromium.org>
Reviewed-by: Chris Fredrickson <cfredric@chromium.org>
Cr-Commit-Position: refs/heads/main@{#924570}
diff --git a/services/network/first_party_sets/first_party_sets.cc b/services/network/first_party_sets/first_party_sets.cc
index f7e732e88d6e6ebc5daed9169d5eee336a9de8c1..1650c28d8b6c61b30531e1e2ef3e2869d8450360 100644
--- a/services/network/first_party_sets/first_party_sets.cc
+++ b/services/network/first_party_sets/first_party_sets.cc
@@ -13,6 +13,7 @@
#include "base/logging.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_split.h"
+#include "base/task/post_task.h"
#include "net/base/schemeful_site.h"
#include "net/cookies/cookie_constants.h"
#include "net/cookies/same_party_context.h"
@@ -72,12 +73,16 @@ void FirstPartySets::SetManuallySpecifiedSet(const std::string& flag_value) {
flag_value, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY));
ApplyManuallySpecifiedSet();
+ manual_sets_ready_ = true;
+ ClearSiteDataOnChangedSetsIfReady();
}
base::flat_map<net::SchemefulSite, net::SchemefulSite>*
FirstPartySets::ParseAndSet(base::StringPiece raw_sets) {
sets_ = FirstPartySetParser::ParseSetsFromComponentUpdater(raw_sets);
ApplyManuallySpecifiedSet();
+ component_sets_ready_ = true;
+ ClearSiteDataOnChangedSetsIfReady();
return &sets_;
}
@@ -218,4 +223,48 @@ void FirstPartySets::ApplyManuallySpecifiedSet() {
sets_.emplace(manual_owner, manual_owner);
}
+void FirstPartySets::SetPersistedSets(base::StringPiece raw_sets) {
+ raw_persisted_sets_ = std::string(raw_sets);
+ persisted_sets_ready_ = true;
+ ClearSiteDataOnChangedSetsIfReady();
+}
+
+void FirstPartySets::SetOnSiteDataCleared(
+ base::OnceCallback<void(const std::string&)> callback) {
+ on_site_data_cleared_ = std::move(callback);
+ ClearSiteDataOnChangedSetsIfReady();
+}
+
+base::flat_set<net::SchemefulSite> FirstPartySets::ComputeSetsDiff(
+ const base::flat_map<net::SchemefulSite, net::SchemefulSite>& old_sets) {
+ if (old_sets.empty())
+ return {};
+
+ base::flat_set<net::SchemefulSite> result;
+ for (const auto& old_pair : old_sets) {
+ const net::SchemefulSite& old_member = old_pair.first;
+ const net::SchemefulSite& old_owner = old_pair.second;
+ const net::SchemefulSite* current_owner = FindOwner(old_member, false);
+ // Look for the removed sites and the ones have owner changed.
+ if (!current_owner || *current_owner != old_owner) {
+ result.emplace(old_member);
+ }
+ }
+ return result;
+}
+
+void FirstPartySets::ClearSiteDataOnChangedSetsIfReady() {
+ if (!persisted_sets_ready_ || !component_sets_ready_ || !manual_sets_ready_ ||
+ on_site_data_cleared_.is_null())
+ return;
+
+ base::flat_set<net::SchemefulSite> diff = ComputeSetsDiff(
+ FirstPartySetParser::DeserializeFirstPartySets(raw_persisted_sets_));
+
+ // TODO(shuuran@chromium.org): Implement site state clearing.
+
+ std::move(on_site_data_cleared_)
+ .Run(FirstPartySetParser::SerializeFirstPartySets(sets_));
+}
+
} // namespace network
diff --git a/services/network/first_party_sets/first_party_sets.h b/services/network/first_party_sets/first_party_sets.h
index 81e0e1080d965947a2ebc1635638c25ad75a1bf7..8158b555856526170051cba72a08312a5528de51 100644
--- a/services/network/first_party_sets/first_party_sets.h
+++ b/services/network/first_party_sets/first_party_sets.h
@@ -9,6 +9,7 @@
#include <memory>
#include <set>
+#include "base/callback.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "net/base/schemeful_site.h"
@@ -87,6 +88,14 @@ class FirstPartySets {
// the members of the set includes the owner.
base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>> Sets() const;
+ // Sets the `raw_persisted_sets_`, which is a JSON-encoded
+ // string representation of a map of site -> site.
+ void SetPersistedSets(base::StringPiece persisted_sets);
+ // Sets the `on_site_data_cleared_` callback, which takes input of a
+ // JSON-encoded string representation of a map of site -> site.
+ void SetOnSiteDataCleared(
+ base::OnceCallback<void(const std::string&)> callback);
+
private:
// Returns a pointer to `site`'s owner (optionally inferring a singleton set
// if necessary), or `nullptr` if `site` has no owner. Must not return
@@ -101,6 +110,19 @@ class FirstPartySets {
// `manually_specified_set_`.
void ApplyManuallySpecifiedSet();
+ // Compares the map `old_sets` to `sets_` and returns the set of sites that:
+ // 1) were in `old_sets` but are no longer in `sets_`, i.e. leave the FPSs;
+ // or, 2) mapped to a different owner site.
+ base::flat_set<net::SchemefulSite> ComputeSetsDiff(
+ const base::flat_map<net::SchemefulSite, net::SchemefulSite>& old_sets);
+
+ // Checks the required inputs have been received, and if so, computes the diff
+ // between the `sets_` and the parsed `raw_persisted_sets_`, and clears the
+ // site data of the set of sites based on the diff.
+ //
+ // TODO(shuuran@chromium.org): Implement the code to clear site state.
+ void ClearSiteDataOnChangedSetsIfReady();
+
// Represents the mapping of site -> site, where keys are members of sets, and
// values are owners of the sets. Owners are explicitly represented as members
// of the set.
@@ -108,6 +130,22 @@ class FirstPartySets {
absl::optional<
std::pair<net::SchemefulSite, base::flat_set<net::SchemefulSite>>>
manually_specified_set_;
+
+ std::string raw_persisted_sets_;
+
+ bool persisted_sets_ready_ = false;
+ bool component_sets_ready_ = false;
+ bool manual_sets_ready_ = false;
+
+ // The callback runs after the site state clearing is completed.
+ base::OnceCallback<void(const std::string&)> on_site_data_cleared_;
+
+ FRIEND_TEST_ALL_PREFIXES(FirstPartySets, ComputeSetsDiff_SitesJoined);
+ FRIEND_TEST_ALL_PREFIXES(FirstPartySets, ComputeSetsDiff_SitesLeft);
+ FRIEND_TEST_ALL_PREFIXES(FirstPartySets, ComputeSetsDiff_OwnerChanged);
+ FRIEND_TEST_ALL_PREFIXES(FirstPartySets, ComputeSetsDiff_OwnerLeft);
+ FRIEND_TEST_ALL_PREFIXES(FirstPartySets, ComputeSetsDiff_OwnerMemberRotate);
+ FRIEND_TEST_ALL_PREFIXES(FirstPartySets, ComputeSetsDiff_EmptySets);
};
} // namespace network
diff --git a/services/network/first_party_sets/first_party_sets_unittest.cc b/services/network/first_party_sets/first_party_sets_unittest.cc
index b929315d9b857e0f86d1d726f7cefefb7ad8e54c..2055619f4c999cbfd5a5ee4780e2eb5c1dad5816 100644
--- a/services/network/first_party_sets/first_party_sets_unittest.cc
+++ b/services/network/first_party_sets/first_party_sets_unittest.cc
@@ -7,6 +7,7 @@
#include <initializer_list>
#include "base/json/json_reader.h"
+#include "base/test/bind.h"
#include "net/base/schemeful_site.h"
#include "net/cookies/cookie_constants.h"
#include "net/cookies/same_party_context.h"
@@ -204,6 +205,30 @@ TEST(FirstPartySets, SetsManuallySpecified_Invalid_RegisteredDomain_Member) {
EXPECT_THAT(sets.ParseAndSet("[]"), Pointee(IsEmpty()));
}
+TEST(FirstPartySets, SetsManuallySpecified_Valid_EmptyValue) {
+ FirstPartySets sets;
+ sets.SetManuallySpecifiedSet("");
+
+ // Set non-empty existing sets to distinguish the failure case from the no-op
+ // case when processing the manually-specified sets.
+ const std::string existing_sets = R"(
+ [
+ {
+ "owner": "https://example.test",
+ "members": ["https://member.test"]
+ }
+ ]
+ )";
+ ASSERT_TRUE(base::JSONReader::Read(existing_sets));
+
+ EXPECT_THAT(sets.ParseAndSet(existing_sets),
+ Pointee(UnorderedElementsAre(
+ Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member.test"),
+ SerializesTo("https://example.test")))));
+}
+
TEST(FirstPartySets, SetsManuallySpecified_Valid_SingleMember) {
FirstPartySets sets;
sets.SetManuallySpecifiedSet("https://example.test,https://member.test");
@@ -469,6 +494,311 @@ TEST(FirstPartySets, SetsManuallySpecified_PrunesInducedSingletons) {
SerializesTo("https://example.test")))));
}
+TEST(FirstPartySets, ComputeSetsDiff_SitesJoined) {
+ auto old_sets = base::flat_map<net::SchemefulSite, net::SchemefulSite>{
+ {net::SchemefulSite(GURL("https://example.test")),
+ net::SchemefulSite(GURL("https://example.test"))},
+ {net::SchemefulSite(GURL("https://member1.test")),
+ net::SchemefulSite(GURL("https://example.test"))},
+ {net::SchemefulSite(GURL("https://member3.test")),
+ net::SchemefulSite(GURL("https://example.test"))}};
+
+ // Consistency check the reviewer-friendly JSON format matches the input.
+ ASSERT_THAT(FirstPartySets().ParseAndSet(R"(
+ [
+ {
+ "owner": "https://example.test",
+ "members": ["https://member1.test", "https://member3.test"]
+ }
+ ]
+ )"),
+ Pointee(old_sets));
+
+ FirstPartySets sets;
+ sets.ParseAndSet(R"(
+ [
+ {
+ "owner": "https://example.test",
+ "members": ["https://member1.test", "https://member3.test"]
+ },
+ {
+ "owner": "https://foo.test",
+ "members": ["https://member2.test"]
+ }
+ ]
+ )");
+ // "https://foo.test" and "https://member2.test" joined FPSs. We don't clear
+ // site data upon joining, so the computed diff should be empty set.
+ EXPECT_THAT(sets.ComputeSetsDiff(old_sets), IsEmpty());
+}
+
+TEST(FirstPartySets, ComputeSetsDiff_SitesLeft) {
+ auto old_sets = base::flat_map<net::SchemefulSite, net::SchemefulSite>{
+ {net::SchemefulSite(GURL("https://example.test")),
+ net::SchemefulSite(GURL("https://example.test"))},
+ {net::SchemefulSite(GURL("https://member1.test")),
+ net::SchemefulSite(GURL("https://example.test"))},
+ {net::SchemefulSite(GURL("https://member3.test")),
+ net::SchemefulSite(GURL("https://example.test"))},
+ {net::SchemefulSite(GURL("https://foo.test")),
+ net::SchemefulSite(GURL("https://foo.test"))},
+ {net::SchemefulSite(GURL("https://member2.test")),
+ net::SchemefulSite(GURL("https://foo.test"))}};
+
+ // Consistency check the reviewer-friendly JSON format matches the input.
+ ASSERT_THAT(FirstPartySets().ParseAndSet(R"(
+ [
+ {
+ "owner": "https://example.test",
+ "members": ["https://member1.test", "https://member3.test"]
+ },
+ {
+ "owner": "https://foo.test",
+ "members": ["https://member2.test"]
+ },
+ ]
+ )"),
+ Pointee(old_sets));
+
+ FirstPartySets sets;
+ sets.ParseAndSet(R"(
+ [
+ {
+ "owner": "https://example.test",
+ "members": ["https://member1.test"]
+ },
+ ]
+ )");
+ // Expected diff: "https://foo.test", "https://member2.test" and
+ // "https://member3.test" left FPSs.
+ EXPECT_THAT(sets.ComputeSetsDiff(old_sets),
+ UnorderedElementsAre(SerializesTo("https://foo.test"),
+ SerializesTo("https://member2.test"),
+ SerializesTo("https://member3.test")));
+}
+
+TEST(FirstPartySets, ComputeSetsDiff_OwnerChanged) {
+ auto old_sets = base::flat_map<net::SchemefulSite, net::SchemefulSite>{
+ {net::SchemefulSite(GURL("https://example.test")),
+ net::SchemefulSite(GURL("https://example.test"))},
+ {net::SchemefulSite(GURL("https://member1.test")),
+ net::SchemefulSite(GURL("https://example.test"))},
+ {net::SchemefulSite(GURL("https://foo.test")),
+ net::SchemefulSite(GURL("https://foo.test"))},
+ {net::SchemefulSite(GURL("https://member2.test")),
+ net::SchemefulSite(GURL("https://foo.test"))},
+ {net::SchemefulSite(GURL("https://member3.test")),
+ net::SchemefulSite(GURL("https://foo.test"))}};
+
+ // Consistency check the reviewer-friendly JSON format matches the input.
+ ASSERT_THAT(FirstPartySets().ParseAndSet(R"(
+ [
+ {
+ "owner": "https://example.test",
+ "members": ["https://member1.test"]
+ },
+ {
+ "owner": "https://foo.test",
+ "members": ["https://member2.test", "https://member3.test"]
+ },
+ ]
+ )"),
+ Pointee(old_sets));
+
+ FirstPartySets sets;
+ sets.ParseAndSet(R"(
+ [
+ {
+ "owner": "https://example.test",
+ "members": ["https://member1.test", "https://member3.test"]
+ },
+ {
+ "owner": "https://foo.test",
+ "members": ["https://member2.test"]
+ }
+ ]
+ )");
+ // Expected diff: "https://member3.test" changed owner.
+ EXPECT_THAT(sets.ComputeSetsDiff(old_sets),
+ UnorderedElementsAre(SerializesTo("https://member3.test")));
+}
+
+TEST(FirstPartySets, ComputeSetsDiff_OwnerLeft) {
+ auto old_sets = base::flat_map<net::SchemefulSite, net::SchemefulSite>{
+ {net::SchemefulSite(GURL("https://example.test")),
+ net::SchemefulSite(GURL("https://example.test"))},
+ {net::SchemefulSite(GURL("https://foo.test")),
+ net::SchemefulSite(GURL("https://example.test"))},
+ {net::SchemefulSite(GURL("https://bar.test")),
+ net::SchemefulSite(GURL("https://example.test"))}};
+
+ // Consistency check the reviewer-friendly JSON format matches the input.
+ ASSERT_THAT(FirstPartySets().ParseAndSet(R"(
+ [
+ {
+ "owner": "https://example.test",
+ "members": ["https://foo.test", "https://bar.test"]
+ }
+ ]
+ )"),
+ Pointee(old_sets));
+
+ FirstPartySets sets;
+ sets.ParseAndSet(R"(
+ [
+ {
+ "owner": "https://foo.test",
+ "members": ["https://bar.test"]
+ }
+ ]
+ )");
+ // Expected diff: "https://example.test" left FPSs, "https://foo.test" and
+ // "https://bar.test" changed owner.
+ // It would be valid to only have example.test in the diff, but our logic
+ // isn't sophisticated enough yet to know that foo.test and bar.test don't
+ // need to be included in the result.
+ EXPECT_THAT(sets.ComputeSetsDiff(old_sets),
+ UnorderedElementsAre(SerializesTo("https://example.test"),
+ SerializesTo("https://foo.test"),
+ SerializesTo("https://bar.test")));
+}
+
+TEST(FirstPartySets, ComputeSetsDiff_OwnerMemberRotate) {
+ auto old_sets = base::flat_map<net::SchemefulSite, net::SchemefulSite>{
+ {net::SchemefulSite(GURL("https://example.test")),
+ net::SchemefulSite(GURL("https://example.test"))},
+ {net::SchemefulSite(GURL("https://foo.test")),
+ net::SchemefulSite(GURL("https://example.test"))}};
+
+ // Consistency check the reviewer-friendly JSON format matches the input.
+ ASSERT_THAT(FirstPartySets().ParseAndSet(R"(
+ [
+ {
+ "owner": "https://example.test",
+ "members": ["https://foo.test"]
+ }
+ ]
+ )"),
+ Pointee(old_sets));
+
+ FirstPartySets sets;
+ sets.ParseAndSet(R"(
+ [
+ {
+ "owner": "https://foo.test",
+ "members": ["https://example.test"]
+ }
+ ]
+ )");
+ // Expected diff: "https://example.test" and "https://foo.test" changed owner.
+ // It would be valid to not include example.test and foo.test in the result,
+ // but our logic isn't sophisticated enough yet to know that.ß
+ EXPECT_THAT(sets.ComputeSetsDiff(old_sets),
+ UnorderedElementsAre(SerializesTo("https://example.test"),
+ SerializesTo("https://foo.test")));
+}
+
+TEST(FirstPartySets, ComputeSetsDiff_EmptySets) {
+ // Empty old_sets.
+ FirstPartySets sets;
+ sets.ParseAndSet(R"(
+ [
+ {
+ "owner": "https://example.test",
+ "members": ["https://member1.test"]
+ },
+ ]
+ )");
+ EXPECT_THAT(sets.ComputeSetsDiff({}), IsEmpty());
+
+ // Empty current sets.
+ auto old_sets = base::flat_map<net::SchemefulSite, net::SchemefulSite>{
+ {net::SchemefulSite(GURL("https://example.test")),
+ net::SchemefulSite(GURL("https://example.test"))},
+ {net::SchemefulSite(GURL("https://member1.test")),
+ net::SchemefulSite(GURL("https://example.test"))}};
+ // Consistency check the reviewer-friendly JSON format matches the input.
+ ASSERT_THAT(FirstPartySets().ParseAndSet(R"(
+ [
+ {
+ "owner": "https://example.test",
+ "members": ["https://member1.test"]
+ }
+ ]
+ )"),
+ Pointee(old_sets));
+ EXPECT_THAT(FirstPartySets().ComputeSetsDiff(old_sets),
+ UnorderedElementsAre(SerializesTo("https://example.test"),
+ SerializesTo("https://member1.test")));
+}
+
+TEST(FirstPartySets, ClearSiteDataOnChangedSetsIfReady_NotReady) {
+ int callback_calls = 0;
+ auto callback = base::BindLambdaForTesting(
+ [&](const std::string& got) { callback_calls++; });
+ // component sets not ready.
+ {
+ FirstPartySets sets;
+ callback_calls = 0;
+ sets.SetPersistedSets("{}");
+ sets.SetManuallySpecifiedSet("");
+ sets.SetOnSiteDataCleared(callback);
+ EXPECT_EQ(callback_calls, 0);
+ }
+ // manual sets not ready.
+ {
+ FirstPartySets sets;
+ callback_calls = 0;
+ sets.ParseAndSet("[]");
+ sets.SetPersistedSets("{}");
+ sets.SetOnSiteDataCleared(callback);
+ EXPECT_EQ(callback_calls, 0);
+ }
+ // persisted sets not ready.
+ {
+ FirstPartySets sets;
+ callback_calls = 0;
+ sets.ParseAndSet("[]");
+ sets.SetManuallySpecifiedSet("");
+ sets.SetOnSiteDataCleared(callback);
+ EXPECT_EQ(callback_calls, 0);
+ }
+ // callback not set.
+ {
+ FirstPartySets sets;
+ callback_calls = 0;
+ sets.ParseAndSet("[]");
+ sets.SetManuallySpecifiedSet("");
+ sets.SetPersistedSets("{}");
+ EXPECT_EQ(callback_calls, 0);
+ }
+}
+
+// The callback only runs when `old_sets` is generated and `sets` has merged the
+// inputs from Component Updater and command line flag.
+TEST(FirstPartySets, ClearSiteDataOnChangedSetsIfReady_Ready) {
+ FirstPartySets sets;
+ int callback_calls = 0;
+ sets.ParseAndSet(R"([
+ {
+ "owner": "https://example.test",
+ "members": ["https://member1.test"]
+ }
+ ])");
+ sets.SetManuallySpecifiedSet("https://example2.test,https://member2.test");
+ sets.SetPersistedSets(
+ R"({"https://example.test":"https://example.test",
+ "https://member1.test":"https://example.test"})");
+ sets.SetOnSiteDataCleared(base::BindLambdaForTesting([&](const std::string&
+ got) {
+ EXPECT_EQ(
+ got,
+ R"({"https://member1.test":"https://example.test","https://member2.test":"https://example2.test"})");
+ callback_calls++;
+ }));
+ EXPECT_EQ(callback_calls, 1);
+}
+
class FirstPartySetsTest : public ::testing::Test {
public:
FirstPartySetsTest() {
diff --git a/services/network/network_service.cc b/services/network/network_service.cc
index 5d598ff6c626510bf1da00d35bc9ba4179bac93e..c850d6950aa7777cdc5c2056d4b80c9dd44d3af9 100644
--- a/services/network/network_service.cc
+++ b/services/network/network_service.cc
@@ -343,8 +343,7 @@ void NetworkService::Initialize(mojom::NetworkServiceParamsPtr params,
}
first_party_sets_ = std::make_unique<FirstPartySets>();
- if (net::cookie_util::IsFirstPartySetsEnabled() &&
- command_line->HasSwitch(switches::kUseFirstPartySet)) {
+ if (net::cookie_util::IsFirstPartySetsEnabled()) {
first_party_sets_->SetManuallySpecifiedSet(
command_line->GetSwitchValueASCII(switches::kUseFirstPartySet));
}
@@ -785,6 +784,14 @@ void NetworkService::SetFirstPartySets(const std::string& raw_sets) {
first_party_sets_->ParseAndSet(raw_sets);
}
+void NetworkService::SetPersistedFirstPartySetsAndGetCurrentSets(
+ const std::string& persisted_sets,
+ mojom::NetworkService::SetPersistedFirstPartySetsAndGetCurrentSetsCallback
+ callback) {
+ first_party_sets_->SetPersistedSets(persisted_sets);
+ first_party_sets_->SetOnSiteDataCleared(std::move(callback));
+}
+
void NetworkService::SetExplicitlyAllowedPorts(
const std::vector<uint16_t>& ports) {
net::SetExplicitlyAllowedPorts(ports);
diff --git a/services/network/network_service.h b/services/network/network_service.h
index 1da4505fc9fe478e00353cd55e615878ea875aa0..963e22f6d5e957684dc56dd6e3ae31fa430a355e 100644
--- a/services/network/network_service.h
+++ b/services/network/network_service.h
@@ -204,6 +204,10 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService
void BindTestInterface(
mojo::PendingReceiver<mojom::NetworkServiceTest> receiver) override;
void SetFirstPartySets(const std::string& raw_sets) override;
+ void SetPersistedFirstPartySetsAndGetCurrentSets(
+ const std::string& persisted_sets,
+ mojom::NetworkService::SetPersistedFirstPartySetsAndGetCurrentSetsCallback
+ callback) override;
void SetExplicitlyAllowedPorts(const std::vector<uint16_t>& ports) override;
// Returns an HttpAuthHandlerFactory for the given NetworkContext.
diff --git a/services/network/network_service_unittest.cc b/services/network/network_service_unittest.cc
index bd8ed7abe5870d23e3b0430f29f0448cf425fabc..dffa318ab85d6851c54d0f3c38ab6bb72f274f40 100644
--- a/services/network/network_service_unittest.cc
+++ b/services/network/network_service_unittest.cc
@@ -925,6 +925,7 @@ class NetworkServiceTestWithService : public testing::Test {
void SetUp() override {
test_server_.AddDefaultHandlers(base::FilePath(kServicesTestData));
ASSERT_TRUE(test_server_.Start());
+ scoped_features_.InitAndEnableFeature(net::features::kFirstPartySets);
service_ = NetworkService::CreateForTesting();
service_->Bind(network_service_.BindNewPipeAndPassReceiver());
}
@@ -989,7 +990,7 @@ class NetworkServiceTestWithService : public testing::Test {
mojo::Remote<mojom::NetworkContext> network_context_;
mojo::Remote<mojom::URLLoader> loader_;
- DISALLOW_COPY_AND_ASSIGN(NetworkServiceTestWithService);
+ base::test::ScopedFeatureList scoped_features_;
};
// Verifies that loading a URL through the network service's mojo interface
@@ -1169,6 +1170,18 @@ TEST_F(NetworkServiceTestWithService, GetNetworkList) {
run_loop.Run();
}
+TEST_F(NetworkServiceTestWithService,
+ SetPersistedFirstPartySetsAndGetCurrentSets) {
+ base::RunLoop run_loop;
+ network_service_->SetPersistedFirstPartySetsAndGetCurrentSets(
+ "", base::BindLambdaForTesting([&](const std::string& got) {
+ EXPECT_EQ(got, "{}");
+ run_loop.Quit();
+ }));
+ network_service_->SetFirstPartySets("");
+ run_loop.Run();
+}
+
class TestNetworkChangeManagerClient
: public mojom::NetworkChangeManagerClient {
public:
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom
index fe5450b20b3c4a8490e853dd236bf6baefa90b81..59fbbde6ffc30d51304a72f402eee7c664ea111b 100644
--- a/services/network/public/mojom/network_service.mojom
+++ b/services/network/public/mojom/network_service.mojom
@@ -373,6 +373,14 @@ interface NetworkService {
// cleared (except for the manually-specified set, if one exists).
SetFirstPartySets(string raw_sets);
+ // Sets the First-Party Sets data that was persisted to compare it with the
+ // current First-Party Sets data set by `SetFirstPartySets()`, which is
+ // considered more up-to-date, and returns a serialized version of the current
+ // one. Both input and output are in format of the JSON-encoded string
+ // representation of a map of site -> site.
+ SetPersistedFirstPartySetsAndGetCurrentSets(string persisted_sets)
+ => (string up_to_date_sets);
+
// Sets the list of ports which will be permitted even if they normally would
// be restricted.
SetExplicitlyAllowedPorts(array<uint16> ports);