1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/reporting/reporting_service.h"
6
7 #include <optional>
8 #include <utility>
9
10 #include "base/feature_list.h"
11 #include "base/functional/bind.h"
12 #include "base/json/json_reader.h"
13 #include "base/logging.h"
14 #include "base/memory/raw_ptr.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/time/tick_clock.h"
17 #include "base/time/time.h"
18 #include "base/values.h"
19 #include "net/base/features.h"
20 #include "net/base/isolation_info.h"
21 #include "net/http/structured_headers.h"
22 #include "net/reporting/reporting_browsing_data_remover.h"
23 #include "net/reporting/reporting_cache.h"
24 #include "net/reporting/reporting_context.h"
25 #include "net/reporting/reporting_delegate.h"
26 #include "net/reporting/reporting_delivery_agent.h"
27 #include "net/reporting/reporting_header_parser.h"
28 #include "net/reporting/reporting_uploader.h"
29 #include "url/gurl.h"
30 #include "url/origin.h"
31
32 namespace net {
33
34 namespace {
35
36 constexpr int kMaxJsonSize = 16 * 1024;
37 constexpr int kMaxJsonDepth = 5;
38
39 // If constructed with a PersistentReportingStore, the first call to any of
40 // QueueReport(), ProcessHeader(), RemoveBrowsingData(), or
41 // RemoveAllBrowsingData() on a valid input will trigger a load from the store.
42 // Tasks are queued pending completion of loading from the store.
43 class ReportingServiceImpl : public ReportingService {
44 public:
ReportingServiceImpl(std::unique_ptr<ReportingContext> context)45 explicit ReportingServiceImpl(std::unique_ptr<ReportingContext> context)
46 : context_(std::move(context)) {
47 if (!context_->IsClientDataPersisted())
48 initialized_ = true;
49 }
50
51 ReportingServiceImpl(const ReportingServiceImpl&) = delete;
52 ReportingServiceImpl& operator=(const ReportingServiceImpl&) = delete;
53
54 // ReportingService implementation:
55
~ReportingServiceImpl()56 ~ReportingServiceImpl() override {
57 if (initialized_)
58 context_->cache()->Flush();
59 }
60
SetDocumentReportingEndpoints(const base::UnguessableToken & reporting_source,const url::Origin & origin,const IsolationInfo & isolation_info,const base::flat_map<std::string,std::string> & endpoints)61 void SetDocumentReportingEndpoints(
62 const base::UnguessableToken& reporting_source,
63 const url::Origin& origin,
64 const IsolationInfo& isolation_info,
65 const base::flat_map<std::string, std::string>& endpoints) override {
66 DCHECK(!reporting_source.is_empty());
67 DoOrBacklogTask(
68 base::BindOnce(&ReportingServiceImpl::DoSetDocumentReportingEndpoints,
69 base::Unretained(this), reporting_source, isolation_info,
70 FixupNetworkAnonymizationKey(
71 isolation_info.network_anonymization_key()),
72 origin, std::move(endpoints)));
73 }
74
SetEnterpriseReportingEndpoints(const base::flat_map<std::string,GURL> & endpoints)75 void SetEnterpriseReportingEndpoints(
76 const base::flat_map<std::string, GURL>& endpoints) override {
77 if (!base::FeatureList::IsEnabled(
78 net::features::kReportingApiEnableEnterpriseCookieIssues)) {
79 return;
80 }
81 context_->cache()->SetEnterpriseReportingEndpoints(endpoints);
82 }
83
SendReportsAndRemoveSource(const base::UnguessableToken & reporting_source)84 void SendReportsAndRemoveSource(
85 const base::UnguessableToken& reporting_source) override {
86 DCHECK(!reporting_source.is_empty());
87 context_->delivery_agent()->SendReportsForSource(reporting_source);
88 context_->cache()->SetExpiredSource(reporting_source);
89 }
90
QueueReport(const GURL & url,const std::optional<base::UnguessableToken> & reporting_source,const NetworkAnonymizationKey & network_anonymization_key,const std::string & user_agent,const std::string & group,const std::string & type,base::Value::Dict body,int depth,ReportingTargetType target_type)91 void QueueReport(
92 const GURL& url,
93 const std::optional<base::UnguessableToken>& reporting_source,
94 const NetworkAnonymizationKey& network_anonymization_key,
95 const std::string& user_agent,
96 const std::string& group,
97 const std::string& type,
98 base::Value::Dict body,
99 int depth,
100 ReportingTargetType target_type) override {
101 DCHECK(context_);
102 DCHECK(context_->delegate());
103 // If |reporting_source| is provided, it must not be empty.
104 DCHECK(!(reporting_source.has_value() && reporting_source->is_empty()));
105
106 if (!context_->delegate()->CanQueueReport(url::Origin::Create(url)))
107 return;
108
109 // Strip username, password, and ref fragment from the URL.
110 GURL sanitized_url = url.GetAsReferrer();
111 if (!sanitized_url.is_valid())
112 return;
113
114 base::TimeTicks queued_ticks = context_->tick_clock().NowTicks();
115
116 // base::Unretained is safe because the callback is stored in
117 // |task_backlog_| which will not outlive |this|.
118 DoOrBacklogTask(
119 base::BindOnce(&ReportingServiceImpl::DoQueueReport,
120 base::Unretained(this), reporting_source,
121 FixupNetworkAnonymizationKey(network_anonymization_key),
122 std::move(sanitized_url), user_agent, group, type,
123 std::move(body), depth, queued_ticks, target_type));
124 }
125
ProcessReportToHeader(const url::Origin & origin,const NetworkAnonymizationKey & network_anonymization_key,const std::string & header_string)126 void ProcessReportToHeader(
127 const url::Origin& origin,
128 const NetworkAnonymizationKey& network_anonymization_key,
129 const std::string& header_string) override {
130 if (header_string.size() > kMaxJsonSize)
131 return;
132
133 std::optional<base::Value> header_value = base::JSONReader::Read(
134 "[" + header_string + "]", base::JSON_PARSE_RFC, kMaxJsonDepth);
135 if (!header_value)
136 return;
137
138 DVLOG(1) << "Received Reporting policy for " << origin;
139 DoOrBacklogTask(base::BindOnce(
140 &ReportingServiceImpl::DoProcessReportToHeader, base::Unretained(this),
141 FixupNetworkAnonymizationKey(network_anonymization_key), origin,
142 std::move(header_value).value()));
143 }
144
RemoveBrowsingData(uint64_t data_type_mask,const base::RepeatingCallback<bool (const url::Origin &)> & origin_filter)145 void RemoveBrowsingData(
146 uint64_t data_type_mask,
147 const base::RepeatingCallback<bool(const url::Origin&)>& origin_filter)
148 override {
149 DoOrBacklogTask(base::BindOnce(&ReportingServiceImpl::DoRemoveBrowsingData,
150 base::Unretained(this), data_type_mask,
151 origin_filter));
152 }
153
RemoveAllBrowsingData(uint64_t data_type_mask)154 void RemoveAllBrowsingData(uint64_t data_type_mask) override {
155 DoOrBacklogTask(
156 base::BindOnce(&ReportingServiceImpl::DoRemoveAllBrowsingData,
157 base::Unretained(this), data_type_mask));
158 }
159
OnShutdown()160 void OnShutdown() override {
161 shut_down_ = true;
162 context_->OnShutdown();
163 }
164
GetPolicy() const165 const ReportingPolicy& GetPolicy() const override {
166 return context_->policy();
167 }
168
StatusAsValue() const169 base::Value StatusAsValue() const override {
170 base::Value::Dict dict;
171 dict.Set("reportingEnabled", true);
172 dict.Set("clients", context_->cache()->GetClientsAsValue());
173 dict.Set("reports", context_->cache()->GetReportsAsValue());
174 return base::Value(std::move(dict));
175 }
176
GetReports() const177 std::vector<raw_ptr<const ReportingReport, VectorExperimental>> GetReports()
178 const override {
179 std::vector<raw_ptr<const net::ReportingReport, VectorExperimental>>
180 reports;
181 context_->cache()->GetReports(&reports);
182 return reports;
183 }
184
185 base::flat_map<url::Origin, std::vector<ReportingEndpoint>>
GetV1ReportingEndpointsByOrigin() const186 GetV1ReportingEndpointsByOrigin() const override {
187 return context_->cache()->GetV1ReportingEndpointsByOrigin();
188 }
189
AddReportingCacheObserver(ReportingCacheObserver * observer)190 void AddReportingCacheObserver(ReportingCacheObserver* observer) override {
191 context_->AddCacheObserver(observer);
192 }
193
RemoveReportingCacheObserver(ReportingCacheObserver * observer)194 void RemoveReportingCacheObserver(ReportingCacheObserver* observer) override {
195 context_->RemoveCacheObserver(observer);
196 }
197
GetContextForTesting() const198 ReportingContext* GetContextForTesting() const override {
199 return context_.get();
200 }
201
202 private:
DoOrBacklogTask(base::OnceClosure task)203 void DoOrBacklogTask(base::OnceClosure task) {
204 if (shut_down_)
205 return;
206
207 FetchAllClientsFromStoreIfNecessary();
208
209 if (!initialized_) {
210 task_backlog_.push_back(std::move(task));
211 return;
212 }
213
214 std::move(task).Run();
215 }
216
DoQueueReport(const std::optional<base::UnguessableToken> & reporting_source,const NetworkAnonymizationKey & network_anonymization_key,GURL sanitized_url,const std::string & user_agent,const std::string & group,const std::string & type,base::Value::Dict body,int depth,base::TimeTicks queued_ticks,ReportingTargetType target_type)217 void DoQueueReport(
218 const std::optional<base::UnguessableToken>& reporting_source,
219 const NetworkAnonymizationKey& network_anonymization_key,
220 GURL sanitized_url,
221 const std::string& user_agent,
222 const std::string& group,
223 const std::string& type,
224 base::Value::Dict body,
225 int depth,
226 base::TimeTicks queued_ticks,
227 ReportingTargetType target_type) {
228 DCHECK(initialized_);
229 context_->cache()->AddReport(reporting_source, network_anonymization_key,
230 sanitized_url, user_agent, group, type,
231 std::move(body), depth, queued_ticks,
232 0 /* attempts */, target_type);
233 }
234
DoProcessReportToHeader(const NetworkAnonymizationKey & network_anonymization_key,const url::Origin & origin,const base::Value & header_value)235 void DoProcessReportToHeader(
236 const NetworkAnonymizationKey& network_anonymization_key,
237 const url::Origin& origin,
238 const base::Value& header_value) {
239 DCHECK(initialized_);
240 DCHECK(header_value.is_list());
241 ReportingHeaderParser::ParseReportToHeader(context_.get(),
242 network_anonymization_key,
243 origin, header_value.GetList());
244 }
245
DoSetDocumentReportingEndpoints(const base::UnguessableToken & reporting_source,const IsolationInfo & isolation_info,const NetworkAnonymizationKey & network_anonymization_key,const url::Origin & origin,base::flat_map<std::string,std::string> header_value)246 void DoSetDocumentReportingEndpoints(
247 const base::UnguessableToken& reporting_source,
248 const IsolationInfo& isolation_info,
249 const NetworkAnonymizationKey& network_anonymization_key,
250 const url::Origin& origin,
251 base::flat_map<std::string, std::string> header_value) {
252 DCHECK(initialized_);
253 ReportingHeaderParser::ProcessParsedReportingEndpointsHeader(
254 context_.get(), reporting_source, isolation_info,
255 network_anonymization_key, origin, std::move(header_value));
256 }
257
DoRemoveBrowsingData(uint64_t data_type_mask,const base::RepeatingCallback<bool (const url::Origin &)> & origin_filter)258 void DoRemoveBrowsingData(
259 uint64_t data_type_mask,
260 const base::RepeatingCallback<bool(const url::Origin&)>& origin_filter) {
261 DCHECK(initialized_);
262 ReportingBrowsingDataRemover::RemoveBrowsingData(
263 context_->cache(), data_type_mask, origin_filter);
264 }
265
DoRemoveAllBrowsingData(uint64_t data_type_mask)266 void DoRemoveAllBrowsingData(uint64_t data_type_mask) {
267 DCHECK(initialized_);
268 ReportingBrowsingDataRemover::RemoveAllBrowsingData(context_->cache(),
269 data_type_mask);
270 }
271
ExecuteBacklog()272 void ExecuteBacklog() {
273 DCHECK(initialized_);
274 DCHECK(context_);
275
276 if (shut_down_)
277 return;
278
279 for (base::OnceClosure& task : task_backlog_) {
280 std::move(task).Run();
281 }
282 task_backlog_.clear();
283 }
284
FetchAllClientsFromStoreIfNecessary()285 void FetchAllClientsFromStoreIfNecessary() {
286 if (!context_->IsClientDataPersisted() || started_loading_from_store_)
287 return;
288
289 started_loading_from_store_ = true;
290 FetchAllClientsFromStore();
291 }
292
FetchAllClientsFromStore()293 void FetchAllClientsFromStore() {
294 DCHECK(context_->IsClientDataPersisted());
295 DCHECK(!initialized_);
296
297 context_->store()->LoadReportingClients(base::BindOnce(
298 &ReportingServiceImpl::OnClientsLoaded, weak_factory_.GetWeakPtr()));
299 }
300
OnClientsLoaded(std::vector<ReportingEndpoint> loaded_endpoints,std::vector<CachedReportingEndpointGroup> loaded_endpoint_groups)301 void OnClientsLoaded(
302 std::vector<ReportingEndpoint> loaded_endpoints,
303 std::vector<CachedReportingEndpointGroup> loaded_endpoint_groups) {
304 initialized_ = true;
305 context_->cache()->AddClientsLoadedFromStore(
306 std::move(loaded_endpoints), std::move(loaded_endpoint_groups));
307 ExecuteBacklog();
308 }
309
310 // Returns either |network_anonymization_key| or an empty
311 // NetworkAnonymizationKey, based on |respect_network_anonymization_key_|.
312 // Should be used on all NetworkAnonymizationKeys passed in through public API
313 // calls.
FixupNetworkAnonymizationKey(const NetworkAnonymizationKey & network_anonymization_key)314 const NetworkAnonymizationKey& FixupNetworkAnonymizationKey(
315 const NetworkAnonymizationKey& network_anonymization_key) {
316 if (respect_network_anonymization_key_)
317 return network_anonymization_key;
318 return empty_nak_;
319 }
320
321 std::unique_ptr<ReportingContext> context_;
322 bool shut_down_ = false;
323 bool started_loading_from_store_ = false;
324 bool initialized_ = false;
325 std::vector<base::OnceClosure> task_backlog_;
326
327 bool respect_network_anonymization_key_ =
328 NetworkAnonymizationKey::IsPartitioningEnabled();
329
330 // Allows returning a NetworkAnonymizationKey by reference when
331 // |respect_network_anonymization_key_| is false.
332 NetworkAnonymizationKey empty_nak_;
333
334 base::WeakPtrFactory<ReportingServiceImpl> weak_factory_{this};
335 };
336
337 } // namespace
338
339 ReportingService::~ReportingService() = default;
340
341 // static
Create(const ReportingPolicy & policy,URLRequestContext * request_context,ReportingCache::PersistentReportingStore * store,const base::flat_map<std::string,GURL> & enterprise_reporting_endpoints)342 std::unique_ptr<ReportingService> ReportingService::Create(
343 const ReportingPolicy& policy,
344 URLRequestContext* request_context,
345 ReportingCache::PersistentReportingStore* store,
346 const base::flat_map<std::string, GURL>& enterprise_reporting_endpoints) {
347 return std::make_unique<ReportingServiceImpl>(ReportingContext::Create(
348 policy, request_context, store, enterprise_reporting_endpoints));
349 }
350
351 // static
CreateForTesting(std::unique_ptr<ReportingContext> reporting_context)352 std::unique_ptr<ReportingService> ReportingService::CreateForTesting(
353 std::unique_ptr<ReportingContext> reporting_context) {
354 return std::make_unique<ReportingServiceImpl>(std::move(reporting_context));
355 }
356
StatusAsValue() const357 base::Value ReportingService::StatusAsValue() const {
358 NOTIMPLEMENTED();
359 return base::Value();
360 }
361
362 } // namespace net
363