reporting_endpoint_manager.cc 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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. #include "net/reporting/reporting_endpoint_manager.h"
  5. #include <map>
  6. #include <set>
  7. #include <string>
  8. #include <utility>
  9. #include <vector>
  10. #include "base/check.h"
  11. #include "base/containers/lru_cache.h"
  12. #include "base/memory/raw_ptr.h"
  13. #include "base/notreached.h"
  14. #include "base/rand_util.h"
  15. #include "base/time/tick_clock.h"
  16. #include "net/base/backoff_entry.h"
  17. #include "net/base/network_isolation_key.h"
  18. #include "net/base/rand_callback.h"
  19. #include "net/reporting/reporting_cache.h"
  20. #include "net/reporting/reporting_delegate.h"
  21. #include "net/reporting/reporting_endpoint.h"
  22. #include "net/reporting/reporting_policy.h"
  23. #include "url/gurl.h"
  24. #include "url/origin.h"
  25. namespace net {
  26. namespace {
  27. class ReportingEndpointManagerImpl : public ReportingEndpointManager {
  28. public:
  29. ReportingEndpointManagerImpl(const ReportingPolicy* policy,
  30. const base::TickClock* tick_clock,
  31. const ReportingDelegate* delegate,
  32. ReportingCache* cache,
  33. const RandIntCallback& rand_callback)
  34. : policy_(policy),
  35. tick_clock_(tick_clock),
  36. delegate_(delegate),
  37. cache_(cache),
  38. rand_callback_(rand_callback),
  39. endpoint_backoff_(kMaxEndpointBackoffCacheSize) {
  40. DCHECK(policy);
  41. DCHECK(tick_clock);
  42. DCHECK(delegate);
  43. DCHECK(cache);
  44. }
  45. ReportingEndpointManagerImpl(const ReportingEndpointManagerImpl&) = delete;
  46. ReportingEndpointManagerImpl& operator=(const ReportingEndpointManagerImpl&) =
  47. delete;
  48. ~ReportingEndpointManagerImpl() override = default;
  49. const ReportingEndpoint FindEndpointForDelivery(
  50. const ReportingEndpointGroupKey& group_key) override {
  51. // Get unexpired endpoints that apply to a delivery to |origin| and |group|.
  52. // May have been configured by a superdomain of |origin|.
  53. std::vector<ReportingEndpoint> endpoints =
  54. cache_->GetCandidateEndpointsForDelivery(group_key);
  55. // Highest-priority endpoint(s) that are not expired, failing, or
  56. // forbidden for use by the ReportingDelegate.
  57. std::vector<ReportingEndpoint> available_endpoints;
  58. // Total weight of endpoints in |available_endpoints|.
  59. int total_weight = 0;
  60. for (const ReportingEndpoint& endpoint : endpoints) {
  61. if (!delegate_->CanUseClient(endpoint.group_key.origin,
  62. endpoint.info.url)) {
  63. continue;
  64. }
  65. // If this client is lower priority than the ones we've found, skip it.
  66. if (!available_endpoints.empty() &&
  67. endpoint.info.priority > available_endpoints[0].info.priority) {
  68. continue;
  69. }
  70. // This brings each match to the front of the MRU cache, so if an entry
  71. // frequently matches requests, it's more likely to stay in the cache.
  72. auto endpoint_backoff_it = endpoint_backoff_.Get(EndpointBackoffKey(
  73. group_key.network_isolation_key, endpoint.info.url));
  74. if (endpoint_backoff_it != endpoint_backoff_.end() &&
  75. endpoint_backoff_it->second->ShouldRejectRequest()) {
  76. continue;
  77. }
  78. // If this client is higher priority than the ones we've found (or we
  79. // haven't found any), forget about those ones and remember this one.
  80. if (available_endpoints.empty() ||
  81. endpoint.info.priority < available_endpoints[0].info.priority) {
  82. available_endpoints.clear();
  83. total_weight = 0;
  84. }
  85. available_endpoints.push_back(endpoint);
  86. total_weight += endpoint.info.weight;
  87. }
  88. if (available_endpoints.empty()) {
  89. return ReportingEndpoint();
  90. }
  91. if (total_weight == 0) {
  92. int random_index = rand_callback_.Run(0, available_endpoints.size() - 1);
  93. return available_endpoints[random_index];
  94. }
  95. int random_index = rand_callback_.Run(0, total_weight - 1);
  96. int weight_so_far = 0;
  97. for (const auto& endpoint : available_endpoints) {
  98. weight_so_far += endpoint.info.weight;
  99. if (random_index < weight_so_far) {
  100. return endpoint;
  101. }
  102. }
  103. // TODO(juliatuttle): Can we reach this in some weird overflow case?
  104. NOTREACHED();
  105. return ReportingEndpoint();
  106. }
  107. void InformOfEndpointRequest(const NetworkIsolationKey& network_isolation_key,
  108. const GURL& endpoint,
  109. bool succeeded) override {
  110. EndpointBackoffKey endpoint_backoff_key(network_isolation_key, endpoint);
  111. // This will bring the entry to the front of the cache, if it exists.
  112. auto endpoint_backoff_it = endpoint_backoff_.Get(endpoint_backoff_key);
  113. if (endpoint_backoff_it == endpoint_backoff_.end()) {
  114. endpoint_backoff_it = endpoint_backoff_.Put(
  115. std::move(endpoint_backoff_key),
  116. std::make_unique<BackoffEntry>(&policy_->endpoint_backoff_policy,
  117. tick_clock_));
  118. }
  119. endpoint_backoff_it->second->InformOfRequest(succeeded);
  120. }
  121. private:
  122. using EndpointBackoffKey = std::pair<NetworkIsolationKey, GURL>;
  123. const raw_ptr<const ReportingPolicy> policy_;
  124. const raw_ptr<const base::TickClock> tick_clock_;
  125. const raw_ptr<const ReportingDelegate> delegate_;
  126. const raw_ptr<ReportingCache> cache_;
  127. RandIntCallback rand_callback_;
  128. // Note: Currently the ReportingBrowsingDataRemover does not clear this data
  129. // because it's not persisted to disk. If it's ever persisted, it will need
  130. // to be cleared as well.
  131. // TODO(chlily): clear this data when endpoints are deleted to avoid unbounded
  132. // growth of this map.
  133. base::LRUCache<EndpointBackoffKey, std::unique_ptr<net::BackoffEntry>>
  134. endpoint_backoff_;
  135. };
  136. } // namespace
  137. // static
  138. std::unique_ptr<ReportingEndpointManager> ReportingEndpointManager::Create(
  139. const ReportingPolicy* policy,
  140. const base::TickClock* tick_clock,
  141. const ReportingDelegate* delegate,
  142. ReportingCache* cache,
  143. const RandIntCallback& rand_callback) {
  144. return std::make_unique<ReportingEndpointManagerImpl>(
  145. policy, tick_clock, delegate, cache, rand_callback);
  146. }
  147. ReportingEndpointManager::~ReportingEndpointManager() = default;
  148. } // namespace net