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