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