| Index: net/reporting/reporting_delivery_agent.cc
|
| diff --git a/net/reporting/reporting_delivery_agent.cc b/net/reporting/reporting_delivery_agent.cc
|
| index f39dde936ea46b4e940c8fc9e2a9aaf8c23624f6..e614aa1b166fde4abfb35c3b85317d1831517538 100644
|
| --- a/net/reporting/reporting_delivery_agent.cc
|
| +++ b/net/reporting/reporting_delivery_agent.cc
|
| @@ -13,9 +13,11 @@
|
| #include "base/logging.h"
|
| #include "base/memory/ptr_util.h"
|
| #include "base/time/tick_clock.h"
|
| +#include "base/timer/timer.h"
|
| #include "base/values.h"
|
| #include "net/reporting/reporting_cache.h"
|
| #include "net/reporting/reporting_endpoint_manager.h"
|
| +#include "net/reporting/reporting_observer.h"
|
| #include "net/reporting/reporting_report.h"
|
| #include "net/reporting/reporting_uploader.h"
|
| #include "url/gurl.h"
|
| @@ -46,97 +48,174 @@ void SerializeReports(const std::vector<const ReportingReport*>& reports,
|
| DCHECK(json_written);
|
| }
|
|
|
| -} // namespace
|
| +class ReportingDeliveryAgentImpl : public ReportingDeliveryAgent,
|
| + public ReportingObserver {
|
| + public:
|
| + ReportingDeliveryAgentImpl(ReportingContext* context)
|
| + : context_(context),
|
| + timer_(base::MakeUnique<base::OneShotTimer>()),
|
| + weak_factory_(this) {
|
| + context_->AddObserver(this);
|
| + }
|
|
|
| -ReportingDeliveryAgent::ReportingDeliveryAgent(ReportingContext* context)
|
| - : context_(context), weak_factory_(this) {}
|
| -ReportingDeliveryAgent::~ReportingDeliveryAgent() {}
|
| + // ReportingDeliveryAgent implementation:
|
|
|
| -class ReportingDeliveryAgent::Delivery {
|
| - public:
|
| - Delivery(const GURL& endpoint,
|
| - const std::vector<const ReportingReport*>& reports)
|
| - : endpoint(endpoint), reports(reports) {}
|
| + ~ReportingDeliveryAgentImpl() override { context_->RemoveObserver(this); }
|
|
|
| - ~Delivery() {}
|
| + void Initialize() override {
|
| + if (CacheHasReports())
|
| + StartTimer();
|
| + }
|
|
|
| - const GURL endpoint;
|
| - const std::vector<const ReportingReport*> reports;
|
| -};
|
| + void SetTimerForTesting(std::unique_ptr<base::Timer> timer) override {
|
| + DCHECK(!timer_->IsRunning());
|
| + timer_ = std::move(timer);
|
| + }
|
| +
|
| + // ReportingObserver implementation:
|
| + void OnCacheUpdated() override {
|
| + if (CacheHasReports())
|
| + StartTimer();
|
| + }
|
|
|
| -void ReportingDeliveryAgent::SendReports() {
|
| - std::vector<const ReportingReport*> reports;
|
| - cache()->GetReports(&reports);
|
| + private:
|
| + class Delivery {
|
| + public:
|
| + Delivery(const GURL& endpoint,
|
| + const std::vector<const ReportingReport*>& reports)
|
| + : endpoint(endpoint), reports(reports) {}
|
|
|
| - // Sort reports into (origin, group) buckets.
|
| - std::map<OriginGroup, std::vector<const ReportingReport*>>
|
| - origin_group_reports;
|
| - for (const ReportingReport* report : reports) {
|
| - OriginGroup origin_group(url::Origin(report->url), report->group);
|
| - origin_group_reports[origin_group].push_back(report);
|
| + ~Delivery() {}
|
| +
|
| + const GURL endpoint;
|
| + const std::vector<const ReportingReport*> reports;
|
| + };
|
| +
|
| + using OriginGroup = std::pair<url::Origin, std::string>;
|
| +
|
| + bool CacheHasReports() {
|
| + std::vector<const ReportingReport*> reports;
|
| + context_->cache()->GetReports(&reports);
|
| + return !reports.empty();
|
| + }
|
| +
|
| + void StartTimer() {
|
| + timer_->Start(FROM_HERE, policy().delivery_interval,
|
| + base::Bind(&ReportingDeliveryAgentImpl::OnTimerFired,
|
| + base::Unretained(this)));
|
| + }
|
| +
|
| + void OnTimerFired() {
|
| + if (CacheHasReports()) {
|
| + SendReports();
|
| + StartTimer();
|
| + }
|
| }
|
|
|
| - // Find endpoint for each (origin, group) bucket and sort reports into
|
| - // endpoint buckets. Don't allow concurrent deliveries to the same (origin,
|
| - // group) bucket.
|
| - std::map<GURL, std::vector<const ReportingReport*>> endpoint_reports;
|
| - for (auto& it : origin_group_reports) {
|
| - const OriginGroup& origin_group = it.first;
|
| + void SendReports() {
|
| + std::vector<const ReportingReport*> reports;
|
| + cache()->GetReports(&reports);
|
|
|
| - if (base::ContainsKey(pending_origin_groups_, origin_group))
|
| - continue;
|
| + // Sort reports into (origin, group) buckets.
|
| + std::map<OriginGroup, std::vector<const ReportingReport*>>
|
| + origin_group_reports;
|
| + for (const ReportingReport* report : reports) {
|
| + OriginGroup origin_group(url::Origin(report->url), report->group);
|
| + origin_group_reports[origin_group].push_back(report);
|
| + }
|
|
|
| - GURL endpoint_url;
|
| - if (!endpoint_manager()->FindEndpointForOriginAndGroup(
|
| - origin_group.first, origin_group.second, &endpoint_url)) {
|
| - continue;
|
| + // Find endpoint for each (origin, group) bucket and sort reports into
|
| + // endpoint buckets. Don't allow concurrent deliveries to the same (origin,
|
| + // group) bucket.
|
| + std::map<GURL, std::vector<const ReportingReport*>> endpoint_reports;
|
| + for (auto& it : origin_group_reports) {
|
| + const OriginGroup& origin_group = it.first;
|
| +
|
| + if (base::ContainsKey(pending_origin_groups_, origin_group))
|
| + continue;
|
| +
|
| + GURL endpoint_url;
|
| + if (!endpoint_manager()->FindEndpointForOriginAndGroup(
|
| + origin_group.first, origin_group.second, &endpoint_url)) {
|
| + continue;
|
| + }
|
| +
|
| + endpoint_reports[endpoint_url].insert(
|
| + endpoint_reports[endpoint_url].end(), it.second.begin(),
|
| + it.second.end());
|
| + pending_origin_groups_.insert(origin_group);
|
| }
|
|
|
| - endpoint_reports[endpoint_url].insert(endpoint_reports[endpoint_url].end(),
|
| - it.second.begin(), it.second.end());
|
| - pending_origin_groups_.insert(origin_group);
|
| + // Start a delivery to each endpoint.
|
| + for (auto& it : endpoint_reports) {
|
| + const GURL& endpoint = it.first;
|
| + const std::vector<const ReportingReport*>& reports = it.second;
|
| +
|
| + endpoint_manager()->SetEndpointPending(endpoint);
|
| + cache()->SetReportsPending(reports);
|
| +
|
| + std::string json;
|
| + SerializeReports(reports, tick_clock()->NowTicks(), &json);
|
| +
|
| + uploader()->StartUpload(
|
| + endpoint, json,
|
| + base::Bind(&ReportingDeliveryAgentImpl::OnUploadComplete,
|
| + weak_factory_.GetWeakPtr(),
|
| + base::MakeUnique<Delivery>(endpoint, reports)));
|
| + }
|
| }
|
|
|
| - // Start a delivery to each endpoint.
|
| - for (auto& it : endpoint_reports) {
|
| - const GURL& endpoint = it.first;
|
| - const std::vector<const ReportingReport*>& reports = it.second;
|
| + void OnUploadComplete(const std::unique_ptr<Delivery>& delivery,
|
| + ReportingUploader::Outcome outcome) {
|
| + if (outcome == ReportingUploader::Outcome::SUCCESS) {
|
| + cache()->RemoveReports(delivery->reports);
|
| + endpoint_manager()->InformOfEndpointRequest(delivery->endpoint, true);
|
| + } else {
|
| + cache()->IncrementReportsAttempts(delivery->reports);
|
| + endpoint_manager()->InformOfEndpointRequest(delivery->endpoint, false);
|
| + }
|
|
|
| - endpoint_manager()->SetEndpointPending(endpoint);
|
| - cache()->SetReportsPending(reports);
|
| + if (outcome == ReportingUploader::Outcome::REMOVE_ENDPOINT)
|
| + cache()->RemoveClientsForEndpoint(delivery->endpoint);
|
|
|
| - std::string json;
|
| - SerializeReports(reports, tick_clock()->NowTicks(), &json);
|
| + for (const ReportingReport* report : delivery->reports) {
|
| + pending_origin_groups_.erase(
|
| + OriginGroup(url::Origin(report->url), report->group));
|
| + }
|
|
|
| - uploader()->StartUpload(
|
| - endpoint, json,
|
| - base::Bind(&ReportingDeliveryAgent::OnUploadComplete,
|
| - weak_factory_.GetWeakPtr(),
|
| - base::MakeUnique<Delivery>(endpoint, reports)));
|
| + endpoint_manager()->ClearEndpointPending(delivery->endpoint);
|
| + cache()->ClearReportsPending(delivery->reports);
|
| }
|
| -}
|
|
|
| -void ReportingDeliveryAgent::OnUploadComplete(
|
| - const std::unique_ptr<Delivery>& delivery,
|
| - ReportingUploader::Outcome outcome) {
|
| - if (outcome == ReportingUploader::Outcome::SUCCESS) {
|
| - cache()->RemoveReports(delivery->reports);
|
| - endpoint_manager()->InformOfEndpointRequest(delivery->endpoint, true);
|
| - } else {
|
| - cache()->IncrementReportsAttempts(delivery->reports);
|
| - endpoint_manager()->InformOfEndpointRequest(delivery->endpoint, false);
|
| + const ReportingPolicy& policy() { return context_->policy(); }
|
| + base::TickClock* tick_clock() { return context_->tick_clock(); }
|
| + ReportingCache* cache() { return context_->cache(); }
|
| + ReportingUploader* uploader() { return context_->uploader(); }
|
| + ReportingEndpointManager* endpoint_manager() {
|
| + return context_->endpoint_manager();
|
| }
|
|
|
| - if (outcome == ReportingUploader::Outcome::REMOVE_ENDPOINT)
|
| - cache()->RemoveClientsForEndpoint(delivery->endpoint);
|
| + ReportingContext* context_;
|
|
|
| - for (const ReportingReport* report : delivery->reports) {
|
| - pending_origin_groups_.erase(
|
| - OriginGroup(url::Origin(report->url), report->group));
|
| - }
|
| + std::unique_ptr<base::Timer> timer_;
|
| +
|
| + // Tracks OriginGroup tuples for which there is a pending delivery running.
|
| + // (Would be an unordered_set, but there's no hash on pair.)
|
| + std::set<OriginGroup> pending_origin_groups_;
|
| +
|
| + base::WeakPtrFactory<ReportingDeliveryAgentImpl> weak_factory_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ReportingDeliveryAgentImpl);
|
| +};
|
|
|
| - endpoint_manager()->ClearEndpointPending(delivery->endpoint);
|
| - cache()->ClearReportsPending(delivery->reports);
|
| +} // namespace
|
| +
|
| +// static
|
| +std::unique_ptr<ReportingDeliveryAgent> ReportingDeliveryAgent::Create(
|
| + ReportingContext* context) {
|
| + return base::MakeUnique<ReportingDeliveryAgentImpl>(context);
|
| }
|
|
|
| +ReportingDeliveryAgent::~ReportingDeliveryAgent() {}
|
| +
|
| } // namespace net
|
|
|