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