1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
content / browser / browsing_data / clear_site_data_utils.cc [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/public/browser/clear_site_data_utils.h"
#include "base/functional/bind.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "content/browser/browser_context_impl.h"
#include "content/browser/browsing_data/browsing_data_remover_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/browsing_data_filter_builder.h"
#include "content/public/browser/browsing_data_remover.h"
#include "content/public/browser/storage_partition_config.h"
#include "content/public/browser/web_contents.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
namespace content {
namespace {
// Finds the BrowserContext associated with the request and requests
// the actual clearing of data for `origin`. The data types to be deleted
// are determined by `clear_site_data_types` and `storage_buckets_to_remove`.
// `web_contents_getter` identifies the WebContents from which the request
// originated. Must be run on the UI thread. The `callback` will be executed
// on the IO thread.
class SiteDataClearer : public BrowsingDataRemover::Observer {
public:
SiteDataClearer(
BrowserContext* browser_context,
std::optional<StoragePartitionConfig> storage_partition_config,
const url::Origin& origin,
const ClearSiteDataTypeSet clear_site_data_types,
const std::set<std::string>& storage_buckets_to_remove,
bool avoid_closing_connections,
std::optional<net::CookiePartitionKey> cookie_partition_key,
std::optional<blink::StorageKey> storage_key,
bool partitioned_state_allowed_only,
base::OnceClosure callback)
: storage_partition_config_(std::move(storage_partition_config)),
origin_(origin),
clear_site_data_types_(clear_site_data_types),
storage_buckets_to_remove_(storage_buckets_to_remove),
avoid_closing_connections_(avoid_closing_connections),
cookie_partition_key_(std::move(cookie_partition_key)),
storage_key_(std::move(storage_key)),
partitioned_state_allowed_only_(partitioned_state_allowed_only),
callback_(std::move(callback)),
pending_task_count_(0),
remover_(nullptr) {
remover_ =
BrowserContextImpl::From(browser_context)->GetBrowsingDataRemover();
DCHECK(remover_);
scoped_observation_.Observe(remover_.get());
}
~SiteDataClearer() override {
// This SiteDataClearer class is self-owned, and the only way for it to be
// destroyed should be the "delete this" part in
// OnBrowsingDataRemoverDone() function, and it invokes the |callback_|. So
// when this destructor is called, the |callback_| should be null.
DCHECK(!callback_);
}
void RunAndDestroySelfWhenDone() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Cookies and channel IDs are scoped to
// a) eTLD+1 of |origin|'s host if |origin|'s host is a registrable domain
// or a subdomain thereof
// b) |origin|'s host exactly if it is an IP address or an internal hostname
// (e.g. "localhost" or "fileserver").
if (clear_site_data_types_.Has(ClearSiteDataType::kCookies)) {
std::string domain = GetDomainAndRegistry(
origin_,
net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
if (domain.empty()) {
domain = origin_.host(); // IP address or internal hostname.
}
std::unique_ptr<BrowsingDataFilterBuilder> cookie_filter_builder(
BrowsingDataFilterBuilder::Create(
BrowsingDataFilterBuilder::Mode::kDelete));
cookie_filter_builder->AddRegisterableDomain(domain);
cookie_filter_builder->SetCookiePartitionKeyCollection(
net::CookiePartitionKeyCollection::FromOptional(
cookie_partition_key_));
cookie_filter_builder->SetPartitionedCookiesOnly(
partitioned_state_allowed_only_);
if (storage_partition_config_.has_value()) {
cookie_filter_builder->SetStoragePartitionConfig(
storage_partition_config_.value());
}
pending_task_count_++;
uint64_t remove_mask = BrowsingDataRemover::DATA_TYPE_COOKIES;
if (avoid_closing_connections_) {
remove_mask |= BrowsingDataRemover::DATA_TYPE_AVOID_CLOSING_CONNECTIONS;
}
remover_->RemoveWithFilterAndReply(
base::Time(), base::Time::Max(), remove_mask,
BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB |
BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB,
std::move(cookie_filter_builder), this);
}
// Storage buckets
if (!storage_buckets_to_remove_.empty()) {
pending_task_count_++;
// For storage buckets, no mask is being passed per se. Therefore, when
// the storage buckets are successfully removed, the `failed_data_types`
// arg should be set to 0 to align with existing behaviour in this class.
remover_->RemoveStorageBucketsAndReply(
storage_partition_config_,
storage_key_.value_or(blink::StorageKey::CreateFirstParty(origin_)),
storage_buckets_to_remove_,
base::BindOnce(&SiteDataClearer::OnBrowsingDataRemoverDone,
weak_factory_.GetWeakPtr(), 0));
}
// Delete origin-scoped data.
uint64_t remove_mask = 0;
if (clear_site_data_types_.Has(ClearSiteDataType::kStorage)) {
remove_mask |= BrowsingDataRemover::DATA_TYPE_DOM_STORAGE;
remove_mask |= BrowsingDataRemover::DATA_TYPE_PRIVACY_SANDBOX;
// Internal data should not be removed by site-initiated deletions.
remove_mask &= ~BrowsingDataRemover::DATA_TYPE_PRIVACY_SANDBOX_INTERNAL;
}
if (clear_site_data_types_.Has(ClearSiteDataType::kCache)) {
remove_mask |= BrowsingDataRemover::DATA_TYPE_CACHE;
}
if (remove_mask) {
std::unique_ptr<BrowsingDataFilterBuilder> origin_filter_builder(
BrowsingDataFilterBuilder::Create(
BrowsingDataFilterBuilder::Mode::kDelete));
origin_filter_builder->AddOrigin(origin_);
origin_filter_builder->SetStorageKey(storage_key_);
if (storage_partition_config_.has_value()) {
origin_filter_builder->SetStoragePartitionConfig(
storage_partition_config_.value());
}
pending_task_count_++;
remover_->RemoveWithFilterAndReply(
base::Time(), base::Time::Max(), remove_mask,
BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB |
BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB,
std::move(origin_filter_builder), this);
}
// We clear client hints for both cookie and cache clears.
if (clear_site_data_types_.HasAny({ClearSiteDataType::kCookies,
ClearSiteDataType::kCache,
ClearSiteDataType::kClientHints})) {
pending_task_count_++;
// For client hints, no mask is being passed per se. Therefore, when
// the client hints are successfully removed, the `failed_data_types`
// arg should be set to 0 to align with existing behaviour in this class.
remover_->ClearClientHintCacheAndReply(
origin_, base::BindOnce(&SiteDataClearer::OnBrowsingDataRemoverDone,
weak_factory_.GetWeakPtr(), 0));
}
DCHECK_GT(pending_task_count_, 0);
}
private:
// BrowsingDataRemover::Observer:
void OnBrowsingDataRemoverDone(uint64_t failed_data_types) override {
DCHECK(pending_task_count_);
if (--pending_task_count_) {
return;
}
std::move(callback_).Run();
delete this;
}
const std::optional<StoragePartitionConfig> storage_partition_config_;
const url::Origin origin_;
const ClearSiteDataTypeSet clear_site_data_types_;
const std::set<std::string> storage_buckets_to_remove_;
const bool avoid_closing_connections_;
const std::optional<net::CookiePartitionKey> cookie_partition_key_;
const std::optional<blink::StorageKey> storage_key_;
const bool partitioned_state_allowed_only_;
base::OnceClosure callback_;
int pending_task_count_ = 0;
raw_ptr<BrowsingDataRemoverImpl> remover_ = nullptr;
base::ScopedObservation<BrowsingDataRemover, BrowsingDataRemover::Observer>
scoped_observation_{this};
base::WeakPtrFactory<SiteDataClearer> weak_factory_{this};
};
} // namespace
void ClearSiteData(
base::WeakPtr<BrowserContext> browser_context,
std::optional<StoragePartitionConfig> storage_partition_config,
const url::Origin& origin,
const ClearSiteDataTypeSet clear_site_data_types,
const std::set<std::string>& storage_buckets_to_remove,
bool avoid_closing_connections,
std::optional<net::CookiePartitionKey> cookie_partition_key,
std::optional<blink::StorageKey> storage_key,
bool partitioned_state_allowed_only,
base::OnceClosure callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// It's not possible to clear all storage and also only specific buckets.
DCHECK(!clear_site_data_types.Has(ClearSiteDataType::kStorage) ||
storage_buckets_to_remove.empty());
if (!browser_context) {
std::move(callback).Run();
return;
}
(new SiteDataClearer(browser_context.get(), storage_partition_config, origin,
clear_site_data_types, storage_buckets_to_remove,
avoid_closing_connections, cookie_partition_key,
storage_key, partitioned_state_allowed_only,
std::move(callback)))
->RunAndDestroySelfWhenDone();
}
} // namespace content