xref: /aosp_15_r20/external/cronet/net/reporting/reporting_service.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 
SendReportsAndRemoveSource(const base::UnguessableToken & reporting_source)75   void SendReportsAndRemoveSource(
76       const base::UnguessableToken& reporting_source) override {
77     DCHECK(!reporting_source.is_empty());
78     context_->delivery_agent()->SendReportsForSource(reporting_source);
79     context_->cache()->SetExpiredSource(reporting_source);
80   }
81 
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)82   void QueueReport(
83       const GURL& url,
84       const std::optional<base::UnguessableToken>& reporting_source,
85       const NetworkAnonymizationKey& network_anonymization_key,
86       const std::string& user_agent,
87       const std::string& group,
88       const std::string& type,
89       base::Value::Dict body,
90       int depth) override {
91     DCHECK(context_);
92     DCHECK(context_->delegate());
93     // If |reporting_source| is provided, it must not be empty.
94     DCHECK(!(reporting_source.has_value() && reporting_source->is_empty()));
95 
96     if (!context_->delegate()->CanQueueReport(url::Origin::Create(url)))
97       return;
98 
99     // Strip username, password, and ref fragment from the URL.
100     GURL sanitized_url = url.GetAsReferrer();
101     if (!sanitized_url.is_valid())
102       return;
103 
104     base::TimeTicks queued_ticks = context_->tick_clock().NowTicks();
105 
106     // base::Unretained is safe because the callback is stored in
107     // |task_backlog_| which will not outlive |this|.
108     DoOrBacklogTask(
109         base::BindOnce(&ReportingServiceImpl::DoQueueReport,
110                        base::Unretained(this), reporting_source,
111                        FixupNetworkAnonymizationKey(network_anonymization_key),
112                        std::move(sanitized_url), user_agent, group, type,
113                        std::move(body), depth, queued_ticks));
114   }
115 
ProcessReportToHeader(const url::Origin & origin,const NetworkAnonymizationKey & network_anonymization_key,const std::string & header_string)116   void ProcessReportToHeader(
117       const url::Origin& origin,
118       const NetworkAnonymizationKey& network_anonymization_key,
119       const std::string& header_string) override {
120     if (header_string.size() > kMaxJsonSize)
121       return;
122 
123     std::optional<base::Value> header_value = base::JSONReader::Read(
124         "[" + header_string + "]", base::JSON_PARSE_RFC, kMaxJsonDepth);
125     if (!header_value)
126       return;
127 
128     DVLOG(1) << "Received Reporting policy for " << origin;
129     DoOrBacklogTask(base::BindOnce(
130         &ReportingServiceImpl::DoProcessReportToHeader, base::Unretained(this),
131         FixupNetworkAnonymizationKey(network_anonymization_key), origin,
132         std::move(header_value).value()));
133   }
134 
RemoveBrowsingData(uint64_t data_type_mask,const base::RepeatingCallback<bool (const url::Origin &)> & origin_filter)135   void RemoveBrowsingData(
136       uint64_t data_type_mask,
137       const base::RepeatingCallback<bool(const url::Origin&)>& origin_filter)
138       override {
139     DoOrBacklogTask(base::BindOnce(&ReportingServiceImpl::DoRemoveBrowsingData,
140                                    base::Unretained(this), data_type_mask,
141                                    origin_filter));
142   }
143 
RemoveAllBrowsingData(uint64_t data_type_mask)144   void RemoveAllBrowsingData(uint64_t data_type_mask) override {
145     DoOrBacklogTask(
146         base::BindOnce(&ReportingServiceImpl::DoRemoveAllBrowsingData,
147                        base::Unretained(this), data_type_mask));
148   }
149 
OnShutdown()150   void OnShutdown() override {
151     shut_down_ = true;
152     context_->OnShutdown();
153   }
154 
GetPolicy() const155   const ReportingPolicy& GetPolicy() const override {
156     return context_->policy();
157   }
158 
StatusAsValue() const159   base::Value StatusAsValue() const override {
160     base::Value::Dict dict;
161     dict.Set("reportingEnabled", true);
162     dict.Set("clients", context_->cache()->GetClientsAsValue());
163     dict.Set("reports", context_->cache()->GetReportsAsValue());
164     return base::Value(std::move(dict));
165   }
166 
GetReports() const167   std::vector<raw_ptr<const ReportingReport, VectorExperimental>> GetReports()
168       const override {
169     std::vector<raw_ptr<const net::ReportingReport, VectorExperimental>>
170         reports;
171     context_->cache()->GetReports(&reports);
172     return reports;
173   }
174 
175   base::flat_map<url::Origin, std::vector<ReportingEndpoint>>
GetV1ReportingEndpointsByOrigin() const176   GetV1ReportingEndpointsByOrigin() const override {
177     return context_->cache()->GetV1ReportingEndpointsByOrigin();
178   }
179 
AddReportingCacheObserver(ReportingCacheObserver * observer)180   void AddReportingCacheObserver(ReportingCacheObserver* observer) override {
181     context_->AddCacheObserver(observer);
182   }
183 
RemoveReportingCacheObserver(ReportingCacheObserver * observer)184   void RemoveReportingCacheObserver(ReportingCacheObserver* observer) override {
185     context_->RemoveCacheObserver(observer);
186   }
187 
GetContextForTesting() const188   ReportingContext* GetContextForTesting() const override {
189     return context_.get();
190   }
191 
192  private:
DoOrBacklogTask(base::OnceClosure task)193   void DoOrBacklogTask(base::OnceClosure task) {
194     if (shut_down_)
195       return;
196 
197     FetchAllClientsFromStoreIfNecessary();
198 
199     if (!initialized_) {
200       task_backlog_.push_back(std::move(task));
201       return;
202     }
203 
204     std::move(task).Run();
205   }
206 
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)207   void DoQueueReport(
208       const std::optional<base::UnguessableToken>& reporting_source,
209       const NetworkAnonymizationKey& network_anonymization_key,
210       GURL sanitized_url,
211       const std::string& user_agent,
212       const std::string& group,
213       const std::string& type,
214       base::Value::Dict body,
215       int depth,
216       base::TimeTicks queued_ticks) {
217     DCHECK(initialized_);
218     context_->cache()->AddReport(
219         reporting_source, network_anonymization_key, sanitized_url, user_agent,
220         group, type, std::move(body), depth, queued_ticks, 0 /* attempts */);
221   }
222 
DoProcessReportToHeader(const NetworkAnonymizationKey & network_anonymization_key,const url::Origin & origin,const base::Value & header_value)223   void DoProcessReportToHeader(
224       const NetworkAnonymizationKey& network_anonymization_key,
225       const url::Origin& origin,
226       const base::Value& header_value) {
227     DCHECK(initialized_);
228     DCHECK(header_value.is_list());
229     ReportingHeaderParser::ParseReportToHeader(context_.get(),
230                                                network_anonymization_key,
231                                                origin, header_value.GetList());
232   }
233 
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)234   void DoSetDocumentReportingEndpoints(
235       const base::UnguessableToken& reporting_source,
236       const IsolationInfo& isolation_info,
237       const NetworkAnonymizationKey& network_anonymization_key,
238       const url::Origin& origin,
239       base::flat_map<std::string, std::string> header_value) {
240     DCHECK(initialized_);
241     ReportingHeaderParser::ProcessParsedReportingEndpointsHeader(
242         context_.get(), reporting_source, isolation_info,
243         network_anonymization_key, origin, std::move(header_value));
244   }
245 
DoRemoveBrowsingData(uint64_t data_type_mask,const base::RepeatingCallback<bool (const url::Origin &)> & origin_filter)246   void DoRemoveBrowsingData(
247       uint64_t data_type_mask,
248       const base::RepeatingCallback<bool(const url::Origin&)>& origin_filter) {
249     DCHECK(initialized_);
250     ReportingBrowsingDataRemover::RemoveBrowsingData(
251         context_->cache(), data_type_mask, origin_filter);
252   }
253 
DoRemoveAllBrowsingData(uint64_t data_type_mask)254   void DoRemoveAllBrowsingData(uint64_t data_type_mask) {
255     DCHECK(initialized_);
256     ReportingBrowsingDataRemover::RemoveAllBrowsingData(context_->cache(),
257                                                         data_type_mask);
258   }
259 
ExecuteBacklog()260   void ExecuteBacklog() {
261     DCHECK(initialized_);
262     DCHECK(context_);
263 
264     if (shut_down_)
265       return;
266 
267     for (base::OnceClosure& task : task_backlog_) {
268       std::move(task).Run();
269     }
270     task_backlog_.clear();
271   }
272 
FetchAllClientsFromStoreIfNecessary()273   void FetchAllClientsFromStoreIfNecessary() {
274     if (!context_->IsClientDataPersisted() || started_loading_from_store_)
275       return;
276 
277     started_loading_from_store_ = true;
278     FetchAllClientsFromStore();
279   }
280 
FetchAllClientsFromStore()281   void FetchAllClientsFromStore() {
282     DCHECK(context_->IsClientDataPersisted());
283     DCHECK(!initialized_);
284 
285     context_->store()->LoadReportingClients(base::BindOnce(
286         &ReportingServiceImpl::OnClientsLoaded, weak_factory_.GetWeakPtr()));
287   }
288 
OnClientsLoaded(std::vector<ReportingEndpoint> loaded_endpoints,std::vector<CachedReportingEndpointGroup> loaded_endpoint_groups)289   void OnClientsLoaded(
290       std::vector<ReportingEndpoint> loaded_endpoints,
291       std::vector<CachedReportingEndpointGroup> loaded_endpoint_groups) {
292     initialized_ = true;
293     context_->cache()->AddClientsLoadedFromStore(
294         std::move(loaded_endpoints), std::move(loaded_endpoint_groups));
295     ExecuteBacklog();
296   }
297 
298   // Returns either |network_anonymization_key| or an empty
299   // NetworkAnonymizationKey, based on |respect_network_anonymization_key_|.
300   // Should be used on all NetworkAnonymizationKeys passed in through public API
301   // calls.
FixupNetworkAnonymizationKey(const NetworkAnonymizationKey & network_anonymization_key)302   const NetworkAnonymizationKey& FixupNetworkAnonymizationKey(
303       const NetworkAnonymizationKey& network_anonymization_key) {
304     if (respect_network_anonymization_key_)
305       return network_anonymization_key;
306     return empty_nak_;
307   }
308 
309   std::unique_ptr<ReportingContext> context_;
310   bool shut_down_ = false;
311   bool started_loading_from_store_ = false;
312   bool initialized_ = false;
313   std::vector<base::OnceClosure> task_backlog_;
314 
315   bool respect_network_anonymization_key_ =
316       NetworkAnonymizationKey::IsPartitioningEnabled();
317 
318   // Allows returning a NetworkAnonymizationKey by reference when
319   // |respect_network_anonymization_key_| is false.
320   NetworkAnonymizationKey empty_nak_;
321 
322   base::WeakPtrFactory<ReportingServiceImpl> weak_factory_{this};
323 };
324 
325 }  // namespace
326 
327 ReportingService::~ReportingService() = default;
328 
329 // static
Create(const ReportingPolicy & policy,URLRequestContext * request_context,ReportingCache::PersistentReportingStore * store)330 std::unique_ptr<ReportingService> ReportingService::Create(
331     const ReportingPolicy& policy,
332     URLRequestContext* request_context,
333     ReportingCache::PersistentReportingStore* store) {
334   return std::make_unique<ReportingServiceImpl>(
335       ReportingContext::Create(policy, request_context, store));
336 }
337 
338 // static
CreateForTesting(std::unique_ptr<ReportingContext> reporting_context)339 std::unique_ptr<ReportingService> ReportingService::CreateForTesting(
340     std::unique_ptr<ReportingContext> reporting_context) {
341   return std::make_unique<ReportingServiceImpl>(std::move(reporting_context));
342 }
343 
StatusAsValue() const344 base::Value ReportingService::StatusAsValue() const {
345   NOTIMPLEMENTED();
346   return base::Value();
347 }
348 
349 }  // namespace net
350