• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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_IMPL_H_
6 #define NET_REPORTING_REPORTING_CACHE_IMPL_H_
7 
8 #include <map>
9 #include <memory>
10 #include <optional>
11 #include <set>
12 #include <string>
13 #include <unordered_set>
14 #include <utility>
15 #include <vector>
16 
17 #include "base/containers/flat_map.h"
18 #include "base/containers/flat_set.h"
19 #include "base/containers/unique_ptr_adapters.h"
20 #include "base/memory/raw_ptr.h"
21 #include "base/sequence_checker.h"
22 #include "base/time/time.h"
23 #include "base/unguessable_token.h"
24 #include "base/values.h"
25 #include "net/base/isolation_info.h"
26 #include "net/base/network_anonymization_key.h"
27 #include "net/reporting/reporting_cache.h"
28 #include "net/reporting/reporting_context.h"
29 #include "net/reporting/reporting_endpoint.h"
30 #include "net/reporting/reporting_header_parser.h"
31 #include "net/reporting/reporting_report.h"
32 #include "net/reporting/reporting_target_type.h"
33 #include "url/gurl.h"
34 #include "url/origin.h"
35 
36 namespace net {
37 
38 class ReportingCacheImpl : public ReportingCache {
39  public:
40   explicit ReportingCacheImpl(
41       ReportingContext* context,
42       const base::flat_map<std::string, GURL>& enterprise_reporting_endpoints);
43 
44   ReportingCacheImpl(const ReportingCacheImpl&) = delete;
45   ReportingCacheImpl& operator=(const ReportingCacheImpl&) = delete;
46 
47   ~ReportingCacheImpl() override;
48 
49   // ReportingCache implementation
50   void AddReport(const std::optional<base::UnguessableToken>& reporting_source,
51                  const NetworkAnonymizationKey& network_anonymization_key,
52                  const GURL& url,
53                  const std::string& user_agent,
54                  const std::string& group_name,
55                  const std::string& type,
56                  base::Value::Dict body,
57                  int depth,
58                  base::TimeTicks queued,
59                  int attempts,
60                  ReportingTargetType target_type) override;
61   void GetReports(
62       std::vector<raw_ptr<const ReportingReport, VectorExperimental>>*
63           reports_out) const override;
64   base::Value GetReportsAsValue() const override;
65   std::vector<raw_ptr<const ReportingReport, VectorExperimental>>
66   GetReportsToDeliver() override;
67   std::vector<raw_ptr<const ReportingReport, VectorExperimental>>
68   GetReportsToDeliverForSource(
69       const base::UnguessableToken& reporting_source) override;
70   void ClearReportsPending(
71       const std::vector<raw_ptr<const ReportingReport, VectorExperimental>>&
72           reports) override;
73   void IncrementReportsAttempts(
74       const std::vector<raw_ptr<const ReportingReport, VectorExperimental>>&
75           reports) override;
76   base::flat_map<url::Origin, std::vector<ReportingEndpoint>>
77   GetV1ReportingEndpointsByOrigin() const override;
78   void IncrementEndpointDeliveries(const ReportingEndpointGroupKey& group_key,
79                                    const GURL& url,
80                                    int reports_delivered,
81                                    bool successful) override;
82   void SetExpiredSource(
83       const base::UnguessableToken& reporting_source) override;
84   const base::flat_set<base::UnguessableToken>& GetExpiredSources()
85       const override;
86   void RemoveReports(
87       const std::vector<raw_ptr<const ReportingReport, VectorExperimental>>&
88           reports) override;
89   void RemoveReports(
90       const std::vector<raw_ptr<const ReportingReport, VectorExperimental>>&
91           reports,
92       bool delivery_success) override;
93   void RemoveAllReports() override;
94   size_t GetFullReportCountForTesting() const override;
95   size_t GetReportCountWithStatusForTesting(
96       ReportingReport::Status status) const override;
97   bool IsReportPendingForTesting(const ReportingReport* report) const override;
98   bool IsReportDoomedForTesting(const ReportingReport* report) const override;
99   void OnParsedHeader(
100       const NetworkAnonymizationKey& network_anonymization_key,
101       const url::Origin& origin,
102       std::vector<ReportingEndpointGroup> parsed_header) override;
103   void OnParsedReportingEndpointsHeader(
104       const base::UnguessableToken& reporting_source,
105       const IsolationInfo& isolation_info,
106       std::vector<ReportingEndpoint> parsed_header) override;
107   void SetEnterpriseReportingEndpoints(
108       const base::flat_map<std::string, GURL>& endpoints) override;
109   std::set<url::Origin> GetAllOrigins() const override;
110   void RemoveClient(const NetworkAnonymizationKey& network_anonymization_key,
111                     const url::Origin& origin) override;
112   void RemoveClientsForOrigin(const url::Origin& origin) override;
113   void RemoveAllClients() override;
114   void RemoveEndpointGroup(const ReportingEndpointGroupKey& group_key) override;
115   void RemoveEndpointsForUrl(const GURL& url) override;
116   void RemoveSourceAndEndpoints(
117       const base::UnguessableToken& reporting_source) override;
118   void AddClientsLoadedFromStore(
119       std::vector<ReportingEndpoint> loaded_endpoints,
120       std::vector<CachedReportingEndpointGroup> loaded_endpoint_groups)
121       override;
122   std::vector<ReportingEndpoint> GetCandidateEndpointsForDelivery(
123       const ReportingEndpointGroupKey& group_key) override;
124   base::Value GetClientsAsValue() const override;
125   size_t GetEndpointCount() const override;
126   void Flush() override;
127   ReportingEndpoint GetV1EndpointForTesting(
128       const base::UnguessableToken& reporting_source,
129       const std::string& endpoint_name) const override;
130   ReportingEndpoint GetEndpointForTesting(
131       const ReportingEndpointGroupKey& group_key,
132       const GURL& url) const override;
133   std::vector<ReportingEndpoint> GetEnterpriseEndpointsForTesting()
134       const override;
135   bool EndpointGroupExistsForTesting(const ReportingEndpointGroupKey& group_key,
136                                      OriginSubdomains include_subdomains,
137                                      base::Time expires) const override;
138   bool ClientExistsForTesting(
139       const NetworkAnonymizationKey& network_anonymization_key,
140       const url::Origin& origin) const override;
141   size_t GetEndpointGroupCountForTesting() const override;
142   size_t GetClientCountForTesting() const override;
143   size_t GetReportingSourceCountForTesting() const override;
144   void SetEndpointForTesting(const ReportingEndpointGroupKey& group_key,
145                              const GURL& url,
146                              OriginSubdomains include_subdomains,
147                              base::Time expires,
148                              int priority,
149                              int weight) override;
150   void SetV1EndpointForTesting(const ReportingEndpointGroupKey& group_key,
151                                const base::UnguessableToken& reporting_source,
152                                const IsolationInfo& isolation_info,
153                                const GURL& url) override;
154   void SetEnterpriseEndpointForTesting(
155       const ReportingEndpointGroupKey& group_key,
156       const GURL& url) override;
157   IsolationInfo GetIsolationInfoForEndpoint(
158       const ReportingEndpoint& endpoint) const override;
159 
160  private:
161   // Represents the entire Report-To configuration for a (NAK, origin) pair.
162   struct Client {
163     Client(const NetworkAnonymizationKey& network_anonymization_key,
164            const url::Origin& origin);
165 
166     Client(const Client& other);
167     Client(Client&& other);
168 
169     Client& operator=(const Client& other);
170     Client& operator=(Client&& other);
171 
172     ~Client();
173 
174     // NAK of the context associated with this client. Needed to prevent leaking
175     // third party contexts across sites.
176     NetworkAnonymizationKey network_anonymization_key;
177 
178     // Origin that configured this client.
179     url::Origin origin;
180 
181     // Total number of endpoints for this origin. Should stay in sync with the
182     // sum of endpoint counts for all the groups within this client.
183     size_t endpoint_count = 0;
184 
185     // Last time that any of the groups for this origin was accessed for a
186     // delivery or updated via a new header. Should stay in sync with the latest
187     // |last_used| of all the groups within this client.
188     base::Time last_used;
189 
190     // Set of endpoint group names for this origin.
191     std::set<std::string> endpoint_group_names;
192   };
193 
194   using ReportSet = base::flat_set<std::unique_ptr<ReportingReport>,
195                                    base::UniquePtrComparator>;
196   using ClientMap = std::multimap<std::string, Client>;
197   using EndpointGroupMap =
198       std::map<ReportingEndpointGroupKey, CachedReportingEndpointGroup>;
199   using EndpointMap =
200       std::multimap<ReportingEndpointGroupKey, ReportingEndpoint>;
201 
202   ReportSet::const_iterator FindReportToEvict() const;
203 
204   // Consistency-checks the entire data structure of clients, groups, and
205   // endpoints, if DCHECK is on. The cached clients should pass this consistency
206   // check after completely parsing a header (i.e. not after the intermediate
207   // steps), and before and after any of the public methods that remove or
208   // retrieve client info. Also calls |sequence_checker_| to DCHECK that we are
209   // being called on a valid sequence.
210   void ConsistencyCheckClients() const;
211 
212   // Helper methods for ConsistencyCheckClients():
213 #if DCHECK_IS_ON()
214   // Returns number of endpoint groups found in |client|.
215   size_t ConsistencyCheckClient(const std::string& domain,
216                                 const Client& client) const;
217 
218   // Returns the number of endpoints found in |group|.
219   size_t ConsistencyCheckEndpointGroup(
220       const ReportingEndpointGroupKey& key,
221       const CachedReportingEndpointGroup& group) const;
222 
223   void ConsistencyCheckEndpoint(const ReportingEndpointGroupKey& key,
224                                 const ReportingEndpoint& endpoint,
225                                 EndpointMap::const_iterator endpoint_it) const;
226 #endif  // DCHECK_IS_ON()
227 
228   // Finds iterator to the client with the given |network_anonymization_key| and
229   // |origin|, if one exists. Returns |clients_.end()| if none is found.
230   ClientMap::iterator FindClientIt(
231       const NetworkAnonymizationKey& network_anonymization_key,
232       const url::Origin& origin);
233 
234   // Overload that takes a ReportingEndpointGroupKey and finds the client
235   // to which a group specified by the |group_key| would belong. The group name
236   // of the key is ignored.
237   ClientMap::iterator FindClientIt(const ReportingEndpointGroupKey& group_key);
238 
239   // Finds iterator to the endpoint group identified by |group_key| (origin and
240   // name), if one exists. Returns |endpoint_groups_.end()| if none is found.
241   EndpointGroupMap::iterator FindEndpointGroupIt(
242       const ReportingEndpointGroupKey& group_key);
243 
244   // Finds iterator to the endpoint for the given |group_key| (origin and group
245   // name) and |url|, if one exists. Returns |endpoints_.end()| if none is
246   // found.
247   EndpointMap::iterator FindEndpointIt(
248       const ReportingEndpointGroupKey& group_key,
249       const GURL& url);
250 
251   // Adds a new client, endpoint group, or endpoint to the cache, if none
252   // exists. If one already exists, updates the existing entry to match the new
253   // one. Returns iterator to newly added client.
254   ClientMap::iterator AddOrUpdateClient(Client new_client);
255   void AddOrUpdateEndpointGroup(CachedReportingEndpointGroup new_group);
256   void AddOrUpdateEndpoint(ReportingEndpoint new_endpoint);
257 
258   // Remove all the endpoints configured for |origin| and |group| whose urls are
259   // not in |endpoints_to_keep_urls|. Does not guarantee that all the endpoints
260   // in |endpoints_to_keep_urls| exist in the cache for that group.
261   void RemoveEndpointsInGroupOtherThan(
262       const ReportingEndpointGroupKey& group_key,
263       const std::set<GURL>& endpoints_to_keep_urls);
264 
265   // Remove all the endpoint groups for the NAK and origin whose names are not
266   // in |groups_to_keep_names|. Does not guarantee that all the groups in
267   // |groups_to_keep_names| exist in the cache for that client.
268   void RemoveEndpointGroupsForClientOtherThan(
269       const NetworkAnonymizationKey& network_anonymization_key,
270       const url::Origin& origin,
271       const std::set<std::string>& groups_to_keep_names);
272 
273   // Gets the endpoints in the given group.
274   std::vector<ReportingEndpoint> GetEndpointsInGroup(
275       const ReportingEndpointGroupKey& group_key) const;
276 
277   // Gets the number of endpoints for the given origin and group.
278   size_t GetEndpointCountInGroup(
279       const ReportingEndpointGroupKey& group_key) const;
280 
281   // Updates the last_used time for the given origin and endpoint group.
282   void MarkEndpointGroupAndClientUsed(ClientMap::iterator client_it,
283                                       EndpointGroupMap::iterator group_it,
284                                       base::Time now);
285 
286   // Removes the endpoint at the given iterator, which must exist in the cache.
287   // Also takes iterators to the client and endpoint group to avoid repeated
288   // lookups. May cause the client and/or group to be removed if they become
289   // empty, which would invalidate those iterators.
290   // Returns the iterator following the endpoint removed, or std::nullopt if
291   // either of |group_it| or |client_it| were invalidated. (If |client_it| is
292   // invalidated, then so must |group_it|).
293   std::optional<EndpointMap::iterator> RemoveEndpointInternal(
294       ClientMap::iterator client_it,
295       EndpointGroupMap::iterator group_it,
296       EndpointMap::iterator endpoint_it);
297 
298   // Removes the endpoint group at the given iterator (which must exist in the
299   // cache). Also takes iterator to the client to avoid repeated lookups. May
300   // cause the client to be removed if it becomes empty, which would
301   // invalidate |client_it|. If |num_endpoints_removed| is not null, then
302   // |*num_endpoints_removed| is incremented by the number of endpoints
303   // removed.
304   // Returns the iterator following the endpoint group removed, or std::nullopt
305   // if |client_it| was invalidated.
306   std::optional<EndpointGroupMap::iterator> RemoveEndpointGroupInternal(
307       ClientMap::iterator client_it,
308       EndpointGroupMap::iterator group_it,
309       size_t* num_endpoints_removed = nullptr);
310 
311   // Removes the client at the given iterator (which must exist in the cache),
312   // along with all of its endpoint groups and endpoints. Invalidates
313   // |client_it|.
314   // Returns the iterator following the client removed.
315   ClientMap::iterator RemoveClientInternal(ClientMap::iterator client_it);
316 
317   // Evict endpoints from the specified client and globally, if necessary to
318   // obey the per-client and global endpoint limits set in the ReportingPolicy.
319   //
320   // To evict from a client: First evicts any stale or expired groups for that
321   // origin. If that removes enough endpoints, then stop. Otherwise, find the
322   // stalest group (which has not been accessed for a delivery in the longest
323   // time) with the most endpoints, and evict the least important endpoints from
324   // that group.
325   // To evict globally: Find the stalest client with the most endpoints and do
326   // the above.
327   void EnforcePerClientAndGlobalEndpointLimits(ClientMap::iterator client_it);
328 
329   // Evicts endpoints from a client until it has evicted |endpoints_to_evict|
330   // endpoints. First tries to remove expired and stale groups. If that fails to
331   // satisfy the limit, finds the stalest group with the most endpoints and
332   // evicts the least important endpoints from it.
333   void EvictEndpointsFromClient(ClientMap::iterator client_it,
334                                 size_t endpoints_to_evict);
335 
336   // Evicts the least important endpoint from a group (the endpoint with lowest
337   // priority and lowest weight). May cause the group and/or client to be
338   // deleted and the iterators invalidated.
339   void EvictEndpointFromGroup(ClientMap::iterator client_it,
340                               EndpointGroupMap::iterator group_it);
341 
342   // Removes all expired or stale groups from the given client. May delete the
343   // client and invalidate |client_it| if it becomes empty.
344   // Increments |*num_endpoints_removed| by the number of endpoints removed.
345   // Returns true if |client_it| was invalidated.
346   bool RemoveExpiredOrStaleGroups(ClientMap::iterator client_it,
347                                   size_t* num_endpoints_removed);
348 
349   // Adds/removes (if it exists) |endpoint_it| from |endpoint_its_by_url_|.
350   void AddEndpointItToIndex(EndpointMap::iterator endpoint_it);
351   void RemoveEndpointItFromIndex(EndpointMap::iterator endpoint_it);
352 
353   // Helper method for IncrementEndpointDeliveries
354   ReportingEndpoint::Statistics* GetEndpointStats(
355       const ReportingEndpointGroupKey& group_key,
356       const GURL& url);
357 
358   // Helper methods for GetClientsAsValue().
359   base::Value GetClientAsValue(const Client& client) const;
360   base::Value GetEndpointGroupAsValue(
361       const CachedReportingEndpointGroup& group) const;
362   base::Value GetEndpointAsValue(const ReportingEndpoint& endpoint) const;
363 
364   // Convenience methods for fetching things from the context_.
clock()365   const base::Clock& clock() const { return context_->clock(); }
tick_clock()366   const base::TickClock& tick_clock() const { return context_->tick_clock(); }
store()367   PersistentReportingStore* store() { return context_->store(); }
368 
369   raw_ptr<ReportingContext> context_;
370 
371   // Reports that have not yet been successfully uploaded.
372   ReportSet reports_;
373 
374   // Reporting API V0 Cache:
375   // The |clients_|, |endpoint_groups_| and |endpoints_| members all hold
376   // endpoint group configuration for the V0 API. These endpoint groups are
377   // configured through the Report-To HTTP header, and are currently used for
378   // both document and network reports.
379 
380   // Map of clients for all configured origins and NAKs, keyed on domain name
381   // (there may be multiple NAKs and origins per domain name).
382   ClientMap clients_;
383 
384   // Map of endpoint groups, keyed on origin and group name. Keys and values
385   // must only contain V0 endpoint group keys.
386   EndpointGroupMap endpoint_groups_;
387 
388   // Map of endpoints, keyed on origin and group name (there may be multiple
389   // endpoints for a given origin and group, with different urls). Keys must
390   // only contain V0 endpoint group keys.
391   EndpointMap endpoints_;
392 
393   // Index of endpoints stored in |endpoints_| keyed on URL, for easier lookup
394   // during RemoveEndpointsForUrl(). Should stay in sync with |endpoints_|.
395   std::multimap<GURL, EndpointMap::iterator> endpoint_its_by_url_;
396 
397   // Reporting API V1 Cache:
398   // The `document_endpoints_` member holds endpoint configuration for the V1
399   // API, configured through the Reporting-Endpoints HTTP header. These
400   // endpoints are strongly associated with the resource which configured them,
401   // and are only used for document reports.
402 
403   // Map of endpoints for each reporting source, keyed on the reporting source
404   // token. This contains only V1 document endpoints.
405   std::map<base::UnguessableToken, std::vector<ReportingEndpoint>>
406       document_endpoints_;
407 
408   // Endpoints set by the enterprise policy.
409   std::vector<ReportingEndpoint> enterprise_endpoints_;
410 
411   // Isolation info for each reporting source. Used for determining credentials
412   // to send when delivering reports. This contains only V1 document endpoints.
413   std::map<base::UnguessableToken, IsolationInfo> isolation_info_;
414 
415   // Reporting source tokens representing sources which have been destroyed.
416   // The configuration in `document_endpoints_` and `isolation_info_` for these
417   // sources can be removed once all outstanding reports are delivered (or
418   // expired).
419   base::flat_set<base::UnguessableToken> expired_sources_;
420 
421   SEQUENCE_CHECKER(sequence_checker_);
422 };
423 
424 }  // namespace net
425 
426 #endif  // NET_REPORTING_REPORTING_CACHE_IMPL_H_
427