• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef NET_REPORTING_REPORTING_CACHE_H_
6 #define NET_REPORTING_REPORTING_CACHE_H_
7 
8 #include <memory>
9 #include <optional>
10 #include <set>
11 #include <string>
12 #include <vector>
13 
14 #include "base/containers/flat_map.h"
15 #include "base/containers/flat_set.h"
16 #include "base/functional/callback.h"
17 #include "base/memory/raw_ptr.h"
18 #include "base/time/time.h"
19 #include "base/unguessable_token.h"
20 #include "base/values.h"
21 #include "net/base/net_export.h"
22 #include "net/reporting/reporting_endpoint.h"
23 #include "net/reporting/reporting_header_parser.h"
24 #include "net/reporting/reporting_report.h"
25 #include "net/reporting/reporting_target_type.h"
26 #include "url/gurl.h"
27 #include "url/origin.h"
28 
29 namespace net {
30 
31 class ReportingContext;
32 class IsolationInfo;
33 class NetworkAnonymizationKey;
34 
35 // The cache holds undelivered reports and clients (per-origin endpoint
36 // configurations) in memory. (It is not responsible for persisting them.)
37 //
38 // Each Reporting "endpoint" represents a report collector at some specified
39 // URL. Endpoints are organized into named "endpoint groups", each of which
40 // additionally specifies some properties such as expiration time.
41 // A "client" represents the entire endpoint configuration set by an origin via
42 // a Report-To header, which consists of multiple endpoint groups, each of which
43 // consists of multiple endpoints. An endpoint group is keyed by its name.  An
44 // endpoint is unkeyed except by the client and group structure tree above it.
45 //
46 // The cache implementation corresponds roughly to the "Reporting cache"
47 // described in the spec, except that endpoints and clients are stored in a more
48 // structurally-convenient way, and endpoint failures/retry-after are tracked in
49 // ReportingEndpointManager.
50 //
51 // The cache implementation has the notion of "pending" reports. These are
52 // reports that are part of an active delivery attempt, so they won't be
53 // actually deallocated. Any attempt to remove a pending report will mark it
54 // "doomed", which will cause it to be deallocated once it is no longer pending.
55 class NET_EXPORT ReportingCache {
56  public:
57   class PersistentReportingStore;
58 
59   static std::unique_ptr<ReportingCache> Create(
60       ReportingContext* context,
61       const base::flat_map<std::string, GURL>& enterprise_reporting_endpoints);
62 
63   virtual ~ReportingCache();
64 
65   // Adds a report to the cache.
66   //
67   // |reporting_source| and |network_anonymization_key| will be used when the
68   // report is delivered, to determine which endpoints are eligible to receive
69   // this report, and which other reports this report can be batched with.
70   //
71   // All other parameters correspond to the desired values for the relevant
72   // fields in ReportingReport.
73   virtual void AddReport(
74       const std::optional<base::UnguessableToken>& reporting_source,
75       const NetworkAnonymizationKey& network_anonymization_key,
76       const GURL& url,
77       const std::string& user_agent,
78       const std::string& group_name,
79       const std::string& type,
80       base::Value::Dict body,
81       int depth,
82       base::TimeTicks queued,
83       int attempts,
84       ReportingTargetType target_type) = 0;
85 
86   // Gets all reports in the cache. The returned pointers are valid as long as
87   // either no calls to |RemoveReports| have happened or the reports' |pending|
88   // flag has been set to true using |SetReportsPending|. Does not return
89   // doomed reports (pending reports for which removal has been requested).
90   //
91   // (Clears any existing data in |*reports_out|.)
92   virtual void GetReports(
93       std::vector<raw_ptr<const ReportingReport, VectorExperimental>>*
94           reports_out) const = 0;
95 
96   // Gets all reports in the cache, including pending and doomed reports, as a
97   // base::Value.
98   virtual base::Value GetReportsAsValue() const = 0;
99 
100   // Gets all reports in the cache that aren't pending or doomed (i.e. that are
101   // eligible for delivery), and marks returned reports as pending in
102   // preparation for a delivery attempt. The returned pointers are valid as long
103   // as the reports are still pending.
104   virtual std::vector<raw_ptr<const ReportingReport, VectorExperimental>>
105   GetReportsToDeliver() = 0;
106 
107   // Gets all reports in the cache which are eligible for delivery, which were
108   // queued for a single `reporting_source`, and marks returned reports as
109   // pending in preparation for a delivery attempt. The returned pointers are
110   // valid as long as the reports are still pending. This method is used when a
111   // reporting source is being destroyed, to trigger delivery of any remaining
112   // outstanding reports.
113   virtual std::vector<raw_ptr<const ReportingReport, VectorExperimental>>
114   GetReportsToDeliverForSource(
115       const base::UnguessableToken& reporting_source) = 0;
116 
117   // Unmarks a set of reports as pending. |reports| must be previously marked as
118   // pending.
119   virtual void ClearReportsPending(
120       const std::vector<raw_ptr<const ReportingReport, VectorExperimental>>&
121           reports) = 0;
122 
123   // Increments |attempts| on a set of reports.
124   virtual void IncrementReportsAttempts(
125       const std::vector<raw_ptr<const ReportingReport, VectorExperimental>>&
126           reports) = 0;
127 
128   // Records that we attempted (and possibly succeeded at) delivering
129   // |reports_delivered| reports to the specified endpoint.
130   virtual void IncrementEndpointDeliveries(
131       const ReportingEndpointGroupKey& group_key,
132       const GURL& url,
133       int reports_delivered,
134       bool successful) = 0;
135 
136   // Marks a `reporting_source` as expired, when the source (document or
137   // worker) has beed destroyed. The endpoint configuration for the source will
138   // be removed by the garbage collector once all outstanding reports have been
139   // delivered or expired.
140   virtual void SetExpiredSource(
141       const base::UnguessableToken& reporting_source) = 0;
142 
143   // Gets the current set of expired reporting sources.
144   virtual const base::flat_set<base::UnguessableToken>& GetExpiredSources()
145       const = 0;
146 
147   // Removes a set of reports. Any reports that are pending will not be removed
148   // immediately, but rather marked doomed and removed once they are no longer
149   // pending.
150   virtual void RemoveReports(
151       const std::vector<raw_ptr<const ReportingReport, VectorExperimental>>&
152           reports) = 0;
153   virtual void RemoveReports(
154       const std::vector<raw_ptr<const ReportingReport, VectorExperimental>>&
155           reports,
156       bool delivery_success) = 0;
157 
158   // Removes all reports. Like |RemoveReports()|, pending reports are doomed
159   // until no longer pending.
160   virtual void RemoveAllReports() = 0;
161 
162   // Gets the count of reports in the cache, *including* doomed reports.
163   //
164   // Needed to ensure that doomed reports are eventually deleted, since no
165   // method provides a view of *every* report in the cache, just non-doomed
166   // ones.
167   virtual size_t GetFullReportCountForTesting() const = 0;
168 
169   // Gets the count of reports in the cache with a specific `status`.
170   virtual size_t GetReportCountWithStatusForTesting(
171       ReportingReport::Status status) const = 0;
172 
173   virtual bool IsReportPendingForTesting(
174       const ReportingReport* report) const = 0;
175 
176   virtual bool IsReportDoomedForTesting(
177       const ReportingReport* report) const = 0;
178 
179   // Adds a new client to the cache for |origin|, or updates the existing one
180   // to match the new header. All values are assumed to be valid as they have
181   // passed through the ReportingHeaderParser.
182   virtual void OnParsedHeader(
183       const NetworkAnonymizationKey& network_anonymization_key,
184       const url::Origin& origin,
185       std::vector<ReportingEndpointGroup> parsed_header) = 0;
186 
187   // Adds named endpoints for |reporting_source| to the cache, based on the
188   // received Reporting-Endpoints header.
189   // |reporting_source| is the token identifying the document or worker with
190   // which this header was received, and may not be empty.
191   // |isolation_info| is the appropriate network isolation info struct for that
192   // source, and is used for determining credentials to send with reports.
193   virtual void OnParsedReportingEndpointsHeader(
194       const base::UnguessableToken& reporting_source,
195       const IsolationInfo& isolation_info,
196       std::vector<ReportingEndpoint> parsed_header) = 0;
197 
198   // Sets reporting endpoints configured by the ReportingEndpoints enterprise
199   // policy in the cache.
200   virtual void SetEnterpriseReportingEndpoints(
201       const base::flat_map<std::string, GURL>& endpoints) = 0;
202 
203   // Gets all the origins of clients in the cache.
204   virtual std::set<url::Origin> GetAllOrigins() const = 0;
205 
206   // Remove client for the given (NAK, origin) pair, if it exists in the cache.
207   // All endpoint groups and endpoints for that client are also removed.
208   virtual void RemoveClient(
209       const NetworkAnonymizationKey& network_anonymization_key,
210       const url::Origin& origin) = 0;
211 
212   // Remove all clients for the given |origin|, if any exists in the cache.
213   // All endpoint groups and endpoints for |origin| are also removed.
214   virtual void RemoveClientsForOrigin(const url::Origin& origin) = 0;
215 
216   // Remove all clients, groups, and endpoints from the cache.
217   virtual void RemoveAllClients() = 0;
218 
219   // Remove the endpoint group matching |group_key|, and remove
220   // all endpoints for that group. May cause the client it was associated with
221   // to be deleted if it becomes empty.
222   virtual void RemoveEndpointGroup(
223       const ReportingEndpointGroupKey& group_key) = 0;
224 
225   // Remove all endpoints for with |url|, regardless of origin or group. Used
226   // when a delivery returns 410 Gone. May cause deletion of groups/clients if
227   // they become empty.
228   virtual void RemoveEndpointsForUrl(const GURL& url) = 0;
229 
230   // Remove `reporting_source` from the cache, including any configured
231   // endpoints. There should be no non-doomed reports in the cache for
232   // `reporting_source` when this is called.
233   virtual void RemoveSourceAndEndpoints(
234       const base::UnguessableToken& reporting_source) = 0;
235 
236   // Insert endpoints and endpoint groups that have been loaded from the store.
237   //
238   // You must only call this method if context.store() was non-null when you
239   // constructed the cache and persist_clients_across_restarts in your
240   // ReportingPolicy is true.
241   virtual void AddClientsLoadedFromStore(
242       std::vector<ReportingEndpoint> loaded_endpoints,
243       std::vector<CachedReportingEndpointGroup> loaded_endpoint_groups) = 0;
244 
245   // Gets endpoints that apply to a delivery for |origin| and |group|.
246   //
247   // First checks for |group| in a client exactly matching |origin|.
248   // If none exists, then checks for |group| in clients for superdomains
249   // of |origin| which have include_subdomains enabled, returning only the
250   // endpoints for the most specific applicable parent origin of |origin|. If
251   // there are multiple origins with that group within the most specific
252   // applicable superdomain, gets endpoints for that group from only one of
253   // them. The group must not be expired.
254   //
255   // For example, given the origin https://foo.bar.baz.com/, the cache
256   // would prioritize returning each potential match below over the ones below
257   // it, for groups with name |group| with include_subdomains enabled:
258   // 1. https://foo.bar.baz.com/ (exact origin match)
259   // 2. https://foo.bar.baz.com:444/ (technically, a superdomain)
260   // 3. https://bar.baz.com/, https://bar.baz.com:444/, etc. (superdomain)
261   // 4. https://baz.com/, https://baz.com:444/, etc. (superdomain)
262   // If both https://bar.baz.com/ and https://bar.baz.com:444/ had a group with
263   // name |group| with include_subdomains enabled, this method would return
264   // endpoints from that group from the earliest-inserted origin.
265   virtual std::vector<ReportingEndpoint> GetCandidateEndpointsForDelivery(
266       const ReportingEndpointGroupKey& group_key) = 0;
267 
268   // Gets the status of all clients in the cache, including expired ones, as a
269   // base::Value.
270   virtual base::Value GetClientsAsValue() const = 0;
271 
272   // Gets the total number of endpoints in the cache across all origins.
273   virtual size_t GetEndpointCount() const = 0;
274 
275   // Flush the contents of the cache to disk, if applicable.
276   virtual void Flush() = 0;
277 
278   // Returns all V1 endpoints keyed by origin.
279   virtual base::flat_map<url::Origin, std::vector<ReportingEndpoint>>
280   GetV1ReportingEndpointsByOrigin() const = 0;
281 
282   // Returns the endpoint named |endpoint_name| for the reporting source, if it
283   // was configured with the Reporting-Endpoints header, otherwise returns an
284   // invalid ReportingEndpoint.
285   // |reporting_source| must not be empty.
286   virtual ReportingEndpoint GetV1EndpointForTesting(
287       const base::UnguessableToken& reporting_source,
288       const std::string& endpoint_name) const = 0;
289 
290   // Finds an endpoint for the given |group_key| and |url|, otherwise returns an
291   // invalid ReportingEndpoint.
292   virtual ReportingEndpoint GetEndpointForTesting(
293       const ReportingEndpointGroupKey& group_key,
294       const GURL& url) const = 0;
295 
296   // Returns all enterprise endpoints in the cache.
297   virtual std::vector<ReportingEndpoint> GetEnterpriseEndpointsForTesting()
298       const = 0;
299 
300   // Returns whether an endpoint group with exactly the given properties exists
301   // in the cache. If |expires| is base::Time(), it will not be checked.
302   virtual bool EndpointGroupExistsForTesting(
303       const ReportingEndpointGroupKey& group_key,
304       OriginSubdomains include_subdomains,
305       base::Time expires) const = 0;
306 
307   // Returns whether a client for the given (NAK, Origin) exists.
308   virtual bool ClientExistsForTesting(
309       const NetworkAnonymizationKey& network_anonymization_key,
310       const url::Origin& origin) const = 0;
311 
312   // Returns number of endpoint groups.
313   virtual size_t GetEndpointGroupCountForTesting() const = 0;
314 
315   // Returns number of endpoint groups.
316   virtual size_t GetClientCountForTesting() const = 0;
317 
318   // Returns number of reporting source tokens associated with endpoints.
319   virtual size_t GetReportingSourceCountForTesting() const = 0;
320 
321   // Sets an endpoint with the given properties in a group with the given
322   // properties, bypassing header parsing. Note that the endpoint is not
323   // guaranteed to exist in the cache after calling this function, if endpoint
324   // eviction is triggered. Unlike the AddOrUpdate*() methods used in header
325   // parsing, this method inserts or updates a single endpoint while leaving the
326   // existing configuration for that origin intact.
327   virtual void SetEndpointForTesting(const ReportingEndpointGroupKey& group_key,
328                                      const GURL& url,
329                                      OriginSubdomains include_subdomains,
330                                      base::Time expires,
331                                      int priority,
332                                      int weight) = 0;
333 
334   // Sets a V1 named endpoint with the given key for `reporting_source`,
335   // bypassing header parsing. This method inserts a single endpoint while
336   // leaving the existing configuration for that source intact. If any
337   // endpoints already exist for this source, then `isolation_info` must
338   // match the value that was previously associated with it.
339   virtual void SetV1EndpointForTesting(
340       const ReportingEndpointGroupKey& group_key,
341       const base::UnguessableToken& reporting_source,
342       const IsolationInfo& isolation_info,
343       const GURL& url) = 0;
344 
345   // Sets an enterprise endpoint.
346   virtual void SetEnterpriseEndpointForTesting(
347       const ReportingEndpointGroupKey& group_key,
348       const GURL& url) = 0;
349 
350   // Gets the isolation info associated with `reporting_source`, used when
351   // determining which credentials to send for a given report. If
352   // `reporting_source` is nullopt, as when a report is being delivered to a V0
353   // reporting endpoint group, this always will return an empty site.
354   virtual IsolationInfo GetIsolationInfoForEndpoint(
355       const ReportingEndpoint& endpoint) const = 0;
356 };
357 
358 // Persistent storage for Reporting reports and clients.
359 class NET_EXPORT ReportingCache::PersistentReportingStore {
360  public:
361   using ReportingClientsLoadedCallback =
362       base::OnceCallback<void(std::vector<ReportingEndpoint>,
363                               std::vector<CachedReportingEndpointGroup>)>;
364 
365   PersistentReportingStore() = default;
366 
367   PersistentReportingStore(const PersistentReportingStore&) = delete;
368   PersistentReportingStore& operator=(const PersistentReportingStore&) = delete;
369 
370   virtual ~PersistentReportingStore() = default;
371 
372   // Initializes the store and retrieves stored endpoints and endpoint groups.
373   // Called only once at startup.
374   virtual void LoadReportingClients(
375       ReportingClientsLoadedCallback loaded_callback) = 0;
376 
377   // Adds an endpoint to the store.
378   virtual void AddReportingEndpoint(const ReportingEndpoint& endpoint) = 0;
379   // Adds an endpoint group to the store.
380   virtual void AddReportingEndpointGroup(
381       const CachedReportingEndpointGroup& group) = 0;
382 
383   // Updates the access time of an endpoint group in the store.
384   virtual void UpdateReportingEndpointGroupAccessTime(
385       const CachedReportingEndpointGroup& group) = 0;
386 
387   // Updates the details of an endpoint in the store.
388   virtual void UpdateReportingEndpointDetails(
389       const ReportingEndpoint& endpoint) = 0;
390   // Updates the details of an endpoint group in the store.
391   virtual void UpdateReportingEndpointGroupDetails(
392       const CachedReportingEndpointGroup& group) = 0;
393 
394   // Deletes an endpoint from the store.
395   virtual void DeleteReportingEndpoint(const ReportingEndpoint& endpoint) = 0;
396   // Deletes an endpoint group from the store.
397   virtual void DeleteReportingEndpointGroup(
398       const CachedReportingEndpointGroup& group) = 0;
399 
400   // TODO(chlily): methods to load, add, and delete reports will be added.
401 
402   // Flushes the store.
403   virtual void Flush() = 0;
404 };
405 
406 }  // namespace net
407 
408 #endif  // NET_REPORTING_REPORTING_CACHE_H_
409