123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402 |
- // Copyright 2019 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #ifndef NET_REPORTING_REPORTING_CACHE_IMPL_H_
- #define NET_REPORTING_REPORTING_CACHE_IMPL_H_
- #include <map>
- #include <memory>
- #include <set>
- #include <string>
- #include <unordered_set>
- #include <utility>
- #include <vector>
- #include "base/containers/flat_map.h"
- #include "base/containers/flat_set.h"
- #include "base/containers/unique_ptr_adapters.h"
- #include "base/memory/raw_ptr.h"
- #include "base/sequence_checker.h"
- #include "base/time/time.h"
- #include "base/unguessable_token.h"
- #include "base/values.h"
- #include "net/base/isolation_info.h"
- #include "net/reporting/reporting_cache.h"
- #include "net/reporting/reporting_context.h"
- #include "net/reporting/reporting_endpoint.h"
- #include "net/reporting/reporting_header_parser.h"
- #include "net/reporting/reporting_report.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- #include "url/gurl.h"
- #include "url/origin.h"
- namespace net {
- class ReportingCacheImpl : public ReportingCache {
- public:
- explicit ReportingCacheImpl(ReportingContext* context);
- ReportingCacheImpl(const ReportingCacheImpl&) = delete;
- ReportingCacheImpl& operator=(const ReportingCacheImpl&) = delete;
- ~ReportingCacheImpl() override;
- // ReportingCache implementation
- void AddReport(const absl::optional<base::UnguessableToken>& reporting_source,
- const NetworkIsolationKey& network_isolation_key,
- const GURL& url,
- const std::string& user_agent,
- const std::string& group_name,
- const std::string& type,
- base::Value::Dict body,
- int depth,
- base::TimeTicks queued,
- int attempts) override;
- void GetReports(
- std::vector<const ReportingReport*>* reports_out) const override;
- base::Value GetReportsAsValue() const override;
- std::vector<const ReportingReport*> GetReportsToDeliver() override;
- std::vector<const ReportingReport*> GetReportsToDeliverForSource(
- const base::UnguessableToken& reporting_source) override;
- void ClearReportsPending(
- const std::vector<const ReportingReport*>& reports) override;
- void IncrementReportsAttempts(
- const std::vector<const ReportingReport*>& reports) override;
- base::flat_map<url::Origin, std::vector<ReportingEndpoint>>
- GetV1ReportingEndpointsByOrigin() const override;
- void IncrementEndpointDeliveries(const ReportingEndpointGroupKey& group_key,
- const GURL& url,
- int reports_delivered,
- bool successful) override;
- void SetExpiredSource(
- const base::UnguessableToken& reporting_source) override;
- const base::flat_set<base::UnguessableToken>& GetExpiredSources()
- const override;
- void RemoveReports(
- const std::vector<const ReportingReport*>& reports) override;
- void RemoveReports(const std::vector<const ReportingReport*>& reports,
- bool delivery_success) override;
- void RemoveAllReports() override;
- size_t GetFullReportCountForTesting() const override;
- size_t GetReportCountWithStatusForTesting(
- ReportingReport::Status status) const override;
- bool IsReportPendingForTesting(const ReportingReport* report) const override;
- bool IsReportDoomedForTesting(const ReportingReport* report) const override;
- void OnParsedHeader(
- const NetworkIsolationKey& network_isolation_key,
- const url::Origin& origin,
- std::vector<ReportingEndpointGroup> parsed_header) override;
- void OnParsedReportingEndpointsHeader(
- const base::UnguessableToken& reporting_source,
- const IsolationInfo& isolation_info,
- std::vector<ReportingEndpoint> parsed_header) override;
- std::set<url::Origin> GetAllOrigins() const override;
- void RemoveClient(const NetworkIsolationKey& network_isolation_key,
- const url::Origin& origin) override;
- void RemoveClientsForOrigin(const url::Origin& origin) override;
- void RemoveAllClients() override;
- void RemoveEndpointGroup(const ReportingEndpointGroupKey& group_key) override;
- void RemoveEndpointsForUrl(const GURL& url) override;
- void RemoveSourceAndEndpoints(
- const base::UnguessableToken& reporting_source) override;
- void AddClientsLoadedFromStore(
- std::vector<ReportingEndpoint> loaded_endpoints,
- std::vector<CachedReportingEndpointGroup> loaded_endpoint_groups)
- override;
- std::vector<ReportingEndpoint> GetCandidateEndpointsForDelivery(
- const ReportingEndpointGroupKey& group_key) override;
- base::Value GetClientsAsValue() const override;
- size_t GetEndpointCount() const override;
- void Flush() override;
- ReportingEndpoint GetV1EndpointForTesting(
- const base::UnguessableToken& reporting_source,
- const std::string& endpoint_name) const override;
- ReportingEndpoint GetEndpointForTesting(
- const ReportingEndpointGroupKey& group_key,
- const GURL& url) const override;
- bool EndpointGroupExistsForTesting(const ReportingEndpointGroupKey& group_key,
- OriginSubdomains include_subdomains,
- base::Time expires) const override;
- bool ClientExistsForTesting(const NetworkIsolationKey& network_isolation_key,
- const url::Origin& origin) const override;
- size_t GetEndpointGroupCountForTesting() const override;
- size_t GetClientCountForTesting() const override;
- size_t GetReportingSourceCountForTesting() const override;
- void SetEndpointForTesting(const ReportingEndpointGroupKey& group_key,
- const GURL& url,
- OriginSubdomains include_subdomains,
- base::Time expires,
- int priority,
- int weight) override;
- void SetV1EndpointForTesting(const ReportingEndpointGroupKey& group_key,
- const base::UnguessableToken& reporting_source,
- const IsolationInfo& isolation_info,
- const GURL& url) override;
- IsolationInfo GetIsolationInfoForEndpoint(
- const ReportingEndpoint& endpoint) const override;
- private:
- // Represents the entire Report-To configuration for a (NIK, origin) pair.
- struct Client {
- Client(const NetworkIsolationKey& network_isolation_key,
- const url::Origin& origin);
- Client(const Client& other);
- Client(Client&& other);
- Client& operator=(const Client& other);
- Client& operator=(Client&& other);
- ~Client();
- // NIK of the context associated with this client. Needed to prevent leaking
- // third party contexts across sites.
- NetworkIsolationKey network_isolation_key;
- // Origin that configured this client.
- url::Origin origin;
- // Total number of endpoints for this origin. Should stay in sync with the
- // sum of endpoint counts for all the groups within this client.
- size_t endpoint_count = 0;
- // Last time that any of the groups for this origin was accessed for a
- // delivery or updated via a new header. Should stay in sync with the latest
- // |last_used| of all the groups within this client.
- base::Time last_used;
- // Set of endpoint group names for this origin.
- std::set<std::string> endpoint_group_names;
- };
- using ReportSet = base::flat_set<std::unique_ptr<ReportingReport>,
- base::UniquePtrComparator>;
- using ClientMap = std::multimap<std::string, Client>;
- using EndpointGroupMap =
- std::map<ReportingEndpointGroupKey, CachedReportingEndpointGroup>;
- using EndpointMap =
- std::multimap<ReportingEndpointGroupKey, ReportingEndpoint>;
- ReportSet::const_iterator FindReportToEvict() const;
- // Consistency-checks the entire data structure of clients, groups, and
- // endpoints, if DCHECK is on. The cached clients should pass this consistency
- // check after completely parsing a header (i.e. not after the intermediate
- // steps), and before and after any of the public methods that remove or
- // retrieve client info. Also calls |sequence_checker_| to DCHECK that we are
- // being called on a valid sequence.
- void ConsistencyCheckClients() const;
- // Helper methods for ConsistencyCheckClients():
- #if DCHECK_IS_ON()
- // Returns number of endpoint groups found in |client|.
- size_t ConsistencyCheckClient(const std::string& domain,
- const Client& client) const;
- // Returns the number of endpoints found in |group|.
- size_t ConsistencyCheckEndpointGroup(
- const ReportingEndpointGroupKey& key,
- const CachedReportingEndpointGroup& group) const;
- void ConsistencyCheckEndpoint(const ReportingEndpointGroupKey& key,
- const ReportingEndpoint& endpoint,
- EndpointMap::const_iterator endpoint_it) const;
- #endif // DCHECK_IS_ON()
- // Finds iterator to the client with the given |network_isolation_key| and
- // |origin|, if one exists. Returns |clients_.end()| if none is found.
- ClientMap::iterator FindClientIt(
- const NetworkIsolationKey& network_isolation_key,
- const url::Origin& origin);
- // Overload that takes a ReportingEndpointGroupKey and finds the client
- // to which a group specified by the |group_key| would belong. The group name
- // of the key is ignored.
- ClientMap::iterator FindClientIt(const ReportingEndpointGroupKey& group_key);
- // Finds iterator to the endpoint group identified by |group_key| (origin and
- // name), if one exists. Returns |endpoint_groups_.end()| if none is found.
- EndpointGroupMap::iterator FindEndpointGroupIt(
- const ReportingEndpointGroupKey& group_key);
- // Finds iterator to the endpoint for the given |group_key| (origin and group
- // name) and |url|, if one exists. Returns |endpoints_.end()| if none is
- // found.
- EndpointMap::iterator FindEndpointIt(
- const ReportingEndpointGroupKey& group_key,
- const GURL& url);
- // Adds a new client, endpoint group, or endpoint to the cache, if none
- // exists. If one already exists, updates the existing entry to match the new
- // one. Returns iterator to newly added client.
- ClientMap::iterator AddOrUpdateClient(Client new_client);
- void AddOrUpdateEndpointGroup(CachedReportingEndpointGroup new_group);
- void AddOrUpdateEndpoint(ReportingEndpoint new_endpoint);
- // Remove all the endpoints configured for |origin| and |group| whose urls are
- // not in |endpoints_to_keep_urls|. Does not guarantee that all the endpoints
- // in |endpoints_to_keep_urls| exist in the cache for that group.
- void RemoveEndpointsInGroupOtherThan(
- const ReportingEndpointGroupKey& group_key,
- const std::set<GURL>& endpoints_to_keep_urls);
- // Remove all the endpoint groups for the NIK and origin whose names are not
- // in |groups_to_keep_names|. Does not guarantee that all the groups in
- // |groups_to_keep_names| exist in the cache for that client.
- void RemoveEndpointGroupsForClientOtherThan(
- const NetworkIsolationKey& network_isolation_key,
- const url::Origin& origin,
- const std::set<std::string>& groups_to_keep_names);
- // Gets the endpoints in the given group.
- std::vector<ReportingEndpoint> GetEndpointsInGroup(
- const ReportingEndpointGroupKey& group_key) const;
- // Gets the number of endpoints for the given origin and group.
- size_t GetEndpointCountInGroup(
- const ReportingEndpointGroupKey& group_key) const;
- // Updates the last_used time for the given origin and endpoint group.
- void MarkEndpointGroupAndClientUsed(ClientMap::iterator client_it,
- EndpointGroupMap::iterator group_it,
- base::Time now);
- // Removes the endpoint at the given iterator, which must exist in the cache.
- // Also takes iterators to the client and endpoint group to avoid repeated
- // lookups. May cause the client and/or group to be removed if they become
- // empty, which would invalidate those iterators.
- // Returns the iterator following the endpoint removed, or absl::nullopt if
- // either of |group_it| or |client_it| were invalidated. (If |client_it| is
- // invalidated, then so must |group_it|).
- absl::optional<EndpointMap::iterator> RemoveEndpointInternal(
- ClientMap::iterator client_it,
- EndpointGroupMap::iterator group_it,
- EndpointMap::iterator endpoint_it);
- // Removes the endpoint group at the given iterator (which must exist in the
- // cache). Also takes iterator to the client to avoid repeated lookups. May
- // cause the client to be removed if it becomes empty, which would
- // invalidate |client_it|. If |num_endpoints_removed| is not null, then
- // |*num_endpoints_removed| is incremented by the number of endpoints
- // removed.
- // Returns the iterator following the endpoint group removed, or absl::nullopt
- // if |client_it| was invalidated.
- absl::optional<EndpointGroupMap::iterator> RemoveEndpointGroupInternal(
- ClientMap::iterator client_it,
- EndpointGroupMap::iterator group_it,
- size_t* num_endpoints_removed = nullptr);
- // Removes the client at the given iterator (which must exist in the cache),
- // along with all of its endpoint groups and endpoints. Invalidates
- // |client_it|.
- // Returns the iterator following the client removed.
- ClientMap::iterator RemoveClientInternal(ClientMap::iterator client_it);
- // Evict endpoints from the specified client and globally, if necessary to
- // obey the per-client and global endpoint limits set in the ReportingPolicy.
- //
- // To evict from a client: First evicts any stale or expired groups for that
- // origin. If that removes enough endpoints, then stop. Otherwise, find the
- // stalest group (which has not been accessed for a delivery in the longest
- // time) with the most endpoints, and evict the least important endpoints from
- // that group.
- // To evict globally: Find the stalest client with the most endpoints and do
- // the above.
- void EnforcePerClientAndGlobalEndpointLimits(ClientMap::iterator client_it);
- // Evicts endpoints from a client until it has evicted |endpoints_to_evict|
- // endpoints. First tries to remove expired and stale groups. If that fails to
- // satisfy the limit, finds the stalest group with the most endpoints and
- // evicts the least important endpoints from it.
- void EvictEndpointsFromClient(ClientMap::iterator client_it,
- size_t endpoints_to_evict);
- // Evicts the least important endpoint from a group (the endpoint with lowest
- // priority and lowest weight). May cause the group and/or client to be
- // deleted and the iterators invalidated.
- void EvictEndpointFromGroup(ClientMap::iterator client_it,
- EndpointGroupMap::iterator group_it);
- // Removes all expired or stale groups from the given client. May delete the
- // client and invalidate |client_it| if it becomes empty.
- // Increments |*num_endpoints_removed| by the number of endpoints removed.
- // Returns true if |client_it| was invalidated.
- bool RemoveExpiredOrStaleGroups(ClientMap::iterator client_it,
- size_t* num_endpoints_removed);
- // Adds/removes (if it exists) |endpoint_it| from |endpoint_its_by_url_|.
- void AddEndpointItToIndex(EndpointMap::iterator endpoint_it);
- void RemoveEndpointItFromIndex(EndpointMap::iterator endpoint_it);
- // Helper method for IncrementEndpointDeliveries
- ReportingEndpoint::Statistics* GetEndpointStats(
- const ReportingEndpointGroupKey& group_key,
- const GURL& url);
- // Helper methods for GetClientsAsValue().
- base::Value GetClientAsValue(const Client& client) const;
- base::Value GetEndpointGroupAsValue(
- const CachedReportingEndpointGroup& group) const;
- base::Value GetEndpointAsValue(const ReportingEndpoint& endpoint) const;
- // Convenience methods for fetching things from the context_.
- const base::Clock& clock() const { return context_->clock(); }
- const base::TickClock& tick_clock() const { return context_->tick_clock(); }
- PersistentReportingStore* store() { return context_->store(); }
- raw_ptr<ReportingContext> context_;
- // Reports that have not yet been successfully uploaded.
- ReportSet reports_;
- // Reporting API V0 Cache:
- // The |clients_|, |endpoint_groups_| and |endpoints_| members all hold
- // endpoint group configuration for the V0 API. These endpoint groups are
- // configured through the Report-To HTTP header, and are currently used for
- // both document and network reports.
- // Map of clients for all configured origins and NIKs, keyed on domain name
- // (there may be multiple NIKs and origins per domain name).
- ClientMap clients_;
- // Map of endpoint groups, keyed on origin and group name. Keys and values
- // must only contain V0 endpoint group keys.
- EndpointGroupMap endpoint_groups_;
- // Map of endpoints, keyed on origin and group name (there may be multiple
- // endpoints for a given origin and group, with different urls). Keys must
- // only contain V0 endpoint group keys.
- EndpointMap endpoints_;
- // Index of endpoints stored in |endpoints_| keyed on URL, for easier lookup
- // during RemoveEndpointsForUrl(). Should stay in sync with |endpoints_|.
- std::multimap<GURL, EndpointMap::iterator> endpoint_its_by_url_;
- // Reporting API V1 Cache:
- // The `document_endpoints_` member holds endpoint configuration for the V1
- // API, configured through the Reporting-Endpoints HTTP header. These
- // endpoints are strongly associated with the resource which configured them,
- // and are only used for document reports.
- // Map of endpoints for each reporting source, keyed on the reporting source
- // token. This contains only V1 document endpoints.
- std::map<base::UnguessableToken, std::vector<ReportingEndpoint>>
- document_endpoints_;
- // Isolation info for each reporting source. Used for determining credentials
- // to send when delivering reports. This contains only V1 document endpoints.
- std::map<base::UnguessableToken, IsolationInfo> isolation_info_;
- // Reporting source tokens representing sources which have been destroyed.
- // The configuration in `document_endpoints_` and `isolation_info_` for these
- // sources can be removed once all outstanding reports are delivered (or
- // expired).
- base::flat_set<base::UnguessableToken> expired_sources_;
- SEQUENCE_CHECKER(sequence_checker_);
- };
- } // namespace net
- #endif // NET_REPORTING_REPORTING_CACHE_IMPL_H_
|