Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 1 | // Copyright 2022 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Shuran Huang | 1039815 | 2022-03-28 21:52:18 | [diff] [blame] | 5 | #include "content/browser/first_party_sets/first_party_sets_loader.h" |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 6 | |
Chris Fredrickson | 4ef2d24 | 2022-09-06 22:47:18 | [diff] [blame] | 7 | #include <iterator> |
Lei Zhang | bd72251 | 2022-03-14 23:21:58 | [diff] [blame] | 8 | #include <set> |
Chris Fredrickson | 878d06b | 2022-09-08 15:20:37 | [diff] [blame] | 9 | #include <sstream> |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 10 | #include <utility> |
| 11 | #include <vector> |
| 12 | |
| 13 | #include "base/check.h" |
| 14 | #include "base/containers/contains.h" |
| 15 | #include "base/containers/flat_map.h" |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 16 | #include "base/files/file_util.h" |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 17 | #include "base/metrics/histogram_functions.h" |
Chris Fredrickson | 4ef2d24 | 2022-09-06 22:47:18 | [diff] [blame] | 18 | #include "base/ranges/algorithm.h" |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 19 | #include "base/sequence_checker.h" |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 20 | #include "base/task/thread_pool.h" |
Shuran Huang | 1039815 | 2022-03-28 21:52:18 | [diff] [blame] | 21 | #include "content/browser/first_party_sets/first_party_set_parser.h" |
Chris Fredrickson | 8db7bf54 | 2022-09-06 17:47:20 | [diff] [blame] | 22 | #include "content/browser/first_party_sets/local_set_declaration.h" |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 23 | #include "net/base/schemeful_site.h" |
Chris Fredrickson | 3327312 | 2022-08-31 22:41:00 | [diff] [blame] | 24 | #include "net/first_party_sets/first_party_set_entry.h" |
Chris Fredrickson | 878d06b | 2022-09-08 15:20:37 | [diff] [blame] | 25 | #include "net/first_party_sets/public_sets.h" |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 26 | #include "third_party/abseil-cpp/absl/types/optional.h" |
| 27 | |
Shuran Huang | 1039815 | 2022-03-28 21:52:18 | [diff] [blame] | 28 | namespace content { |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 29 | |
| 30 | namespace { |
| 31 | |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 32 | std::string ReadSetsFile(base::File sets_file) { |
| 33 | std::string raw_sets; |
| 34 | base::ScopedFILE file(FileToFILE(std::move(sets_file), "r")); |
| 35 | return base::ReadStreamToString(file.get(), &raw_sets) ? raw_sets : ""; |
| 36 | } |
| 37 | |
| 38 | } // namespace |
| 39 | |
| 40 | FirstPartySetsLoader::FirstPartySetsLoader( |
Kirubel Aklilu | 6d1ef6b9 | 2022-07-08 13:40:19 | [diff] [blame] | 41 | LoadCompleteOnceCallback on_load_complete) |
| 42 | : on_load_complete_(std::move(on_load_complete)) {} |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 43 | |
| 44 | FirstPartySetsLoader::~FirstPartySetsLoader() { |
| 45 | DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 46 | } |
| 47 | |
| 48 | void FirstPartySetsLoader::SetManuallySpecifiedSet( |
Chris Fredrickson | 8db7bf54 | 2022-09-06 17:47:20 | [diff] [blame] | 49 | const LocalSetDeclaration& local_set) { |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 50 | DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
Chris Fredrickson | 8db7bf54 | 2022-09-06 17:47:20 | [diff] [blame] | 51 | manually_specified_set_ = local_set; |
cfredric | cc53588b | 2022-03-04 19:09:00 | [diff] [blame] | 52 | UmaHistogramTimes( |
Chris Fredrickson | 92e21d0 | 2022-04-22 21:16:19 | [diff] [blame] | 53 | "Cookie.FirstPartySets.InitializationDuration.ReadCommandLineSet2", |
cfredric | cc53588b | 2022-03-04 19:09:00 | [diff] [blame] | 54 | construction_timer_.Elapsed()); |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 55 | |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 56 | MaybeFinishLoading(); |
| 57 | } |
| 58 | |
| 59 | void FirstPartySetsLoader::SetComponentSets(base::File sets_file) { |
| 60 | DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 61 | if (component_sets_parse_progress_ != Progress::kNotStarted) { |
| 62 | DisposeFile(std::move(sets_file)); |
| 63 | return; |
| 64 | } |
| 65 | |
| 66 | component_sets_parse_progress_ = Progress::kStarted; |
| 67 | |
| 68 | if (!sets_file.IsValid()) { |
| 69 | OnReadSetsFile(""); |
| 70 | return; |
| 71 | } |
| 72 | |
| 73 | // We use USER_BLOCKING here since First-Party Set initialization blocks |
| 74 | // network navigations at startup. |
| 75 | base::ThreadPool::PostTaskAndReplyWithResult( |
| 76 | FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING}, |
| 77 | base::BindOnce(&ReadSetsFile, std::move(sets_file)), |
| 78 | base::BindOnce(&FirstPartySetsLoader::OnReadSetsFile, |
| 79 | weak_factory_.GetWeakPtr())); |
| 80 | } |
| 81 | |
| 82 | void FirstPartySetsLoader::OnReadSetsFile(const std::string& raw_sets) { |
| 83 | DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 84 | DCHECK_EQ(component_sets_parse_progress_, Progress::kStarted); |
| 85 | |
cfredric | 6b617446 | 2022-02-16 18:12:48 | [diff] [blame] | 86 | std::istringstream stream(raw_sets); |
Chris Fredrickson | d149b84 | 2022-08-17 21:41:00 | [diff] [blame] | 87 | FirstPartySetParser::SetsAndAliases public_sets = |
Chris Fredrickson | f9de345 | 2022-09-12 21:46:56 | [diff] [blame^] | 88 | FirstPartySetParser::ParseSetsFromStream(stream, /*emit_errors=*/false); |
Chris Fredrickson | dd2f3096 | 2022-08-18 13:48:27 | [diff] [blame] | 89 | sets_ = std::move(public_sets.first); |
| 90 | aliases_ = std::move(public_sets.second); |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 91 | |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 92 | component_sets_parse_progress_ = Progress::kFinished; |
cfredric | cc53588b | 2022-03-04 19:09:00 | [diff] [blame] | 93 | UmaHistogramTimes( |
Chris Fredrickson | 92e21d0 | 2022-04-22 21:16:19 | [diff] [blame] | 94 | "Cookie.FirstPartySets.InitializationDuration.ReadComponentSets2", |
cfredric | cc53588b | 2022-03-04 19:09:00 | [diff] [blame] | 95 | construction_timer_.Elapsed()); |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 96 | MaybeFinishLoading(); |
| 97 | } |
| 98 | |
| 99 | void FirstPartySetsLoader::DisposeFile(base::File sets_file) { |
| 100 | if (sets_file.IsValid()) { |
| 101 | base::ThreadPool::PostTask( |
| 102 | FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, |
| 103 | base::BindOnce( |
| 104 | [](base::File sets_file) { |
| 105 | // Run `sets_file`'s dtor in the threadpool. |
| 106 | }, |
| 107 | std::move(sets_file))); |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | void FirstPartySetsLoader::ApplyManuallySpecifiedSet() { |
| 112 | DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
Kirubel Aklilu | 72845462 | 2022-04-15 19:04:18 | [diff] [blame] | 113 | DCHECK(HasAllInputs()); |
Chris Fredrickson | 8db7bf54 | 2022-09-06 17:47:20 | [diff] [blame] | 114 | if (manually_specified_set_->empty()) |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 115 | return; |
Chris Fredrickson | fcbdaac | 2022-08-10 16:38:42 | [diff] [blame] | 116 | const net::SchemefulSite& manual_owner = |
Chris Fredrickson | 8db7bf54 | 2022-09-06 17:47:20 | [diff] [blame] | 117 | manually_specified_set_->GetPrimary(); |
Chris Fredrickson | 4ef2d24 | 2022-09-06 22:47:18 | [diff] [blame] | 118 | FlattenedSets manual_sites = manually_specified_set_->GetSet(); |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 119 | |
Kirubel Aklilu | 6d1ef6b9 | 2022-07-08 13:40:19 | [diff] [blame] | 120 | // Erase the intersection between |sets_| and |manually_specified_set_| and |
Kirubel Aklilu | 72845462 | 2022-04-15 19:04:18 | [diff] [blame] | 121 | // any members whose owner was in the intersection. |
Chris Fredrickson | fcbdaac | 2022-08-10 16:38:42 | [diff] [blame] | 122 | base::EraseIf( |
| 123 | sets_, [&](const std::pair<net::SchemefulSite, net::FirstPartySetEntry>& |
| 124 | public_site_and_entry) { |
| 125 | const net::SchemefulSite& public_site = public_site_and_entry.first; |
| 126 | const net::SchemefulSite& public_owner = |
| 127 | public_site_and_entry.second.primary(); |
| 128 | return public_site == manual_owner || public_owner == manual_owner || |
| 129 | base::ranges::any_of( |
| 130 | manual_sites, [&](const std::pair<net::SchemefulSite, |
| 131 | net::FirstPartySetEntry>& |
| 132 | manual_site_and_entry) { |
| 133 | const net::SchemefulSite& manual_site = |
| 134 | manual_site_and_entry.first; |
| 135 | return manual_site == public_site || |
| 136 | manual_site == public_owner; |
| 137 | }); |
| 138 | }); |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 139 | |
Kirubel Aklilu | 6d1ef6b9 | 2022-07-08 13:40:19 | [diff] [blame] | 140 | // Next, we must add the manually specified set to |sets_|. |
Chris Fredrickson | 4ef2d24 | 2022-09-06 22:47:18 | [diff] [blame] | 141 | base::ranges::move(manual_sites, std::inserter(sets_, sets_.end())); |
Kirubel Aklilu | 289d61f | 2022-05-02 18:36:23 | [diff] [blame] | 142 | // Now remove singleton sets, which are sets that just contain sites that |
| 143 | // *are* owners, but no longer have any (other) members. |
| 144 | std::set<net::SchemefulSite> owners_with_members; |
| 145 | for (const auto& it : sets_) { |
Chris Fredrickson | c2efa96f | 2022-08-04 20:40:44 | [diff] [blame] | 146 | if (it.first != it.second.primary()) |
| 147 | owners_with_members.insert(it.second.primary()); |
Kirubel Aklilu | 289d61f | 2022-05-02 18:36:23 | [diff] [blame] | 148 | } |
| 149 | base::EraseIf(sets_, [&owners_with_members](const auto& p) { |
Chris Fredrickson | c2efa96f | 2022-08-04 20:40:44 | [diff] [blame] | 150 | return p.first == p.second.primary() && |
| 151 | !base::Contains(owners_with_members, p.first); |
Kirubel Aklilu | 289d61f | 2022-05-02 18:36:23 | [diff] [blame] | 152 | }); |
Chris Fredrickson | f9de345 | 2022-09-12 21:46:56 | [diff] [blame^] | 153 | |
| 154 | // TODO(https://crbug.com/1349781): merge aliases. |
Kirubel Aklilu | 289d61f | 2022-05-02 18:36:23 | [diff] [blame] | 155 | } |
| 156 | |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 157 | void FirstPartySetsLoader::MaybeFinishLoading() { |
| 158 | DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
Kirubel Aklilu | 72845462 | 2022-04-15 19:04:18 | [diff] [blame] | 159 | if (!HasAllInputs()) |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 160 | return; |
cfredric | 0c632ce0 | 2022-03-03 19:14:52 | [diff] [blame] | 161 | ApplyManuallySpecifiedSet(); |
Chris Fredrickson | 878d06b | 2022-09-08 15:20:37 | [diff] [blame] | 162 | std::move(on_load_complete_) |
| 163 | .Run(net::PublicSets(std::move(sets_), std::move(aliases_))); |
Shuran Huang | 71a22ff | 2022-02-11 14:54:10 | [diff] [blame] | 164 | } |
| 165 | |
Kirubel Aklilu | 72845462 | 2022-04-15 19:04:18 | [diff] [blame] | 166 | bool FirstPartySetsLoader::HasAllInputs() const { |
| 167 | DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 168 | return component_sets_parse_progress_ == Progress::kFinished && |
| 169 | manually_specified_set_.has_value(); |
| 170 | } |
| 171 | |
Kirubel Aklilu | 583f57ab | 2022-04-12 16:10:50 | [diff] [blame] | 172 | } // namespace content |