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 |