juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 1 | // Copyright 2017 The Chromium Authors. All rights reserved. |
| 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 | |
juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 8 | #include <memory> |
Lily Chen | efb6fcf | 2019-04-19 04:17:54 | [diff] [blame] | 9 | #include <string> |
juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 10 | #include <vector> |
| 11 | |
| 12 | #include "base/macros.h" |
| 13 | #include "base/stl_util.h" |
| 14 | #include "base/time/time.h" |
| 15 | #include "base/values.h" |
| 16 | #include "net/base/net_export.h" |
| 17 | #include "net/reporting/reporting_client.h" |
Lily Chen | efb6fcf | 2019-04-19 04:17:54 | [diff] [blame] | 18 | #include "net/reporting/reporting_context.h" |
| 19 | #include "net/reporting/reporting_header_parser.h" |
juliatuttle | 667c0bb | 2017-07-06 15:17:13 | [diff] [blame] | 20 | #include "net/reporting/reporting_report.h" |
juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 21 | #include "url/gurl.h" |
| 22 | #include "url/origin.h" |
| 23 | |
| 24 | namespace net { |
| 25 | |
juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 26 | // The cache holds undelivered reports and clients (per-origin endpoint |
| 27 | // configurations) in memory. (It is not responsible for persisting them.) |
| 28 | // |
Lily Chen | efb6fcf | 2019-04-19 04:17:54 | [diff] [blame] | 29 | // Each Reporting "endpoint" represents a report collector at some specified |
| 30 | // URL. Endpoints are organized into named "endpoint groups", each of which |
| 31 | // additionally specifes some properties such as expiration time. |
| 32 | // A "client" represents the entire endpoint configuration set by an origin via |
| 33 | // a Report-To header, which consists of multiple endpoint groups, each of which |
| 34 | // consists of multiple endpoints. An endpoint group is keyed by its name. An |
| 35 | // endpoint is unkeyed except by the client and group structure tree above it. |
| 36 | // |
| 37 | // The cache implementation corresponds roughly to the "Reporting cache" |
| 38 | // described in the spec, except that endpoints and clients are stored in a more |
| 39 | // structurally-convenient way, and endpoint failures/retry-after are tracked in |
| 40 | // ReportingEndpointManager. |
juliatuttle | 72a9ba6 | 2017-03-28 17:28:52 | [diff] [blame] | 41 | // |
| 42 | // The cache implementation has the notion of "pending" reports. These are |
| 43 | // reports that are part of an active delivery attempt, so they won't be |
| 44 | // actually deallocated. Any attempt to remove a pending report wil mark it |
| 45 | // "doomed", which will cause it to be deallocated once it is no longer pending. |
juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 46 | class NET_EXPORT ReportingCache { |
| 47 | public: |
Lily Chen | c565231 | 2019-03-20 21:58:30 | [diff] [blame] | 48 | class PersistentReportingStore; |
| 49 | |
juliatuttle | 0c436c8c | 2017-06-05 16:57:04 | [diff] [blame] | 50 | static std::unique_ptr<ReportingCache> Create(ReportingContext* context); |
juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 51 | |
juliatuttle | 0c436c8c | 2017-06-05 16:57:04 | [diff] [blame] | 52 | virtual ~ReportingCache(); |
juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 53 | |
| 54 | // Adds a report to the cache. |
| 55 | // |
| 56 | // All parameters correspond to the desired values for the relevant fields in |
| 57 | // ReportingReport. |
juliatuttle | 0c436c8c | 2017-06-05 16:57:04 | [diff] [blame] | 58 | virtual void AddReport(const GURL& url, |
Douglas Creager | f6cb49f7 | 2018-07-19 20:14:53 | [diff] [blame] | 59 | const std::string& user_agent, |
Lily Chen | efb6fcf | 2019-04-19 04:17:54 | [diff] [blame] | 60 | const std::string& group_name, |
juliatuttle | 0c436c8c | 2017-06-05 16:57:04 | [diff] [blame] | 61 | const std::string& type, |
| 62 | std::unique_ptr<const base::Value> body, |
Julia Tuttle | 107e3067 | 2018-03-29 18:48:42 | [diff] [blame] | 63 | int depth, |
juliatuttle | 0c436c8c | 2017-06-05 16:57:04 | [diff] [blame] | 64 | base::TimeTicks queued, |
| 65 | int attempts) = 0; |
juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 66 | |
| 67 | // Gets all reports in the cache. The returned pointers are valid as long as |
| 68 | // either no calls to |RemoveReports| have happened or the reports' |pending| |
| 69 | // flag has been set to true using |SetReportsPending|. Does not return |
| 70 | // doomed reports (pending reports for which removal has been requested). |
| 71 | // |
| 72 | // (Clears any existing data in |*reports_out|.) |
juliatuttle | 0c436c8c | 2017-06-05 16:57:04 | [diff] [blame] | 73 | virtual void GetReports( |
| 74 | std::vector<const ReportingReport*>* reports_out) const = 0; |
juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 75 | |
Douglas Creager | 0b937ec | 2018-04-13 13:53:09 | [diff] [blame] | 76 | // Gets all reports in the cache, including pending and doomed reports, as a |
| 77 | // base::Value. |
| 78 | virtual base::Value GetReportsAsValue() const = 0; |
| 79 | |
Douglas Creager | 66494e1 | 2018-03-05 22:21:00 | [diff] [blame] | 80 | // Gets all reports in the cache that aren't pending. The returned pointers |
| 81 | // are valid as long as either no calls to |RemoveReports| have happened or |
| 82 | // the reports' |pending| flag has been set to true using |SetReportsPending|. |
| 83 | // |
| 84 | // (Clears any existing data in |*reports_out|.) |
| 85 | virtual void GetNonpendingReports( |
| 86 | std::vector<const ReportingReport*>* reports_out) const = 0; |
| 87 | |
juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 88 | // Marks a set of reports as pending. |reports| must not already be marked as |
| 89 | // pending. |
juliatuttle | 0c436c8c | 2017-06-05 16:57:04 | [diff] [blame] | 90 | virtual void SetReportsPending( |
| 91 | const std::vector<const ReportingReport*>& reports) = 0; |
juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 92 | |
| 93 | // Unmarks a set of reports as pending. |reports| must be previously marked as |
| 94 | // pending. |
juliatuttle | 0c436c8c | 2017-06-05 16:57:04 | [diff] [blame] | 95 | virtual void ClearReportsPending( |
| 96 | const std::vector<const ReportingReport*>& reports) = 0; |
juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 97 | |
| 98 | // Increments |attempts| on a set of reports. |
juliatuttle | 0c436c8c | 2017-06-05 16:57:04 | [diff] [blame] | 99 | virtual void IncrementReportsAttempts( |
| 100 | const std::vector<const ReportingReport*>& reports) = 0; |
juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 101 | |
Lily Chen | efb6fcf | 2019-04-19 04:17:54 | [diff] [blame] | 102 | // Records that we attempted (and possibly succeeded at) delivering |
| 103 | // |reports_delivered| reports to the specified endpoint. |
Douglas Creager | e13028c | 2018-07-02 18:08:27 | [diff] [blame] | 104 | virtual void IncrementEndpointDeliveries(const url::Origin& origin, |
Lily Chen | efb6fcf | 2019-04-19 04:17:54 | [diff] [blame] | 105 | const std::string& group_name, |
| 106 | const GURL& url, |
Douglas Creager | e13028c | 2018-07-02 18:08:27 | [diff] [blame] | 107 | int reports_delivered, |
| 108 | bool successful) = 0; |
Douglas Creager | 1f0b502 | 2018-04-10 18:19:13 | [diff] [blame] | 109 | |
juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 110 | // Removes a set of reports. Any reports that are pending will not be removed |
| 111 | // immediately, but rather marked doomed and removed once they are no longer |
| 112 | // pending. |
juliatuttle | 667c0bb | 2017-07-06 15:17:13 | [diff] [blame] | 113 | virtual void RemoveReports(const std::vector<const ReportingReport*>& reports, |
| 114 | ReportingReport::Outcome outcome) = 0; |
juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 115 | |
| 116 | // Removes all reports. Like |RemoveReports()|, pending reports are doomed |
| 117 | // until no longer pending. |
juliatuttle | 667c0bb | 2017-07-06 15:17:13 | [diff] [blame] | 118 | virtual void RemoveAllReports(ReportingReport::Outcome outcome) = 0; |
juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 119 | |
juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 120 | // Gets the count of reports in the cache, *including* doomed reports. |
| 121 | // |
| 122 | // Needed to ensure that doomed reports are eventually deleted, since no |
| 123 | // method provides a view of *every* report in the cache, just non-doomed |
| 124 | // ones. |
juliatuttle | 0c436c8c | 2017-06-05 16:57:04 | [diff] [blame] | 125 | virtual size_t GetFullReportCountForTesting() const = 0; |
juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 126 | |
juliatuttle | 0c436c8c | 2017-06-05 16:57:04 | [diff] [blame] | 127 | virtual bool IsReportPendingForTesting( |
| 128 | const ReportingReport* report) const = 0; |
juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 129 | |
juliatuttle | 0c436c8c | 2017-06-05 16:57:04 | [diff] [blame] | 130 | virtual bool IsReportDoomedForTesting( |
| 131 | const ReportingReport* report) const = 0; |
Lily Chen | efb6fcf | 2019-04-19 04:17:54 | [diff] [blame] | 132 | |
| 133 | // Adds a new client to the cache for |origin|, or updates the existing one |
| 134 | // to match the new header. All values are assumed to be valid as they have |
| 135 | // passed through the ReportingHeaderParser. |
| 136 | virtual void OnParsedHeader( |
| 137 | const url::Origin& origin, |
| 138 | std::vector<ReportingEndpointGroup> parsed_header) = 0; |
| 139 | |
| 140 | // Gets all the origins of clients in the cache. |
| 141 | virtual std::vector<url::Origin> GetAllOrigins() const = 0; |
| 142 | |
| 143 | // Remove client for the given |origin|, if it exists in the cache. |
| 144 | // All endpoint groups and endpoints for |origin| are also removed. |
| 145 | virtual void RemoveClient(const url::Origin& origin) = 0; |
| 146 | |
| 147 | // Remove all clients, groups, and endpoints from the cache. |
| 148 | virtual void RemoveAllClients() = 0; |
| 149 | |
| 150 | // Remove the endpoint group named |name| for the given |origin|, and remove |
| 151 | // all endpoints for that group. May cause the client for |origin| to be |
| 152 | // deleted if it becomes empty. |
| 153 | virtual void RemoveEndpointGroup(const url::Origin& origin, |
| 154 | const std::string& group_name) = 0; |
| 155 | |
| 156 | // Remove all endpoints for with |url|, regardless of origin or group. Used |
| 157 | // when a delivery returns 410 Gone. May cause deletion of groups/clients if |
| 158 | // they become empty. |
| 159 | virtual void RemoveEndpointsForUrl(const GURL& url) = 0; |
| 160 | |
| 161 | // Gets endpoints that apply to a delivery for |origin| and |group|. |
| 162 | // |
| 163 | // First checks for |group| in a client exactly matching |origin|. |
| 164 | // If none exists, then checks for |group| in clients for superdomains |
| 165 | // of |origin| which have include_subdomains enabled, returning only the |
| 166 | // endpoints for the most specific applicable parent origin of |origin|. If |
| 167 | // there are multiple origins with that group within the most specific |
| 168 | // applicable superdomain, gets endpoints for that group from only one of |
| 169 | // them. The group must not be expired. |
| 170 | // |
| 171 | // For example, given the origin https://foo.bar.baz.com/, the cache |
| 172 | // would prioritize returning each potential match below over the ones below |
| 173 | // it, for groups with name |group| with include_subdomains enabled: |
| 174 | // 1. https://foo.bar.baz.com/ (exact origin match) |
| 175 | // 2. https://foo.bar.baz.com:444/ (technically, a superdomain) |
| 176 | // 3. https://bar.baz.com/, https://bar.baz.com:444/, etc. (superdomain) |
| 177 | // 4. https://baz.com/, https://baz.com:444/, etc. (superdomain) |
| 178 | // If both https://bar.baz.com/ and https://bar.baz.com:444/ had a group with |
| 179 | // name |group| with include_subdomains enabled, this method would return |
| 180 | // endpoints from that group from the earliest-inserted origin. |
| 181 | virtual std::vector<ReportingClient> GetCandidateEndpointsForDelivery( |
| 182 | const url::Origin& origin, |
| 183 | const std::string& group_name) = 0; |
| 184 | |
| 185 | // Gets the status of all clients in the cache, including expired ones, as a |
| 186 | // base::Value. |
| 187 | virtual base::Value GetClientsAsValue() const = 0; |
| 188 | |
| 189 | // Gets the total number of endpoints in the cache across all origins. |
| 190 | virtual size_t GetEndpointCount() const = 0; |
| 191 | |
| 192 | // Finds an endpoint for the given |origin|, |group_name|, and |url|, |
| 193 | // otherwise returns an invalid ReportingClient. |
| 194 | virtual ReportingClient GetEndpointForTesting(const url::Origin& origin, |
| 195 | const std::string& group_name, |
| 196 | const GURL& url) const = 0; |
| 197 | |
| 198 | // Returns whether an endpoint group with exactly the given properties exists |
| 199 | // in the cache. If |expires| is base::Time(), it will not be checked. |
| 200 | virtual bool EndpointGroupExistsForTesting( |
| 201 | const url::Origin& origin, |
| 202 | const std::string& group_name, |
| 203 | OriginSubdomains include_subdomains, |
| 204 | base::Time expires) const = 0; |
| 205 | |
| 206 | // Returns number of endpoint groups. |
| 207 | virtual size_t GetEndpointGroupCountForTesting() const = 0; |
| 208 | |
| 209 | // Sets an endpoint with the given properties in a group with the given |
| 210 | // properties, bypassing header parsing. Note that the endpoint is not |
| 211 | // guaranteed to exist in the cache after calling this function, if endpoint |
| 212 | // eviction is triggered. Unlike the AddOrUpdate*() methods used in header |
| 213 | // parsing, this method inserts or updates a single endpoint while leaving the |
| 214 | // exiting configuration for that origin intact. |
| 215 | virtual void SetEndpointForTesting(const url::Origin& origin, |
| 216 | const std::string& group_name, |
| 217 | const GURL& url, |
| 218 | OriginSubdomains include_subdomains, |
| 219 | base::Time expires, |
| 220 | int priority, |
| 221 | int weight) = 0; |
juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 222 | }; |
| 223 | |
Lily Chen | c565231 | 2019-03-20 21:58:30 | [diff] [blame] | 224 | // Persistent storage for Reporting reports and clients. |
| 225 | class NET_EXPORT ReportingCache::PersistentReportingStore { |
| 226 | public: |
| 227 | PersistentReportingStore() = default; |
| 228 | virtual ~PersistentReportingStore() = default; |
| 229 | |
| 230 | // TODO(chlily): methods to load, add, update, delete, etc. will be added. |
| 231 | |
| 232 | // Flushes the store. |
| 233 | virtual void Flush() = 0; |
| 234 | |
| 235 | private: |
| 236 | DISALLOW_COPY_AND_ASSIGN(PersistentReportingStore); |
| 237 | }; |
| 238 | |
juliatuttle | 58684333 | 2017-03-27 16:22:37 | [diff] [blame] | 239 | } // namespace net |
| 240 | |
| 241 | #endif // NET_REPORTING_REPORTING_CACHE_H_ |