1 // Copyright 2019 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_IMPL_H_ 6 #define NET_REPORTING_REPORTING_CACHE_IMPL_H_ 7 8 #include <map> 9 #include <memory> 10 #include <set> 11 #include <string> 12 #include <unordered_map> 13 #include <unordered_set> 14 #include <utility> 15 #include <vector> 16 17 #include "base/containers/flat_set.h" 18 #include "base/containers/unique_ptr_adapters.h" 19 #include "base/macros.h" 20 #include "base/optional.h" 21 #include "base/sequence_checker.h" 22 #include "base/time/time.h" 23 #include "base/values.h" 24 #include "net/reporting/reporting_cache.h" 25 #include "net/reporting/reporting_context.h" 26 #include "net/reporting/reporting_endpoint.h" 27 #include "net/reporting/reporting_header_parser.h" 28 #include "net/reporting/reporting_report.h" 29 #include "url/gurl.h" 30 #include "url/origin.h" 31 32 namespace net { 33 34 class ReportingCacheImpl : public ReportingCache { 35 public: 36 ReportingCacheImpl(ReportingContext* context); 37 38 ~ReportingCacheImpl() override; 39 40 // ReportingCache implementation 41 void AddReport(const GURL& url, 42 const std::string& user_agent, 43 const std::string& group_name, 44 const std::string& type, 45 std::unique_ptr<const base::Value> body, 46 int depth, 47 base::TimeTicks queued, 48 int attempts) override; 49 void GetReports( 50 std::vector<const ReportingReport*>* reports_out) const override; 51 base::Value GetReportsAsValue() const override; 52 std::vector<const ReportingReport*> GetReportsToDeliver() override; 53 void ClearReportsPending( 54 const std::vector<const ReportingReport*>& reports) override; 55 void IncrementReportsAttempts( 56 const std::vector<const ReportingReport*>& reports) override; 57 void IncrementEndpointDeliveries(const ReportingEndpointGroupKey& group_key, 58 const GURL& url, 59 int reports_delivered, 60 bool successful) override; 61 void RemoveReports(const std::vector<const ReportingReport*>& reports, 62 ReportingReport::Outcome outcome) override; 63 void RemoveAllReports(ReportingReport::Outcome outcome) override; 64 size_t GetFullReportCountForTesting() const override; 65 bool IsReportPendingForTesting(const ReportingReport* report) const override; 66 bool IsReportDoomedForTesting(const ReportingReport* report) const override; 67 void OnParsedHeader( 68 const url::Origin& origin, 69 std::vector<ReportingEndpointGroup> parsed_header) override; 70 std::set<url::Origin> GetAllOrigins() const override; 71 void RemoveClient(const NetworkIsolationKey& network_isolation_key, 72 const url::Origin& origin) override; 73 void RemoveClientsForOrigin(const url::Origin& origin) override; 74 void RemoveAllClients() override; 75 void RemoveEndpointGroup(const ReportingEndpointGroupKey& group_key) override; 76 void RemoveEndpointsForUrl(const GURL& url) override; 77 void AddClientsLoadedFromStore( 78 std::vector<ReportingEndpoint> loaded_endpoints, 79 std::vector<CachedReportingEndpointGroup> loaded_endpoint_groups) 80 override; 81 std::vector<ReportingEndpoint> GetCandidateEndpointsForDelivery( 82 const ReportingEndpointGroupKey& group_key) override; 83 base::Value GetClientsAsValue() const override; 84 size_t GetEndpointCount() const override; 85 void Flush() override; 86 ReportingEndpoint GetEndpointForTesting( 87 const ReportingEndpointGroupKey& group_key, 88 const GURL& url) const override; 89 bool EndpointGroupExistsForTesting(const ReportingEndpointGroupKey& group_key, 90 OriginSubdomains include_subdomains, 91 base::Time expires) const override; 92 bool ClientExistsForTesting(const NetworkIsolationKey& network_isolation_key, 93 const url::Origin& origin) const override; 94 size_t GetEndpointGroupCountForTesting() const override; 95 size_t GetClientCountForTesting() const override; 96 void SetEndpointForTesting(const ReportingEndpointGroupKey& group_key, 97 const GURL& url, 98 OriginSubdomains include_subdomains, 99 base::Time expires, 100 int priority, 101 int weight) override; 102 103 private: 104 // Represents the entire Report-To configuration for a (NIK, origin) pair. 105 struct Client { 106 Client(const NetworkIsolationKey& network_isolation_key, 107 const url::Origin& origin); 108 109 Client(const Client& other); 110 Client(Client&& other); 111 112 Client& operator=(const Client& other); 113 Client& operator=(Client&& other); 114 115 ~Client(); 116 117 // NIK of the context associated with this client. Needed to prevent leaking 118 // third party contexts across sites. 119 NetworkIsolationKey network_isolation_key; 120 121 // Origin that configured this client. 122 url::Origin origin; 123 124 // Total number of endpoints for this origin. Should stay in sync with the 125 // sum of endpoint counts for all the groups within this client. 126 size_t endpoint_count = 0; 127 128 // Last time that any of the groups for this origin was accessed for a 129 // delivery or updated via a new header. Should stay in sync with the latest 130 // |last_used| of all the groups within this client. 131 base::Time last_used; 132 133 // Set of endpoint group names for this origin. 134 std::set<std::string> endpoint_group_names; 135 }; 136 137 using ReportSet = base::flat_set<std::unique_ptr<ReportingReport>, 138 base::UniquePtrComparator>; 139 using ClientMap = std::multimap<std::string, Client>; 140 using EndpointGroupMap = 141 std::map<ReportingEndpointGroupKey, CachedReportingEndpointGroup>; 142 using EndpointMap = 143 std::multimap<ReportingEndpointGroupKey, ReportingEndpoint>; 144 145 ReportSet::const_iterator FindReportToEvict() const; 146 147 // Sanity-checks the entire data structure of clients, groups, and endpoints, 148 // if DCHECK is on. The cached clients should pass this sanity check after 149 // completely parsing a header (i.e. not after the intermediate steps), and 150 // before and after any of the public methods that remove or retrieve client 151 // info. Also calls |sequence_checker_| to DCHECK that we are being called on 152 // a valid sequence. 153 void SanityCheckClients() const; 154 155 // Helper methods for SanityCheckClients(): 156 #if DCHECK_IS_ON() 157 // Returns number of endpoint groups found in |client|. 158 size_t SanityCheckClient(const std::string& domain, 159 const Client& client) const; 160 161 // Returns the number of endpoints found in |group|. 162 size_t SanityCheckEndpointGroup( 163 const ReportingEndpointGroupKey& key, 164 const CachedReportingEndpointGroup& group) const; 165 166 void SanityCheckEndpoint(const ReportingEndpointGroupKey& key, 167 const ReportingEndpoint& endpoint, 168 EndpointMap::const_iterator endpoint_it) const; 169 #endif // DCHECK_IS_ON() 170 171 // Finds iterator to the client with the given |network_isolation_key| and 172 // |origin|, if one exists. Returns |clients_.end()| if none is found. 173 ClientMap::iterator FindClientIt( 174 const NetworkIsolationKey& network_isolation_key, 175 const url::Origin& origin); 176 177 // Overload that takes a ReportingEndpointGroupKey and finds the client 178 // to which a group specified by the |group_key| would belong. The group name 179 // of the key is ignored. 180 ClientMap::iterator FindClientIt(const ReportingEndpointGroupKey& group_key); 181 182 // Finds iterator to the endpoint group identified by |group_key| (origin and 183 // name), if one exists. Returns |endpoint_groups_.end()| if none is found. 184 EndpointGroupMap::iterator FindEndpointGroupIt( 185 const ReportingEndpointGroupKey& group_key); 186 187 // Finds iterator to the endpoint for the given |group_key| (origin and group 188 // name) and |url|, if one exists. Returns |endpoints_.end()| if none is 189 // found. 190 EndpointMap::iterator FindEndpointIt( 191 const ReportingEndpointGroupKey& group_key, 192 const GURL& url); 193 194 // Adds a new client, endpoint group, or endpoint to the cache, if none 195 // exists. If one already exists, updates the existing entry to match the new 196 // one. Returns iterator to newly added client. 197 ClientMap::iterator AddOrUpdateClient(Client new_client); 198 void AddOrUpdateEndpointGroup(CachedReportingEndpointGroup new_group); 199 void AddOrUpdateEndpoint(ReportingEndpoint new_endpoint); 200 201 // Remove all the endpoints configured for |origin| and |group| whose urls are 202 // not in |endpoints_to_keep_urls|. Does not guarantee that all the endpoints 203 // in |endpoints_to_keep_urls| exist in the cache for that group. 204 void RemoveEndpointsInGroupOtherThan( 205 const ReportingEndpointGroupKey& group_key, 206 const std::set<GURL>& endpoints_to_keep_urls); 207 208 // Remove all the endpoint groups for the NIK and origin whose names are not 209 // in |groups_to_keep_names|. Does not guarantee that all the groups in 210 // |groups_to_keep_names| exist in the cache for that client. 211 void RemoveEndpointGroupsForClientOtherThan( 212 const NetworkIsolationKey& network_isolation_key, 213 const url::Origin& origin, 214 const std::set<std::string>& groups_to_keep_names); 215 216 // Gets the endpoints in the given group. 217 std::vector<ReportingEndpoint> GetEndpointsInGroup( 218 const ReportingEndpointGroupKey& group_key) const; 219 220 // Gets the number of endpoints for the given origin and group. 221 size_t GetEndpointCountInGroup( 222 const ReportingEndpointGroupKey& group_key) const; 223 224 // Updates the last_used time for the given origin and endpoint group. 225 void MarkEndpointGroupAndClientUsed(ClientMap::iterator client_it, 226 EndpointGroupMap::iterator group_it, 227 base::Time now); 228 229 // Removes the endpoint at the given iterator, which must exist in the cache. 230 // Also takes iterators to the client and endpoint group to avoid repeated 231 // lookups. May cause the client and/or group to be removed if they become 232 // empty, which would invalidate those iterators. 233 // Returns the iterator following the endpoint removed, or base::nullopt if 234 // either of |group_it| or |client_it| were invalidated. (If |client_it| is 235 // invalidated, then so must |group_it|). 236 base::Optional<EndpointMap::iterator> RemoveEndpointInternal( 237 ClientMap::iterator client_it, 238 EndpointGroupMap::iterator group_it, 239 EndpointMap::iterator endpoint_it); 240 241 // Removes the endpoint group at the given iterator (which must exist in the 242 // cache). Also takes iterator to the client to avoid repeated lookups. May 243 // cause the client to be removed if it becomes empty, which would 244 // invalidate |client_it|. If |num_endpoints_removed| is not null, then 245 // |*num_endpoints_removed| is incremented by the number of endpoints 246 // removed. 247 // Returns the iterator following the endpoint group removed, or base::nullopt 248 // if |client_it| was invalidated. 249 base::Optional<EndpointGroupMap::iterator> RemoveEndpointGroupInternal( 250 ClientMap::iterator client_it, 251 EndpointGroupMap::iterator group_it, 252 size_t* num_endpoints_removed = nullptr); 253 254 // Removes the client at the given iterator (which must exist in the cache), 255 // along with all of its endpoint groups and endpoints. Invalidates 256 // |client_it|. 257 // Returns the iterator following the client removed. 258 ClientMap::iterator RemoveClientInternal(ClientMap::iterator client_it); 259 260 // Evict endpoints from the specified client and globally, if necessary to 261 // obey the per-client and global endpoint limits set in the ReportingPolicy. 262 // 263 // To evict from a client: First evicts any stale or expired groups for that 264 // origin. If that removes enough endpoints, then stop. Otherwise, find the 265 // stalest group (which has not been accessed for a delivery in the longest 266 // time) with the most endpoints, and evict the least important endpoints from 267 // that group. 268 // To evict globally: Find the stalest client with the most endpoints and do 269 // the above. 270 void EnforcePerClientAndGlobalEndpointLimits(ClientMap::iterator client_it); 271 272 // Evicts endpoints from a client until it has evicted |endpoints_to_evict| 273 // endpoints. First tries to remove expired and stale groups. If that fails to 274 // satisfy the limit, finds the stalest group with the most endpoints and 275 // evicts the least important endpoints from it. 276 void EvictEndpointsFromClient(ClientMap::iterator client_it, 277 size_t endpoints_to_evict); 278 279 // Evicts the least important endpoint from a group (the endpoint with lowest 280 // priority and lowest weight). May cause the group and/or client to be 281 // deleted and the iterators invalidated. 282 void EvictEndpointFromGroup(ClientMap::iterator client_it, 283 EndpointGroupMap::iterator group_it); 284 285 // Removes all expired or stale groups from the given client. May delete the 286 // client and invalidate |client_it| if it becomes empty. 287 // Increments |*num_endpoints_removed| by the number of endpoints removed. 288 // Returns true if |client_it| was invalidated. 289 bool RemoveExpiredOrStaleGroups(ClientMap::iterator client_it, 290 size_t* num_endpoints_removed); 291 292 // Adds/removes (if it exists) |endpoint_it| from |endpoint_its_by_url_|. 293 void AddEndpointItToIndex(EndpointMap::iterator endpoint_it); 294 void RemoveEndpointItFromIndex(EndpointMap::iterator endpoint_it); 295 296 // Helper methods for GetClientsAsValue(). 297 base::Value GetClientAsValue(const Client& client) const; 298 base::Value GetEndpointGroupAsValue( 299 const CachedReportingEndpointGroup& group) const; 300 base::Value GetEndpointAsValue(const ReportingEndpoint& endpoint) const; 301 302 // Convenience methods for fetching things from the context_. clock()303 const base::Clock& clock() const { return context_->clock(); } tick_clock()304 const base::TickClock& tick_clock() const { return context_->tick_clock(); } store()305 PersistentReportingStore* store() { return context_->store(); } 306 307 ReportingContext* context_; 308 309 // Reports that have not yet been successfully uploaded. 310 ReportSet reports_; 311 312 // Map of clients for all configured origins and NIKs, keyed on domain name 313 // (there may be multiple NIKs and origins per domain name). 314 ClientMap clients_; 315 316 // Map of endpoint groups, keyed on origin and group name. 317 EndpointGroupMap endpoint_groups_; 318 319 // Map of endpoints, keyed on origin and group name (there may be multiple 320 // endpoints for a given origin and group, with different urls). 321 EndpointMap endpoints_; 322 323 // Index of endpoints stored in |endpoints_| keyed on URL, for easier lookup 324 // during RemoveEndpointsForUrl(). Should stay in sync with |endpoints_|. 325 std::multimap<GURL, EndpointMap::iterator> endpoint_its_by_url_; 326 327 SEQUENCE_CHECKER(sequence_checker_); 328 329 DISALLOW_COPY_AND_ASSIGN(ReportingCacheImpl); 330 }; 331 332 } // namespace net 333 334 #endif // NET_REPORTING_REPORTING_CACHE_IMPL_H_ 335