1 // Copyright 2017 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/reporting/reporting_garbage_collector.h" 6 7 #include <utility> 8 #include <vector> 9 10 #include "base/containers/flat_set.h" 11 #include "base/functional/bind.h" 12 #include "base/memory/raw_ptr.h" 13 #include "base/time/tick_clock.h" 14 #include "base/time/time.h" 15 #include "base/timer/timer.h" 16 #include "net/reporting/reporting_cache.h" 17 #include "net/reporting/reporting_cache_observer.h" 18 #include "net/reporting/reporting_context.h" 19 #include "net/reporting/reporting_policy.h" 20 #include "net/reporting/reporting_report.h" 21 22 namespace net { 23 24 namespace { 25 26 class ReportingGarbageCollectorImpl : public ReportingGarbageCollector, 27 public ReportingCacheObserver { 28 public: ReportingGarbageCollectorImpl(ReportingContext * context)29 explicit ReportingGarbageCollectorImpl(ReportingContext* context) 30 : context_(context), timer_(std::make_unique<base::OneShotTimer>()) { 31 context_->AddCacheObserver(this); 32 } 33 34 // ReportingGarbageCollector implementation: 35 ~ReportingGarbageCollectorImpl()36 ~ReportingGarbageCollectorImpl() override { 37 context_->RemoveCacheObserver(this); 38 } 39 SetTimerForTesting(std::unique_ptr<base::OneShotTimer> timer)40 void SetTimerForTesting(std::unique_ptr<base::OneShotTimer> timer) override { 41 timer_ = std::move(timer); 42 } 43 44 // ReportingObserver implementation: OnReportsUpdated()45 void OnReportsUpdated() override { EnsureTimerIsRunning(); } OnEndpointsUpdatedForOrigin(const std::vector<ReportingEndpoint> & endpoints)46 void OnEndpointsUpdatedForOrigin( 47 const std::vector<ReportingEndpoint>& endpoints) override { 48 EnsureTimerIsRunning(); 49 } 50 51 private: 52 // TODO(crbug.com/912622): Garbage collect clients, reports with no matching 53 // endpoints. CollectGarbage()54 void CollectGarbage() { 55 base::TimeTicks now = context_->tick_clock().NowTicks(); 56 const ReportingPolicy& policy = context_->policy(); 57 58 base::flat_set<base::UnguessableToken> sources_to_remove = 59 context_->cache()->GetExpiredSources(); 60 61 std::vector<const ReportingReport*> all_reports; 62 context_->cache()->GetReports(&all_reports); 63 64 std::vector<const ReportingReport*> failed_reports; 65 std::vector<const ReportingReport*> expired_reports; 66 for (const ReportingReport* report : all_reports) { 67 if (report->attempts >= policy.max_report_attempts) 68 failed_reports.push_back(report); 69 else if (now - report->queued >= policy.max_report_age) 70 expired_reports.push_back(report); 71 else 72 sources_to_remove.erase(report->reporting_source); 73 } 74 75 // Don't restart the timer on the garbage collector's own updates. 76 context_->RemoveCacheObserver(this); 77 context_->cache()->RemoveReports(failed_reports); 78 context_->cache()->RemoveReports(expired_reports); 79 for (const base::UnguessableToken& reporting_source : sources_to_remove) { 80 context_->cache()->RemoveSourceAndEndpoints(reporting_source); 81 } 82 context_->AddCacheObserver(this); 83 } 84 EnsureTimerIsRunning()85 void EnsureTimerIsRunning() { 86 if (timer_->IsRunning()) 87 return; 88 89 timer_->Start(FROM_HERE, context_->policy().garbage_collection_interval, 90 base::BindOnce(&ReportingGarbageCollectorImpl::CollectGarbage, 91 base::Unretained(this))); 92 } 93 94 raw_ptr<ReportingContext> context_; 95 std::unique_ptr<base::OneShotTimer> timer_; 96 }; 97 98 } // namespace 99 100 // static Create(ReportingContext * context)101std::unique_ptr<ReportingGarbageCollector> ReportingGarbageCollector::Create( 102 ReportingContext* context) { 103 return std::make_unique<ReportingGarbageCollectorImpl>(context); 104 } 105 106 ReportingGarbageCollector::~ReportingGarbageCollector() = default; 107 108 } // namespace net 109