| // Copyright 2017 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. | 
 |  | 
 | #include "net/reporting/reporting_endpoint_manager.h" | 
 |  | 
 | #include <map> | 
 | #include <set> | 
 | #include <string> | 
 | #include <vector> | 
 |  | 
 | #include "base/logging.h" | 
 | #include "base/macros.h" | 
 | #include "base/rand_util.h" | 
 | #include "base/stl_util.h" | 
 | #include "base/time/tick_clock.h" | 
 | #include "net/base/backoff_entry.h" | 
 | #include "net/base/rand_callback.h" | 
 | #include "net/reporting/reporting_cache.h" | 
 | #include "net/reporting/reporting_client.h" | 
 | #include "net/reporting/reporting_delegate.h" | 
 | #include "net/reporting/reporting_policy.h" | 
 | #include "url/gurl.h" | 
 | #include "url/origin.h" | 
 |  | 
 | namespace net { | 
 |  | 
 | namespace { | 
 |  | 
 | class ReportingEndpointManagerImpl : public ReportingEndpointManager { | 
 |  public: | 
 |   ReportingEndpointManagerImpl(ReportingContext* context, | 
 |                                const RandIntCallback& rand_callback) | 
 |       : context_(context), rand_callback_(rand_callback) {} | 
 |  | 
 |   ~ReportingEndpointManagerImpl() override = default; | 
 |  | 
 |   const ReportingClient* FindClientForOriginAndGroup( | 
 |       const url::Origin& origin, | 
 |       const std::string& group) override { | 
 |     std::vector<const ReportingClient*> clients; | 
 |     cache()->GetClientsForOriginAndGroup(origin, group, &clients); | 
 |  | 
 |     // Highest-priority client(s) that are not expired, pending, failing, or | 
 |     // forbidden for use by the ReportingDelegate. | 
 |     std::vector<const ReportingClient*> available_clients; | 
 |     // Total weight of clients in available_clients. | 
 |     int total_weight = 0; | 
 |  | 
 |     base::TimeTicks now = tick_clock()->NowTicks(); | 
 |     for (const ReportingClient* client : clients) { | 
 |       if (client->expires < now) | 
 |         continue; | 
 |       if (base::ContainsKey(endpoint_backoff_, client->endpoint) && | 
 |           endpoint_backoff_[client->endpoint]->ShouldRejectRequest()) { | 
 |         continue; | 
 |       } | 
 |       if (!delegate()->CanUseClient(client->origin, client->endpoint)) | 
 |         continue; | 
 |  | 
 |       // If this client is lower priority than the ones we've found, skip it. | 
 |       if (!available_clients.empty() && | 
 |           client->priority > available_clients[0]->priority) { | 
 |         continue; | 
 |       } | 
 |  | 
 |       // If this client is higher priority than the ones we've found (or we | 
 |       // haven't found any), forget about those ones and remember this one. | 
 |       if (available_clients.empty() || | 
 |           client->priority < available_clients[0]->priority) { | 
 |         available_clients.clear(); | 
 |         total_weight = 0; | 
 |       } | 
 |  | 
 |       available_clients.push_back(client); | 
 |       total_weight += client->weight; | 
 |     } | 
 |  | 
 |     if (available_clients.empty()) { | 
 |       return nullptr; | 
 |     } | 
 |  | 
 |     int random_index = rand_callback_.Run(0, total_weight - 1); | 
 |     int weight_so_far = 0; | 
 |     for (size_t i = 0; i < available_clients.size(); ++i) { | 
 |       const ReportingClient* client = available_clients[i]; | 
 |       weight_so_far += client->weight; | 
 |       if (random_index < weight_so_far) { | 
 |         return client; | 
 |       } | 
 |     } | 
 |  | 
 |     // TODO(juliatuttle): Can we reach this in some weird overflow case? | 
 |     NOTREACHED(); | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   void InformOfEndpointRequest(const GURL& endpoint, bool succeeded) override { | 
 |     if (!base::ContainsKey(endpoint_backoff_, endpoint)) { | 
 |       endpoint_backoff_[endpoint] = std::make_unique<BackoffEntry>( | 
 |           &policy().endpoint_backoff_policy, tick_clock()); | 
 |     } | 
 |     endpoint_backoff_[endpoint]->InformOfRequest(succeeded); | 
 |   } | 
 |  | 
 |  private: | 
 |   const ReportingPolicy& policy() { return context_->policy(); } | 
 |   const base::TickClock* tick_clock() { return context_->tick_clock(); } | 
 |   ReportingDelegate* delegate() { return context_->delegate(); } | 
 |   ReportingCache* cache() { return context_->cache(); } | 
 |  | 
 |   ReportingContext* context_; | 
 |  | 
 |   RandIntCallback rand_callback_; | 
 |  | 
 |   // Note: Currently the ReportingBrowsingDataRemover does not clear this data | 
 |   // because it's not persisted to disk. If it's ever persisted, it will need | 
 |   // to be cleared as well. | 
 |   std::map<GURL, std::unique_ptr<net::BackoffEntry>> endpoint_backoff_; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(ReportingEndpointManagerImpl); | 
 | }; | 
 |  | 
 | }  // namespace | 
 |  | 
 | // static | 
 | std::unique_ptr<ReportingEndpointManager> ReportingEndpointManager::Create( | 
 |     ReportingContext* context, | 
 |     const RandIntCallback& rand_callback) { | 
 |   return std::make_unique<ReportingEndpointManagerImpl>(context, rand_callback); | 
 | } | 
 |  | 
 | ReportingEndpointManager::~ReportingEndpointManager() = default; | 
 |  | 
 | }  // namespace net |