diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-09-18 14:34:04 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-10-04 11:15:27 +0000 |
commit | e6430e577f105ad8813c92e75c54660c4985026e (patch) | |
tree | 88115e5d1fb471fea807111924dcccbeadbf9e4f /chromium/net/reporting | |
parent | 53d399fe6415a96ea6986ec0d402a9c07da72453 (diff) | |
download | qtwebengine-chromium-e6430e577f105ad8813c92e75c54660c4985026e.tar.gz |
BASELINE: Update Chromium to 61.0.3163.99
Change-Id: I8452f34574d88ca2b27af9bd56fc9ff3f16b1367
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/net/reporting')
21 files changed, 704 insertions, 583 deletions
diff --git a/chromium/net/reporting/reporting_browsing_data_remover.cc b/chromium/net/reporting/reporting_browsing_data_remover.cc index a10bcf86b3e..5983fe6be95 100644 --- a/chromium/net/reporting/reporting_browsing_data_remover.cc +++ b/chromium/net/reporting/reporting_browsing_data_remover.cc @@ -14,74 +14,52 @@ namespace net { -namespace { - -class ReportingBrowsingDataRemoverImpl : public ReportingBrowsingDataRemover { - public: - ReportingBrowsingDataRemoverImpl(ReportingContext* context) - : context_(context) {} - - // ReportingBrowsingDataRemover implementation: - - ~ReportingBrowsingDataRemoverImpl() override {} - - void RemoveBrowsingData( - int data_type_mask, - base::Callback<bool(const GURL&)> origin_filter) override { - ReportingCache* cache = context_->cache(); - bool remove_reports = (data_type_mask & DATA_TYPE_REPORTS) != 0; - bool remove_clients = (data_type_mask & DATA_TYPE_CLIENTS) != 0; - - if (origin_filter.is_null()) { - if (remove_reports) - cache->RemoveAllReports(); - if (remove_clients) - cache->RemoveAllClients(); - return; - } - +// static +void ReportingBrowsingDataRemover::RemoveBrowsingData( + ReportingCache* cache, + int data_type_mask, + base::Callback<bool(const GURL&)> origin_filter) { + bool remove_reports = (data_type_mask & DATA_TYPE_REPORTS) != 0; + bool remove_clients = (data_type_mask & DATA_TYPE_CLIENTS) != 0; + + if (origin_filter.is_null()) { if (remove_reports) { - std::vector<const ReportingReport*> all_reports; - cache->GetReports(&all_reports); - - std::vector<const ReportingReport*> reports_to_remove; - for (const ReportingReport* report : all_reports) { - if (origin_filter.Run(report->url)) - reports_to_remove.push_back(report); - } - - cache->RemoveReports(reports_to_remove); + cache->RemoveAllReports( + ReportingReport::Outcome::ERASED_BROWSING_DATA_REMOVED); } + if (remove_clients) + cache->RemoveAllClients(); + return; + } - if (remove_clients) { - std::vector<const ReportingClient*> all_clients; - cache->GetClients(&all_clients); - - std::vector<const ReportingClient*> clients_to_remove; - for (const ReportingClient* client : all_clients) { - // TODO(juliatuttle): Examine client endpoint as well? - if (origin_filter.Run(client->origin.GetURL())) - clients_to_remove.push_back(client); - } + if (remove_reports) { + std::vector<const ReportingReport*> all_reports; + cache->GetReports(&all_reports); - cache->RemoveClients(clients_to_remove); + std::vector<const ReportingReport*> reports_to_remove; + for (const ReportingReport* report : all_reports) { + if (origin_filter.Run(report->url)) + reports_to_remove.push_back(report); } - } - private: - ReportingContext* context_; + cache->RemoveReports( + reports_to_remove, + ReportingReport::Outcome::ERASED_BROWSING_DATA_REMOVED); + } - DISALLOW_COPY_AND_ASSIGN(ReportingBrowsingDataRemoverImpl); -}; + if (remove_clients) { + std::vector<const ReportingClient*> all_clients; + cache->GetClients(&all_clients); -} // namespace + std::vector<const ReportingClient*> clients_to_remove; + for (const ReportingClient* client : all_clients) { + // TODO(juliatuttle): Examine client endpoint as well? + if (origin_filter.Run(client->origin.GetURL())) + clients_to_remove.push_back(client); + } -// static -std::unique_ptr<ReportingBrowsingDataRemover> -ReportingBrowsingDataRemover::Create(ReportingContext* context) { - return base::MakeUnique<ReportingBrowsingDataRemoverImpl>(context); + cache->RemoveClients(clients_to_remove); + } } -ReportingBrowsingDataRemover::~ReportingBrowsingDataRemover() {} - } // namespace net diff --git a/chromium/net/reporting/reporting_browsing_data_remover.h b/chromium/net/reporting/reporting_browsing_data_remover.h index 0c89885c7d9..0f531d74b92 100644 --- a/chromium/net/reporting/reporting_browsing_data_remover.h +++ b/chromium/net/reporting/reporting_browsing_data_remover.h @@ -14,7 +14,7 @@ namespace net { -class ReportingContext; +class ReportingCache; // Clears browsing data (reports and clients) from the Reporting system. class NET_EXPORT ReportingBrowsingDataRemover { @@ -24,13 +24,6 @@ class NET_EXPORT ReportingBrowsingDataRemover { DATA_TYPE_CLIENTS = 0x2, }; - // Creates a ReportingBrowsingDataRemover. |context| must outlive the - // browsing data remover. - static std::unique_ptr<ReportingBrowsingDataRemover> Create( - ReportingContext* context); - - virtual ~ReportingBrowsingDataRemover(); - // Removes browsing data from the Reporting system. |data_type_mask| specifies // which types of data to remove: reports queued by browser features and/or // clients (endpoints configured by origins). |origin_filter|, if not null, @@ -39,9 +32,13 @@ class NET_EXPORT ReportingBrowsingDataRemover { // Note: Currently this does not clear the endpoint backoff data in // ReportingEndpointManager because that's not persisted to disk. If it's ever // persisted, it will need to be cleared as well. - virtual void RemoveBrowsingData( + static void RemoveBrowsingData( + ReportingCache* cache, int data_type_mask, - base::Callback<bool(const GURL&)> origin_filter) = 0; + base::Callback<bool(const GURL&)> origin_filter); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ReportingBrowsingDataRemover); }; } // namespace net diff --git a/chromium/net/reporting/reporting_browsing_data_remover_unittest.cc b/chromium/net/reporting/reporting_browsing_data_remover_unittest.cc index 5b05451601d..cd4a728ffd6 100644 --- a/chromium/net/reporting/reporting_browsing_data_remover_unittest.cc +++ b/chromium/net/reporting/reporting_browsing_data_remover_unittest.cc @@ -35,7 +35,8 @@ class ReportingBrowsingDataRemoverTest : public ReportingTestBase { base::Bind(&ReportingBrowsingDataRemoverTest::HostIs, host); } - browsing_data_remover()->RemoveBrowsingData(data_type_mask, origin_filter); + ReportingBrowsingDataRemover::RemoveBrowsingData(cache(), data_type_mask, + origin_filter); } static bool HostIs(std::string host, const GURL& url) { diff --git a/chromium/net/reporting/reporting_cache.cc b/chromium/net/reporting/reporting_cache.cc index 7920a20ca4f..87c270d62f4 100644 --- a/chromium/net/reporting/reporting_cache.cc +++ b/chromium/net/reporting/reporting_cache.cc @@ -8,6 +8,8 @@ #include <memory> #include <set> #include <string> +#include <unordered_map> +#include <unordered_set> #include <utility> #include <vector> @@ -42,359 +44,428 @@ std::string GetSuperdomain(const std::string& domain) { return domain.substr(dot_pos + 1); } -} // namespace +class ReportingCacheImpl : public ReportingCache { + public: + ReportingCacheImpl(ReportingContext* context) : context_(context) { + DCHECK(context_); + } -ReportingCache::ReportingCache(ReportingContext* context) : context_(context) { - DCHECK(context_); -} + ~ReportingCacheImpl() override { + base::TimeTicks now = tick_clock()->NowTicks(); -ReportingCache::~ReportingCache() {} + // Mark all undoomed reports as erased at shutdown, and record outcomes of + // all remaining reports (doomed or not). + for (auto it = reports_.begin(); it != reports_.end(); ++it) { + ReportingReport* report = it->second.get(); + if (!base::ContainsKey(doomed_reports_, report)) + report->outcome = ReportingReport::Outcome::ERASED_REPORTING_SHUT_DOWN; + report->RecordOutcome(now); + } -void ReportingCache::AddReport(const GURL& url, - const std::string& group, - const std::string& type, - std::unique_ptr<const base::Value> body, - base::TimeTicks queued, - int attempts) { - auto report = base::MakeUnique<ReportingReport>( - url, group, type, std::move(body), queued, attempts); - - auto inserted = - reports_.insert(std::make_pair(report.get(), std::move(report))); - DCHECK(inserted.second); - - if (reports_.size() > context_->policy().max_report_count) { - // There should be at most one extra report (the one added above). - DCHECK_EQ(context_->policy().max_report_count + 1, reports_.size()); - const ReportingReport* to_evict = FindReportToEvict(); - DCHECK_NE(nullptr, to_evict); - // The newly-added report isn't pending, so even if all other reports are - // pending, the cache should have a report to evict. - DCHECK(!base::ContainsKey(pending_reports_, to_evict)); - size_t erased = reports_.erase(to_evict); - DCHECK_EQ(1u, erased); + reports_.clear(); } - context_->NotifyCacheUpdated(); -} + void AddReport(const GURL& url, + const std::string& group, + const std::string& type, + std::unique_ptr<const base::Value> body, + base::TimeTicks queued, + int attempts) override { + auto report = base::MakeUnique<ReportingReport>( + url, group, type, std::move(body), queued, attempts); + + auto inserted = + reports_.insert(std::make_pair(report.get(), std::move(report))); + DCHECK(inserted.second); -void ReportingCache::GetReports( - std::vector<const ReportingReport*>* reports_out) const { - reports_out->clear(); - for (const auto& it : reports_) { - if (!base::ContainsKey(doomed_reports_, it.first)) - reports_out->push_back(it.second.get()); - } -} + if (reports_.size() > context_->policy().max_report_count) { + // There should be at most one extra report (the one added above). + DCHECK_EQ(context_->policy().max_report_count + 1, reports_.size()); + const ReportingReport* to_evict = FindReportToEvict(); + DCHECK_NE(nullptr, to_evict); + // The newly-added report isn't pending, so even if all other reports are + // pending, the cache should have a report to evict. + DCHECK(!base::ContainsKey(pending_reports_, to_evict)); + reports_[to_evict]->outcome = ReportingReport::Outcome::ERASED_EVICTED; + RemoveReportInternal(to_evict); + } -void ReportingCache::SetReportsPending( - const std::vector<const ReportingReport*>& reports) { - for (const ReportingReport* report : reports) { - auto inserted = pending_reports_.insert(report); - DCHECK(inserted.second); + context_->NotifyCacheUpdated(); } -} - -void ReportingCache::ClearReportsPending( - const std::vector<const ReportingReport*>& reports) { - std::vector<const ReportingReport*> reports_to_remove; - for (const ReportingReport* report : reports) { - size_t erased = pending_reports_.erase(report); - DCHECK_EQ(1u, erased); - if (base::ContainsKey(doomed_reports_, report)) { - reports_to_remove.push_back(report); - doomed_reports_.erase(report); + void GetReports( + std::vector<const ReportingReport*>* reports_out) const override { + reports_out->clear(); + for (const auto& it : reports_) { + if (!base::ContainsKey(doomed_reports_, it.first)) + reports_out->push_back(it.second.get()); } } - RemoveReports(reports_to_remove); -} - -void ReportingCache::IncrementReportsAttempts( - const std::vector<const ReportingReport*>& reports) { - for (const ReportingReport* report : reports) { - DCHECK(base::ContainsKey(reports_, report)); - reports_[report]->attempts++; + void SetReportsPending( + const std::vector<const ReportingReport*>& reports) override { + for (const ReportingReport* report : reports) { + auto inserted = pending_reports_.insert(report); + DCHECK(inserted.second); + } } - context_->NotifyCacheUpdated(); -} + void ClearReportsPending( + const std::vector<const ReportingReport*>& reports) override { + std::vector<const ReportingReport*> reports_to_remove; -void ReportingCache::RemoveReports( - const std::vector<const ReportingReport*>& reports) { - for (const ReportingReport* report : reports) { - if (base::ContainsKey(pending_reports_, report)) { - doomed_reports_.insert(report); - } else { - DCHECK(!base::ContainsKey(doomed_reports_, report)); - size_t erased = reports_.erase(report); + for (const ReportingReport* report : reports) { + size_t erased = pending_reports_.erase(report); DCHECK_EQ(1u, erased); + if (base::ContainsKey(doomed_reports_, report)) { + reports_to_remove.push_back(report); + doomed_reports_.erase(report); + } } + + for (const ReportingReport* report : reports_to_remove) + RemoveReportInternal(report); } - context_->NotifyCacheUpdated(); -} + void IncrementReportsAttempts( + const std::vector<const ReportingReport*>& reports) override { + for (const ReportingReport* report : reports) { + DCHECK(base::ContainsKey(reports_, report)); + reports_[report]->attempts++; + } -void ReportingCache::RemoveAllReports() { - std::vector<std::unordered_map<const ReportingReport*, - std::unique_ptr<ReportingReport>>::iterator> - reports_to_remove; - for (auto it = reports_.begin(); it != reports_.end(); ++it) { - ReportingReport* report = it->second.get(); - if (!base::ContainsKey(pending_reports_, report)) - reports_to_remove.push_back(it); - else - doomed_reports_.insert(report); + context_->NotifyCacheUpdated(); } - for (auto& it : reports_to_remove) - reports_.erase(it); + void RemoveReports(const std::vector<const ReportingReport*>& reports, + ReportingReport::Outcome outcome) override { + for (const ReportingReport* report : reports) { + reports_[report]->outcome = outcome; + if (base::ContainsKey(pending_reports_, report)) { + doomed_reports_.insert(report); + } else { + DCHECK(!base::ContainsKey(doomed_reports_, report)); + RemoveReportInternal(report); + } + } - context_->NotifyCacheUpdated(); -} + context_->NotifyCacheUpdated(); + } -void ReportingCache::GetClients( - std::vector<const ReportingClient*>* clients_out) const { - clients_out->clear(); - for (const auto& it : clients_) - for (const auto& endpoint_and_client : it.second) - clients_out->push_back(endpoint_and_client.second.get()); -} + void RemoveAllReports(ReportingReport::Outcome outcome) override { + std::vector<const ReportingReport*> reports_to_remove; + for (auto it = reports_.begin(); it != reports_.end(); ++it) { + ReportingReport* report = it->second.get(); + report->outcome = outcome; + if (!base::ContainsKey(pending_reports_, report)) + reports_to_remove.push_back(report); + else + doomed_reports_.insert(report); + } + + for (const ReportingReport* report : reports_to_remove) + RemoveReportInternal(report); -void ReportingCache::GetClientsForOriginAndGroup( - const url::Origin& origin, - const std::string& group, - std::vector<const ReportingClient*>* clients_out) const { - clients_out->clear(); + context_->NotifyCacheUpdated(); + } - const auto it = clients_.find(origin); - if (it != clients_.end()) { - for (const auto& endpoint_and_client : it->second) { - if (endpoint_and_client.second->group == group) + void GetClients( + std::vector<const ReportingClient*>* clients_out) const override { + clients_out->clear(); + for (const auto& it : clients_) + for (const auto& endpoint_and_client : it.second) clients_out->push_back(endpoint_and_client.second.get()); - } } - // If no clients were found, try successive superdomain suffixes until a - // client with includeSubdomains is found or there are no more domain - // components left. - std::string domain = origin.host(); - while (clients_out->empty() && !domain.empty()) { - GetWildcardClientsForDomainAndGroup(domain, group, clients_out); - domain = GetSuperdomain(domain); + void GetClientsForOriginAndGroup( + const url::Origin& origin, + const std::string& group, + std::vector<const ReportingClient*>* clients_out) const override { + clients_out->clear(); + + const auto it = clients_.find(origin); + if (it != clients_.end()) { + for (const auto& endpoint_and_client : it->second) { + if (endpoint_and_client.second->group == group) + clients_out->push_back(endpoint_and_client.second.get()); + } + } + + // If no clients were found, try successive superdomain suffixes until a + // client with includeSubdomains is found or there are no more domain + // components left. + std::string domain = origin.host(); + while (clients_out->empty() && !domain.empty()) { + GetWildcardClientsForDomainAndGroup(domain, group, clients_out); + domain = GetSuperdomain(domain); + } } -} -void ReportingCache::SetClient(const url::Origin& origin, - const GURL& endpoint, - ReportingClient::Subdomains subdomains, - const std::string& group, - base::TimeTicks expires) { - DCHECK(endpoint.SchemeIsCryptographic()); + void SetClient(const url::Origin& origin, + const GURL& endpoint, + ReportingClient::Subdomains subdomains, + const std::string& group, + base::TimeTicks expires) override { + DCHECK(endpoint.SchemeIsCryptographic()); + + base::TimeTicks last_used = tick_clock()->NowTicks(); - base::TimeTicks last_used = tick_clock()->NowTicks(); + const ReportingClient* old_client = + GetClientByOriginAndEndpoint(origin, endpoint); + if (old_client) { + last_used = client_last_used_[old_client]; + RemoveClient(old_client); + } - const ReportingClient* old_client = - GetClientByOriginAndEndpoint(origin, endpoint); - if (old_client) { - last_used = client_last_used_[old_client]; - RemoveClient(old_client); + AddClient(base::MakeUnique<ReportingClient>(origin, endpoint, subdomains, + group, expires), + last_used); + + if (client_last_used_.size() > context_->policy().max_client_count) { + // There should only ever be one extra client, added above. + DCHECK_EQ(context_->policy().max_client_count + 1, + client_last_used_.size()); + // And that shouldn't happen if it was replaced, not added. + DCHECK(!old_client); + const ReportingClient* to_evict = + FindClientToEvict(tick_clock()->NowTicks()); + DCHECK(to_evict); + RemoveClient(to_evict); + } + + context_->NotifyCacheUpdated(); } - AddClient(base::MakeUnique<ReportingClient>(origin, endpoint, subdomains, - group, expires), - last_used); - - if (client_last_used_.size() > context_->policy().max_client_count) { - // There should only ever be one extra client, added above. - DCHECK_EQ(context_->policy().max_client_count + 1, - client_last_used_.size()); - // And that shouldn't happen if it was replaced, not added. - DCHECK(!old_client); - const ReportingClient* to_evict = - FindClientToEvict(tick_clock()->NowTicks()); - DCHECK(to_evict); - RemoveClient(to_evict); + void MarkClientUsed(const url::Origin& origin, + const GURL& endpoint) override { + const ReportingClient* client = + GetClientByOriginAndEndpoint(origin, endpoint); + DCHECK(client); + client_last_used_[client] = tick_clock()->NowTicks(); } - context_->NotifyCacheUpdated(); -} + void RemoveClients( + const std::vector<const ReportingClient*>& clients_to_remove) override { + for (const ReportingClient* client : clients_to_remove) + RemoveClient(client); -void ReportingCache::MarkClientUsed(const url::Origin& origin, - const GURL& endpoint) { - const ReportingClient* client = - GetClientByOriginAndEndpoint(origin, endpoint); - DCHECK(client); - client_last_used_[client] = tick_clock()->NowTicks(); -} + context_->NotifyCacheUpdated(); + } -void ReportingCache::RemoveClients( - const std::vector<const ReportingClient*>& clients_to_remove) { - for (const ReportingClient* client : clients_to_remove) + void RemoveClientForOriginAndEndpoint(const url::Origin& origin, + const GURL& endpoint) override { + const ReportingClient* client = + GetClientByOriginAndEndpoint(origin, endpoint); RemoveClient(client); - context_->NotifyCacheUpdated(); -} + context_->NotifyCacheUpdated(); + } -void ReportingCache::RemoveClientForOriginAndEndpoint(const url::Origin& origin, - const GURL& endpoint) { - const ReportingClient* client = - GetClientByOriginAndEndpoint(origin, endpoint); - RemoveClient(client); + void RemoveClientsForEndpoint(const GURL& endpoint) override { + std::vector<const ReportingClient*> clients_to_remove; - context_->NotifyCacheUpdated(); -} + for (auto& origin_and_endpoints : clients_) + if (base::ContainsKey(origin_and_endpoints.second, endpoint)) + clients_to_remove.push_back( + origin_and_endpoints.second[endpoint].get()); -void ReportingCache::RemoveClientsForEndpoint(const GURL& endpoint) { - std::vector<const ReportingClient*> clients_to_remove; + for (const ReportingClient* client : clients_to_remove) + RemoveClient(client); - for (auto& origin_and_endpoints : clients_) - if (base::ContainsKey(origin_and_endpoints.second, endpoint)) - clients_to_remove.push_back(origin_and_endpoints.second[endpoint].get()); + if (!clients_to_remove.empty()) + context_->NotifyCacheUpdated(); + } - for (const ReportingClient* client : clients_to_remove) - RemoveClient(client); + void RemoveAllClients() override { + clients_.clear(); + wildcard_clients_.clear(); + client_last_used_.clear(); - if (!clients_to_remove.empty()) context_->NotifyCacheUpdated(); -} - -void ReportingCache::RemoveAllClients() { - clients_.clear(); - wildcard_clients_.clear(); - client_last_used_.clear(); + } - context_->NotifyCacheUpdated(); -} + size_t GetFullReportCountForTesting() const override { + return reports_.size(); + } -const ReportingReport* ReportingCache::FindReportToEvict() const { - const ReportingReport* earliest_queued = nullptr; + bool IsReportPendingForTesting(const ReportingReport* report) const override { + return base::ContainsKey(pending_reports_, report); + } - for (const auto& it : reports_) { - const ReportingReport* report = it.first; - if (base::ContainsKey(pending_reports_, report)) - continue; - if (!earliest_queued || report->queued < earliest_queued->queued) { - earliest_queued = report; - } + bool IsReportDoomedForTesting(const ReportingReport* report) const override { + return base::ContainsKey(doomed_reports_, report); } - return earliest_queued; -} + private: + ReportingContext* context_; -void ReportingCache::AddClient(std::unique_ptr<ReportingClient> client, - base::TimeTicks last_used) { - DCHECK(client); + // Owns all reports, keyed by const raw pointer for easier lookup. + std::unordered_map<const ReportingReport*, std::unique_ptr<ReportingReport>> + reports_; - url::Origin origin = client->origin; - GURL endpoint = client->endpoint; + // Reports that have been marked pending (in use elsewhere and should not be + // deleted until no longer pending). + std::unordered_set<const ReportingReport*> pending_reports_; - auto inserted_last_used = - client_last_used_.insert(std::make_pair(client.get(), last_used)); - DCHECK(inserted_last_used.second); + // Reports that have been marked doomed (would have been deleted, but were + // pending when the deletion was requested). + std::unordered_set<const ReportingReport*> doomed_reports_; - if (client->subdomains == ReportingClient::Subdomains::INCLUDE) { - const std::string& domain = origin.host(); - auto inserted_wildcard_client = - wildcard_clients_[domain].insert(client.get()); - DCHECK(inserted_wildcard_client.second); - } + // Owns all clients, keyed by origin, then endpoint URL. + // (These would be unordered_map, but neither url::Origin nor GURL has a hash + // function implemented.) + std::map<url::Origin, std::map<GURL, std::unique_ptr<ReportingClient>>> + clients_; - auto inserted_client = - clients_[origin].insert(std::make_pair(endpoint, std::move(client))); - DCHECK(inserted_client.second); -} + // References but does not own all clients with includeSubdomains set, keyed + // by domain name. + std::unordered_map<std::string, std::unordered_set<const ReportingClient*>> + wildcard_clients_; -void ReportingCache::RemoveClient(const ReportingClient* client) { - DCHECK(client); + // The time that each client has last been used. + std::unordered_map<const ReportingClient*, base::TimeTicks> client_last_used_; - url::Origin origin = client->origin; - GURL endpoint = client->endpoint; + base::TickClock* tick_clock() { return context_->tick_clock(); } - if (client->subdomains == ReportingClient::Subdomains::INCLUDE) { - const std::string& domain = origin.host(); - size_t erased_wildcard_client = wildcard_clients_[domain].erase(client); - DCHECK_EQ(1u, erased_wildcard_client); - if (wildcard_clients_[domain].empty()) { - size_t erased_wildcard_domain = wildcard_clients_.erase(domain); - DCHECK_EQ(1u, erased_wildcard_domain); + void RemoveReportInternal(const ReportingReport* report) { + reports_[report]->RecordOutcome(tick_clock()->NowTicks()); + size_t erased = reports_.erase(report); + DCHECK_EQ(1u, erased); + } + + const ReportingReport* FindReportToEvict() const { + const ReportingReport* earliest_queued = nullptr; + + for (const auto& it : reports_) { + const ReportingReport* report = it.first; + if (base::ContainsKey(pending_reports_, report)) + continue; + if (!earliest_queued || report->queued < earliest_queued->queued) { + earliest_queued = report; + } } + + return earliest_queued; } - size_t erased_last_used = client_last_used_.erase(client); - DCHECK_EQ(1u, erased_last_used); + void AddClient(std::unique_ptr<ReportingClient> client, + base::TimeTicks last_used) { + DCHECK(client); - size_t erased_endpoint = clients_[origin].erase(endpoint); - DCHECK_EQ(1u, erased_endpoint); - if (clients_[origin].empty()) { - size_t erased_origin = clients_.erase(origin); - DCHECK_EQ(1u, erased_origin); + url::Origin origin = client->origin; + GURL endpoint = client->endpoint; + + auto inserted_last_used = + client_last_used_.insert(std::make_pair(client.get(), last_used)); + DCHECK(inserted_last_used.second); + + if (client->subdomains == ReportingClient::Subdomains::INCLUDE) { + const std::string& domain = origin.host(); + auto inserted_wildcard_client = + wildcard_clients_[domain].insert(client.get()); + DCHECK(inserted_wildcard_client.second); + } + + auto inserted_client = + clients_[origin].insert(std::make_pair(endpoint, std::move(client))); + DCHECK(inserted_client.second); } -} -const ReportingClient* ReportingCache::GetClientByOriginAndEndpoint( - const url::Origin& origin, - const GURL& endpoint) const { - const auto& origin_it = clients_.find(origin); - if (origin_it == clients_.end()) - return nullptr; + void RemoveClient(const ReportingClient* client) { + DCHECK(client); - const auto& endpoint_it = origin_it->second.find(endpoint); - if (endpoint_it == origin_it->second.end()) - return nullptr; + url::Origin origin = client->origin; + GURL endpoint = client->endpoint; - return endpoint_it->second.get(); -} + if (client->subdomains == ReportingClient::Subdomains::INCLUDE) { + const std::string& domain = origin.host(); + size_t erased_wildcard_client = wildcard_clients_[domain].erase(client); + DCHECK_EQ(1u, erased_wildcard_client); + if (wildcard_clients_[domain].empty()) { + size_t erased_wildcard_domain = wildcard_clients_.erase(domain); + DCHECK_EQ(1u, erased_wildcard_domain); + } + } + + size_t erased_last_used = client_last_used_.erase(client); + DCHECK_EQ(1u, erased_last_used); + + size_t erased_endpoint = clients_[origin].erase(endpoint); + DCHECK_EQ(1u, erased_endpoint); + if (clients_[origin].empty()) { + size_t erased_origin = clients_.erase(origin); + DCHECK_EQ(1u, erased_origin); + } + } -void ReportingCache::GetWildcardClientsForDomainAndGroup( - const std::string& domain, - const std::string& group, - std::vector<const ReportingClient*>* clients_out) const { - clients_out->clear(); + const ReportingClient* GetClientByOriginAndEndpoint( + const url::Origin& origin, + const GURL& endpoint) const { + const auto& origin_it = clients_.find(origin); + if (origin_it == clients_.end()) + return nullptr; - auto it = wildcard_clients_.find(domain); - if (it == wildcard_clients_.end()) - return; + const auto& endpoint_it = origin_it->second.find(endpoint); + if (endpoint_it == origin_it->second.end()) + return nullptr; - for (const ReportingClient* client : it->second) { - DCHECK_EQ(ReportingClient::Subdomains::INCLUDE, client->subdomains); - if (client->group == group) - clients_out->push_back(client); + return endpoint_it->second.get(); } -} -const ReportingClient* ReportingCache::FindClientToEvict( - base::TimeTicks now) const { - DCHECK(!client_last_used_.empty()); - - const ReportingClient* earliest_used = nullptr; - base::TimeTicks earliest_used_last_used; - const ReportingClient* earliest_expired = nullptr; - - for (const auto& it : client_last_used_) { - const ReportingClient* client = it.first; - base::TimeTicks client_last_used = it.second; - if (earliest_used == nullptr || - client_last_used < earliest_used_last_used) { - earliest_used = client; - earliest_used_last_used = client_last_used; + void GetWildcardClientsForDomainAndGroup( + const std::string& domain, + const std::string& group, + std::vector<const ReportingClient*>* clients_out) const { + clients_out->clear(); + + auto it = wildcard_clients_.find(domain); + if (it == wildcard_clients_.end()) + return; + + for (const ReportingClient* client : it->second) { + DCHECK_EQ(ReportingClient::Subdomains::INCLUDE, client->subdomains); + if (client->group == group) + clients_out->push_back(client); } - if (earliest_expired == nullptr || - client->expires < earliest_expired->expires) { - earliest_expired = client; + } + + const ReportingClient* FindClientToEvict(base::TimeTicks now) const { + DCHECK(!client_last_used_.empty()); + + const ReportingClient* earliest_used = nullptr; + base::TimeTicks earliest_used_last_used; + const ReportingClient* earliest_expired = nullptr; + + for (const auto& it : client_last_used_) { + const ReportingClient* client = it.first; + base::TimeTicks client_last_used = it.second; + if (earliest_used == nullptr || + client_last_used < earliest_used_last_used) { + earliest_used = client; + earliest_used_last_used = client_last_used; + } + if (earliest_expired == nullptr || + client->expires < earliest_expired->expires) { + earliest_expired = client; + } } + + // If there are expired clients, return the earliest-expired. + if (earliest_expired->expires < now) + return earliest_expired; + else + return earliest_used; } +}; - // If there are expired clients, return the earliest-expired. - if (earliest_expired->expires < now) - return earliest_expired; - else - return earliest_used; -} +} // namespace -base::TickClock* ReportingCache::tick_clock() { - return context_->tick_clock(); +// static +std::unique_ptr<ReportingCache> ReportingCache::Create( + ReportingContext* context) { + return base::MakeUnique<ReportingCacheImpl>(context); } +ReportingCache::~ReportingCache() {} + } // namespace net diff --git a/chromium/net/reporting/reporting_cache.h b/chromium/net/reporting/reporting_cache.h index 1a5d31d8328..2cd4bb7172c 100644 --- a/chromium/net/reporting/reporting_cache.h +++ b/chromium/net/reporting/reporting_cache.h @@ -5,12 +5,7 @@ #ifndef NET_REPORTING_REPORTING_CACHE_H_ #define NET_REPORTING_REPORTING_CACHE_H_ -#include <map> #include <memory> -#include <set> -#include <string> -#include <unordered_map> -#include <unordered_set> #include <vector> #include "base/macros.h" @@ -19,17 +14,13 @@ #include "base/values.h" #include "net/base/net_export.h" #include "net/reporting/reporting_client.h" +#include "net/reporting/reporting_report.h" #include "url/gurl.h" #include "url/origin.h" -namespace base { -class TickClock; -} // namespace base - namespace net { class ReportingContext; -struct ReportingReport; // The cache holds undelivered reports and clients (per-origin endpoint // configurations) in memory. (It is not responsible for persisting them.) @@ -44,21 +35,20 @@ struct ReportingReport; // "doomed", which will cause it to be deallocated once it is no longer pending. class NET_EXPORT ReportingCache { public: - // |context| must outlive the ReportingCache. - ReportingCache(ReportingContext* context); + static std::unique_ptr<ReportingCache> Create(ReportingContext* context); - ~ReportingCache(); + virtual ~ReportingCache(); // Adds a report to the cache. // // All parameters correspond to the desired values for the relevant fields in // ReportingReport. - void AddReport(const GURL& url, - const std::string& group, - const std::string& type, - std::unique_ptr<const base::Value> body, - base::TimeTicks queued, - int attempts); + virtual void AddReport(const GURL& url, + const std::string& group, + const std::string& type, + std::unique_ptr<const base::Value> body, + base::TimeTicks queued, + int attempts) = 0; // Gets all reports in the cache. The returned pointers are valid as long as // either no calls to |RemoveReports| have happened or the reports' |pending| @@ -66,28 +56,32 @@ class NET_EXPORT ReportingCache { // doomed reports (pending reports for which removal has been requested). // // (Clears any existing data in |*reports_out|.) - void GetReports(std::vector<const ReportingReport*>* reports_out) const; + virtual void GetReports( + std::vector<const ReportingReport*>* reports_out) const = 0; // Marks a set of reports as pending. |reports| must not already be marked as // pending. - void SetReportsPending(const std::vector<const ReportingReport*>& reports); + virtual void SetReportsPending( + const std::vector<const ReportingReport*>& reports) = 0; // Unmarks a set of reports as pending. |reports| must be previously marked as // pending. - void ClearReportsPending(const std::vector<const ReportingReport*>& reports); + virtual void ClearReportsPending( + const std::vector<const ReportingReport*>& reports) = 0; // Increments |attempts| on a set of reports. - void IncrementReportsAttempts( - const std::vector<const ReportingReport*>& reports); + virtual void IncrementReportsAttempts( + const std::vector<const ReportingReport*>& reports) = 0; // Removes a set of reports. Any reports that are pending will not be removed // immediately, but rather marked doomed and removed once they are no longer // pending. - void RemoveReports(const std::vector<const ReportingReport*>& reports); + virtual void RemoveReports(const std::vector<const ReportingReport*>& reports, + ReportingReport::Outcome outcome) = 0; // Removes all reports. Like |RemoveReports()|, pending reports are doomed // until no longer pending. - void RemoveAllReports(); + virtual void RemoveAllReports(ReportingReport::Outcome outcome) = 0; // Creates or updates a client for a particular origin and a particular // endpoint. @@ -96,18 +90,20 @@ class NET_EXPORT ReportingCache { // |Client|. // // |endpoint| must use a cryptographic scheme. - void SetClient(const url::Origin& origin, - const GURL& endpoint, - ReportingClient::Subdomains subdomains, - const std::string& group, - base::TimeTicks expires); + virtual void SetClient(const url::Origin& origin, + const GURL& endpoint, + ReportingClient::Subdomains subdomains, + const std::string& group, + base::TimeTicks expires) = 0; - void MarkClientUsed(const url::Origin& origin, const GURL& endpoint); + virtual void MarkClientUsed(const url::Origin& origin, + const GURL& endpoint) = 0; // Gets all of the clients in the cache, regardless of origin or group. // // (Clears any existing data in |*clients_out|.) - void GetClients(std::vector<const ReportingClient*>* clients_out) const; + virtual void GetClients( + std::vector<const ReportingClient*>* clients_out) const = 0; // Gets all of the clients configured for a particular origin in a particular // group. The returned pointers are only guaranteed to be valid if no calls @@ -125,95 +121,43 @@ class NET_EXPORT ReportingCache { // etc. // // (Clears any existing data in |*clients_out|.) - void GetClientsForOriginAndGroup( + virtual void GetClientsForOriginAndGroup( const url::Origin& origin, const std::string& group, - std::vector<const ReportingClient*>* clients_out) const; + std::vector<const ReportingClient*>* clients_out) const = 0; // Removes a set of clients. // // May invalidate ReportingClient pointers returned by |GetClients| or // |GetClientsForOriginAndGroup|. - void RemoveClients(const std::vector<const ReportingClient*>& clients); + virtual void RemoveClients( + const std::vector<const ReportingClient*>& clients) = 0; // Removes a client for a particular origin and a particular endpoint. - void RemoveClientForOriginAndEndpoint(const url::Origin& origin, - const GURL& endpoint); + virtual void RemoveClientForOriginAndEndpoint(const url::Origin& origin, + const GURL& endpoint) = 0; // Removes all clients whose endpoint is |endpoint|. // // May invalidate ReportingClient pointers returned by |GetClients| or // |GetClientsForOriginAndGroup|. - void RemoveClientsForEndpoint(const GURL& endpoint); + virtual void RemoveClientsForEndpoint(const GURL& endpoint) = 0; // Removes all clients. - void RemoveAllClients(); + virtual void RemoveAllClients() = 0; // Gets the count of reports in the cache, *including* doomed reports. // // Needed to ensure that doomed reports are eventually deleted, since no // method provides a view of *every* report in the cache, just non-doomed // ones. - size_t GetFullReportCountForTesting() const { return reports_.size(); } - - bool IsReportPendingForTesting(const ReportingReport* report) const { - return base::ContainsKey(pending_reports_, report); - } - - bool IsReportDoomedForTesting(const ReportingReport* report) const { - return base::ContainsKey(doomed_reports_, report); - } - - private: - const ReportingReport* FindReportToEvict() const; - - void AddClient(std::unique_ptr<ReportingClient> client, - base::TimeTicks last_used); - - void RemoveClient(const ReportingClient* client); - - const ReportingClient* GetClientByOriginAndEndpoint( - const url::Origin& origin, - const GURL& endpoint) const; - - void GetWildcardClientsForDomainAndGroup( - const std::string& domain, - const std::string& group, - std::vector<const ReportingClient*>* clients_out) const; - - const ReportingClient* FindClientToEvict(base::TimeTicks now) const; - - base::TickClock* tick_clock(); - - ReportingContext* context_; - - // Owns all reports, keyed by const raw pointer for easier lookup. - std::unordered_map<const ReportingReport*, std::unique_ptr<ReportingReport>> - reports_; - - // Reports that have been marked pending (in use elsewhere and should not be - // deleted until no longer pending). - std::unordered_set<const ReportingReport*> pending_reports_; - - // Reports that have been marked doomed (would have been deleted, but were - // pending when the deletion was requested). - std::unordered_set<const ReportingReport*> doomed_reports_; - - // Owns all clients, keyed by origin, then endpoint URL. - // (These would be unordered_map, but neither url::Origin nor GURL has a hash - // function implemented.) - std::map<url::Origin, std::map<GURL, std::unique_ptr<ReportingClient>>> - clients_; - - // References but does not own all clients with includeSubdomains set, keyed - // by domain name. - std::unordered_map<std::string, std::unordered_set<const ReportingClient*>> - wildcard_clients_; + virtual size_t GetFullReportCountForTesting() const = 0; - // The time that each client has last been used. - std::unordered_map<const ReportingClient*, base::TimeTicks> client_last_used_; + virtual bool IsReportPendingForTesting( + const ReportingReport* report) const = 0; - DISALLOW_COPY_AND_ASSIGN(ReportingCache); + virtual bool IsReportDoomedForTesting( + const ReportingReport* report) const = 0; }; } // namespace net diff --git a/chromium/net/reporting/reporting_cache_unittest.cc b/chromium/net/reporting/reporting_cache_unittest.cc index eb2e158357e..d1924ff9400 100644 --- a/chromium/net/reporting/reporting_cache_unittest.cc +++ b/chromium/net/reporting/reporting_cache_unittest.cc @@ -108,7 +108,7 @@ TEST_F(ReportingCacheTest, Reports) { ASSERT_TRUE(report); EXPECT_EQ(1, report->attempts); - cache()->RemoveReports(reports); + cache()->RemoveReports(reports, ReportingReport::Outcome::UNKNOWN); EXPECT_EQ(3, observer()->cache_update_count()); cache()->GetReports(&reports); @@ -126,7 +126,7 @@ TEST_F(ReportingCacheTest, RemoveAllReports) { cache()->GetReports(&reports); EXPECT_EQ(2u, reports.size()); - cache()->RemoveAllReports(); + cache()->RemoveAllReports(ReportingReport::Outcome::UNKNOWN); EXPECT_EQ(3, observer()->cache_update_count()); cache()->GetReports(&reports); @@ -148,7 +148,7 @@ TEST_F(ReportingCacheTest, RemovePendingReports) { EXPECT_TRUE(cache()->IsReportPendingForTesting(reports[0])); EXPECT_FALSE(cache()->IsReportDoomedForTesting(reports[0])); - cache()->RemoveReports(reports); + cache()->RemoveReports(reports, ReportingReport::Outcome::UNKNOWN); EXPECT_TRUE(cache()->IsReportPendingForTesting(reports[0])); EXPECT_TRUE(cache()->IsReportDoomedForTesting(reports[0])); EXPECT_EQ(2, observer()->cache_update_count()); @@ -179,7 +179,7 @@ TEST_F(ReportingCacheTest, RemoveAllPendingReports) { EXPECT_TRUE(cache()->IsReportPendingForTesting(reports[0])); EXPECT_FALSE(cache()->IsReportDoomedForTesting(reports[0])); - cache()->RemoveAllReports(); + cache()->RemoveAllReports(ReportingReport::Outcome::UNKNOWN); EXPECT_TRUE(cache()->IsReportPendingForTesting(reports[0])); EXPECT_TRUE(cache()->IsReportDoomedForTesting(reports[0])); EXPECT_EQ(2, observer()->cache_update_count()); diff --git a/chromium/net/reporting/reporting_context.cc b/chromium/net/reporting/reporting_context.cc index 6d022be491d..5e3809a77a2 100644 --- a/chromium/net/reporting/reporting_context.cc +++ b/chromium/net/reporting/reporting_context.cc @@ -15,7 +15,6 @@ #include "base/time/tick_clock.h" #include "base/time/time.h" #include "net/base/backoff_entry.h" -#include "net/reporting/reporting_browsing_data_remover.h" #include "net/reporting/reporting_cache.h" #include "net/reporting/reporting_delegate.h" #include "net/reporting/reporting_delivery_agent.h" @@ -80,12 +79,11 @@ ReportingContext::ReportingContext(const ReportingPolicy& policy, tick_clock_(std::move(tick_clock)), uploader_(std::move(uploader)), delegate_(std::move(delegate)), - cache_(base::MakeUnique<ReportingCache>(this)), - endpoint_manager_(base::MakeUnique<ReportingEndpointManager>(this)), + cache_(ReportingCache::Create(this)), + endpoint_manager_(ReportingEndpointManager::Create(this)), delivery_agent_(ReportingDeliveryAgent::Create(this)), persister_(ReportingPersister::Create(this)), garbage_collector_(ReportingGarbageCollector::Create(this)), - network_change_observer_(ReportingNetworkChangeObserver::Create(this)), - browsing_data_remover_(ReportingBrowsingDataRemover::Create(this)) {} + network_change_observer_(ReportingNetworkChangeObserver::Create(this)) {} } // namespace net diff --git a/chromium/net/reporting/reporting_context.h b/chromium/net/reporting/reporting_context.h index 4467cb05197..139ca02dbc5 100644 --- a/chromium/net/reporting/reporting_context.h +++ b/chromium/net/reporting/reporting_context.h @@ -20,7 +20,6 @@ class TickClock; namespace net { -class ReportingBrowsingDataRemover; class ReportingCache; class ReportingDelegate; class ReportingDeliveryAgent; @@ -57,9 +56,6 @@ class NET_EXPORT ReportingContext { ReportingGarbageCollector* garbage_collector() { return garbage_collector_.get(); } - ReportingBrowsingDataRemover* browsing_data_remover() { - return browsing_data_remover_.get(); - } ReportingPersister* persister() { return persister_.get(); } @@ -104,9 +100,6 @@ class NET_EXPORT ReportingContext { // |network_change_observer_| must come after |cache_|. std::unique_ptr<ReportingNetworkChangeObserver> network_change_observer_; - // |browsing_data_remover_| must come after |cache_|. - std::unique_ptr<ReportingBrowsingDataRemover> browsing_data_remover_; - DISALLOW_COPY_AND_ASSIGN(ReportingContext); }; diff --git a/chromium/net/reporting/reporting_delivery_agent.cc b/chromium/net/reporting/reporting_delivery_agent.cc index 3d42797f4ff..38d601cca05 100644 --- a/chromium/net/reporting/reporting_delivery_agent.cc +++ b/chromium/net/reporting/reporting_delivery_agent.cc @@ -41,7 +41,7 @@ void SerializeReports(const std::vector<const ReportingReport*>& reports, report_value->SetInteger("age", (now - report->queued).InMilliseconds()); report_value->SetString("type", report->type); report_value->SetString("url", report->url.spec()); - report_value->Set("report", report->body->DeepCopy()); + report_value->Set("report", base::MakeUnique<base::Value>(*report->body)); reports_value.Append(std::move(report_value)); } @@ -170,7 +170,8 @@ class ReportingDeliveryAgentImpl : public ReportingDeliveryAgent, void OnUploadComplete(const std::unique_ptr<Delivery>& delivery, ReportingUploader::Outcome outcome) { if (outcome == ReportingUploader::Outcome::SUCCESS) { - cache()->RemoveReports(delivery->reports); + cache()->RemoveReports(delivery->reports, + ReportingReport::Outcome::DELIVERED); endpoint_manager()->InformOfEndpointRequest(delivery->endpoint, true); } else { cache()->IncrementReportsAttempts(delivery->reports); diff --git a/chromium/net/reporting/reporting_delivery_agent_unittest.cc b/chromium/net/reporting/reporting_delivery_agent_unittest.cc index c108c78c790..f1a575a2c99 100644 --- a/chromium/net/reporting/reporting_delivery_agent_unittest.cc +++ b/chromium/net/reporting/reporting_delivery_agent_unittest.cc @@ -178,7 +178,7 @@ TEST_F(ReportingDeliveryAgentTest, ConcurrentRemove) { EXPECT_FALSE(cache()->IsReportDoomedForTesting(report)); // Report should appear removed, even though the cache has doomed it. - cache()->RemoveReports(reports); + cache()->RemoveReports(reports, ReportingReport::Outcome::UNKNOWN); cache()->GetReports(&reports); EXPECT_TRUE(reports.empty()); EXPECT_TRUE(cache()->IsReportDoomedForTesting(report)); diff --git a/chromium/net/reporting/reporting_endpoint_manager.cc b/chromium/net/reporting/reporting_endpoint_manager.cc index f1fde5933eb..cd54026c79a 100644 --- a/chromium/net/reporting/reporting_endpoint_manager.cc +++ b/chromium/net/reporting/reporting_endpoint_manager.cc @@ -4,10 +4,13 @@ #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/memory/ptr_util.h" #include "base/rand_util.h" #include "base/stl_util.h" @@ -22,62 +25,91 @@ namespace net { -ReportingEndpointManager::ReportingEndpointManager(ReportingContext* context) - : context_(context) {} +namespace { -ReportingEndpointManager::~ReportingEndpointManager() {} +class ReportingEndpointManagerImpl : public ReportingEndpointManager { + public: + ReportingEndpointManagerImpl(ReportingContext* context) : context_(context) {} + + ~ReportingEndpointManagerImpl() override {} + + bool FindEndpointForOriginAndGroup(const url::Origin& origin, + const std::string& group, + GURL* endpoint_url_out) override { + std::vector<const ReportingClient*> clients; + cache()->GetClientsForOriginAndGroup(origin, group, &clients); + + // Filter out expired, pending, and backed-off endpoints. + std::vector<const ReportingClient*> available_clients; + base::TimeTicks now = tick_clock()->NowTicks(); + for (const ReportingClient* client : clients) { + if (client->expires < now) + continue; + if (base::ContainsKey(pending_endpoints_, client->endpoint)) + continue; + if (base::ContainsKey(endpoint_backoff_, client->endpoint) && + endpoint_backoff_[client->endpoint]->ShouldRejectRequest()) { + continue; + } + if (!delegate()->CanUseClient(client->origin, client->endpoint)) + continue; + available_clients.push_back(client); + } -bool ReportingEndpointManager::FindEndpointForOriginAndGroup( - const url::Origin& origin, - const std::string& group, - GURL* endpoint_url_out) { - std::vector<const ReportingClient*> clients; - cache()->GetClientsForOriginAndGroup(origin, group, &clients); - - // Filter out expired, pending, and backed-off endpoints. - std::vector<const ReportingClient*> available_clients; - base::TimeTicks now = tick_clock()->NowTicks(); - for (const ReportingClient* client : clients) { - if (client->expires < now) - continue; - if (base::ContainsKey(pending_endpoints_, client->endpoint)) - continue; - if (base::ContainsKey(endpoint_backoff_, client->endpoint) && - endpoint_backoff_[client->endpoint]->ShouldRejectRequest()) { - continue; + if (available_clients.empty()) { + *endpoint_url_out = GURL(); + return false; } - if (!delegate()->CanUseClient(client->origin, client->endpoint)) - continue; - available_clients.push_back(client); + + int random_index = base::RandInt(0, available_clients.size() - 1); + *endpoint_url_out = available_clients[random_index]->endpoint; + return true; } - if (available_clients.empty()) { - *endpoint_url_out = GURL(); - return false; + void SetEndpointPending(const GURL& endpoint) override { + DCHECK(!base::ContainsKey(pending_endpoints_, endpoint)); + pending_endpoints_.insert(endpoint); } - int random_index = base::RandInt(0, available_clients.size() - 1); - *endpoint_url_out = available_clients[random_index]->endpoint; - return true; -} + void ClearEndpointPending(const GURL& endpoint) override { + DCHECK(base::ContainsKey(pending_endpoints_, endpoint)); + pending_endpoints_.erase(endpoint); + } -void ReportingEndpointManager::SetEndpointPending(const GURL& endpoint) { - DCHECK(!base::ContainsKey(pending_endpoints_, endpoint)); - pending_endpoints_.insert(endpoint); -} + void InformOfEndpointRequest(const GURL& endpoint, bool succeeded) override { + if (!base::ContainsKey(endpoint_backoff_, endpoint)) { + endpoint_backoff_[endpoint] = base::MakeUnique<BackoffEntry>( + &policy().endpoint_backoff_policy, tick_clock()); + } + endpoint_backoff_[endpoint]->InformOfRequest(succeeded); + } -void ReportingEndpointManager::ClearEndpointPending(const GURL& endpoint) { - DCHECK(base::ContainsKey(pending_endpoints_, endpoint)); - pending_endpoints_.erase(endpoint); -} + private: + const ReportingPolicy& policy() { return context_->policy(); } + base::TickClock* tick_clock() { return context_->tick_clock(); } + ReportingDelegate* delegate() { return context_->delegate(); } + ReportingCache* cache() { return context_->cache(); } -void ReportingEndpointManager::InformOfEndpointRequest(const GURL& endpoint, - bool succeeded) { - if (!base::ContainsKey(endpoint_backoff_, endpoint)) { - endpoint_backoff_[endpoint] = base::MakeUnique<BackoffEntry>( - &policy().endpoint_backoff_policy, tick_clock()); - } - endpoint_backoff_[endpoint]->InformOfRequest(succeeded); + ReportingContext* context_; + + std::set<GURL> pending_endpoints_; + + // 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) { + return base::MakeUnique<ReportingEndpointManagerImpl>(context); } +ReportingEndpointManager::~ReportingEndpointManager() {} + } // namespace net diff --git a/chromium/net/reporting/reporting_endpoint_manager.h b/chromium/net/reporting/reporting_endpoint_manager.h index e7819e101ae..1f35198479a 100644 --- a/chromium/net/reporting/reporting_endpoint_manager.h +++ b/chromium/net/reporting/reporting_endpoint_manager.h @@ -5,41 +5,31 @@ #ifndef NET_REPORTING_REPORTING_ENDPOINT_MANAGER_H_ #define NET_REPORTING_REPORTING_ENDPOINT_MANAGER_H_ -#include <map> #include <memory> -#include <set> #include <string> #include "base/macros.h" -#include "base/time/tick_clock.h" -#include "net/base/backoff_entry.h" #include "net/base/net_export.h" #include "net/reporting/reporting_context.h" class GURL; -namespace base { -class TickClock; -} // namespace base - namespace url { class Origin; } // namespace url namespace net { -class ReportingCache; -class ReportingDelegate; -struct ReportingPolicy; - // Keeps track of which endpoints are pending (have active delivery attempts to // them) or in exponential backoff after one or more failures, and chooses an // endpoint from an endpoint group to receive reports for an origin. class NET_EXPORT ReportingEndpointManager { public: // |context| must outlive the ReportingEndpointManager. - ReportingEndpointManager(ReportingContext* context); - ~ReportingEndpointManager(); + static std::unique_ptr<ReportingEndpointManager> Create( + ReportingContext* context); + + virtual ~ReportingEndpointManager(); // Finds an endpoint configured by |origin| in group |group| that is not // pending, in exponential backoff from failed requests, or expired. @@ -50,37 +40,21 @@ class NET_EXPORT ReportingEndpointManager { // Returns true and sets |*endpoint_url_out| to the endpoint URL if an // endpoint was chosen; returns false (and leaves |*endpoint_url_out| invalid) // if no endpoint was found. - bool FindEndpointForOriginAndGroup(const url::Origin& origin, - const std::string& group, - GURL* endpoint_url_out); + virtual bool FindEndpointForOriginAndGroup(const url::Origin& origin, + const std::string& group, + GURL* endpoint_url_out) = 0; // Adds |endpoint| to the set of pending endpoints, preventing it from being // chosen for a second parallel delivery attempt. - void SetEndpointPending(const GURL& endpoint); + virtual void SetEndpointPending(const GURL& endpoint) = 0; // Removes |endpoint| from the set of pending endpoints. - void ClearEndpointPending(const GURL& endpoint); + virtual void ClearEndpointPending(const GURL& endpoint) = 0; // Informs the EndpointManager of a successful or unsuccessful request made to // |endpoint| so it can manage exponential backoff of failing endpoints. - void InformOfEndpointRequest(const GURL& endpoint, bool succeeded); - - private: - const ReportingPolicy& policy() { return context_->policy(); } - base::TickClock* tick_clock() { return context_->tick_clock(); } - ReportingDelegate* delegate() { return context_->delegate(); } - ReportingCache* cache() { return context_->cache(); } - - ReportingContext* context_; - - std::set<GURL> pending_endpoints_; - - // 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(ReportingEndpointManager); + virtual void InformOfEndpointRequest(const GURL& endpoint, + bool succeeded) = 0; }; } // namespace net diff --git a/chromium/net/reporting/reporting_feature.h b/chromium/net/reporting/reporting_feature.h index eae3cfb77d8..4bd3d39e81e 100644 --- a/chromium/net/reporting/reporting_feature.h +++ b/chromium/net/reporting/reporting_feature.h @@ -14,4 +14,4 @@ extern const base::Feature NET_EXPORT kReporting; } // namespace features -#endif +#endif // NET_REPORTING_REPORTING_FEATURE_H_ diff --git a/chromium/net/reporting/reporting_garbage_collector.cc b/chromium/net/reporting/reporting_garbage_collector.cc index 50e6d562057..188cda1e46c 100644 --- a/chromium/net/reporting/reporting_garbage_collector.cc +++ b/chromium/net/reporting/reporting_garbage_collector.cc @@ -57,17 +57,21 @@ class ReportingGarbageCollectorImpl : public ReportingGarbageCollector, std::vector<const ReportingReport*> all_reports; context_->cache()->GetReports(&all_reports); - std::vector<const ReportingReport*> reports_to_remove; + std::vector<const ReportingReport*> failed_reports; + std::vector<const ReportingReport*> expired_reports; for (const ReportingReport* report : all_reports) { - if (now - report->queued >= policy.max_report_age || - report->attempts >= policy.max_report_attempts) { - reports_to_remove.push_back(report); - } + if (report->attempts >= policy.max_report_attempts) + failed_reports.push_back(report); + else if (now - report->queued >= policy.max_report_age) + expired_reports.push_back(report); } // Don't restart the timer on the garbage collector's own updates. context_->RemoveObserver(this); - context_->cache()->RemoveReports(reports_to_remove); + context_->cache()->RemoveReports(failed_reports, + ReportingReport::Outcome::ERASED_FAILED); + context_->cache()->RemoveReports(expired_reports, + ReportingReport::Outcome::ERASED_EXPIRED); context_->AddObserver(this); } diff --git a/chromium/net/reporting/reporting_header_parser.cc b/chromium/net/reporting/reporting_header_parser.cc index 8a0c7b2b9c1..058b33548b2 100644 --- a/chromium/net/reporting/reporting_header_parser.cc +++ b/chromium/net/reporting/reporting_header_parser.cc @@ -8,6 +8,7 @@ #include "base/json/json_reader.h" #include "base/logging.h" +#include "base/metrics/histogram_macros.h" #include "base/time/tick_clock.h" #include "base/time/time.h" #include "base/values.h" @@ -19,39 +20,82 @@ namespace net { namespace { +enum class HeaderOutcome { + DISCARDED_NO_REPORTING_SERVICE = 0, + DISCARDED_INVALID_SSL_INFO = 1, + DISCARDED_CERT_STATUS_ERROR = 2, + DISCARDED_INVALID_JSON = 3, + PARSED = 4, + + MAX +}; + +void RecordHeaderOutcome(HeaderOutcome outcome) { + UMA_HISTOGRAM_ENUMERATION("Reporting.HeaderOutcome", outcome, + HeaderOutcome::MAX); +} + +enum class HeaderEndpointOutcome { + DISCARDED_NOT_DICTIONARY = 0, + DISCARDED_ENDPOINT_MISSING = 1, + DISCARDED_ENDPOINT_NOT_STRING = 2, + DISCARDED_ENDPOINT_INVALID = 3, + DISCARDED_ENDPOINT_INSECURE = 4, + DISCARDED_TTL_MISSING = 5, + DISCARDED_TTL_NOT_INTEGER = 6, + DISCARDED_TTL_NEGATIVE = 7, + DISCARDED_GROUP_NOT_STRING = 8, + REMOVED = 9, + SET_REJECTED_BY_DELEGATE = 10, + SET = 11, + + MAX +}; + +void RecordHeaderEndpointOutcome(HeaderEndpointOutcome outcome) { + UMA_HISTOGRAM_ENUMERATION("Reporting.HeaderEndpointOutcome", outcome, + HeaderEndpointOutcome::MAX); +} + const char kUrlKey[] = "url"; const char kIncludeSubdomainsKey[] = "includeSubdomains"; const char kGroupKey[] = "group"; const char kGroupDefaultValue[] = "default"; const char kMaxAgeKey[] = "max-age"; -void ProcessEndpoint(ReportingDelegate* delegate, - ReportingCache* cache, - base::TimeTicks now, - const GURL& url, - const base::Value& value) { +HeaderEndpointOutcome ProcessEndpoint(ReportingDelegate* delegate, + ReportingCache* cache, + base::TimeTicks now, + const GURL& url, + const base::Value& value) { const base::DictionaryValue* dict = nullptr; if (!value.GetAsDictionary(&dict)) - return; + return HeaderEndpointOutcome::DISCARDED_NOT_DICTIONARY; DCHECK(dict); std::string endpoint_url_string; + if (!dict->HasKey(kUrlKey)) + return HeaderEndpointOutcome::DISCARDED_ENDPOINT_MISSING; if (!dict->GetString(kUrlKey, &endpoint_url_string)) - return; + return HeaderEndpointOutcome::DISCARDED_ENDPOINT_NOT_STRING; GURL endpoint_url(endpoint_url_string); if (!endpoint_url.is_valid()) - return; + return HeaderEndpointOutcome::DISCARDED_ENDPOINT_INVALID; if (!endpoint_url.SchemeIsCryptographic()) - return; + return HeaderEndpointOutcome::DISCARDED_ENDPOINT_INSECURE; int ttl_sec = -1; - if (!dict->GetInteger(kMaxAgeKey, &ttl_sec) || ttl_sec < 0) - return; + if (!dict->HasKey(kMaxAgeKey)) + return HeaderEndpointOutcome::DISCARDED_TTL_MISSING; + if (!dict->GetInteger(kMaxAgeKey, &ttl_sec)) + return HeaderEndpointOutcome::DISCARDED_TTL_NOT_INTEGER; + if (ttl_sec < 0) + return HeaderEndpointOutcome::DISCARDED_TTL_NEGATIVE; std::string group = kGroupDefaultValue; if (dict->HasKey(kGroupKey) && !dict->GetString(kGroupKey, &group)) - return; + return HeaderEndpointOutcome::DISCARDED_GROUP_NOT_STRING; ReportingClient::Subdomains subdomains = ReportingClient::Subdomains::EXCLUDE; bool subdomains_bool = false; @@ -61,22 +105,38 @@ void ProcessEndpoint(ReportingDelegate* delegate, subdomains = ReportingClient::Subdomains::INCLUDE; } - url::Origin origin(url); + if (ttl_sec == 0) { + cache->RemoveClientForOriginAndEndpoint(url::Origin(url), endpoint_url); + return HeaderEndpointOutcome::REMOVED; + } + url::Origin origin(url); if (!delegate->CanSetClient(origin, endpoint_url)) - return; + return HeaderEndpointOutcome::SET_REJECTED_BY_DELEGATE; - if (ttl_sec > 0) { - cache->SetClient(origin, endpoint_url, subdomains, group, - now + base::TimeDelta::FromSeconds(ttl_sec)); - } else { - cache->RemoveClientForOriginAndEndpoint(origin, endpoint_url); - } + cache->SetClient(origin, endpoint_url, subdomains, group, + now + base::TimeDelta::FromSeconds(ttl_sec)); + return HeaderEndpointOutcome::SET; } } // namespace // static +void ReportingHeaderParser::RecordHeaderDiscardedForNoReportingService() { + RecordHeaderOutcome(HeaderOutcome::DISCARDED_NO_REPORTING_SERVICE); +} + +// static +void ReportingHeaderParser::RecordHeaderDiscardedForInvalidSSLInfo() { + RecordHeaderOutcome(HeaderOutcome::DISCARDED_INVALID_SSL_INFO); +} + +// static +void ReportingHeaderParser::RecordHeaderDiscardedForCertStatusError() { + RecordHeaderOutcome(HeaderOutcome::DISCARDED_CERT_STATUS_ERROR); +} + +// static void ReportingHeaderParser::ParseHeader(ReportingContext* context, const GURL& url, const std::string& json_value) { @@ -84,8 +144,10 @@ void ReportingHeaderParser::ParseHeader(ReportingContext* context, std::unique_ptr<base::Value> value = base::JSONReader::Read("[" + json_value + "]"); - if (!value) + if (!value) { + RecordHeaderOutcome(HeaderOutcome::DISCARDED_INVALID_JSON); return; + } const base::ListValue* list = nullptr; bool is_list = value->GetAsList(&list); @@ -98,7 +160,8 @@ void ReportingHeaderParser::ParseHeader(ReportingContext* context, const base::Value* endpoint = nullptr; bool got_endpoint = list->Get(i, &endpoint); DCHECK(got_endpoint); - ProcessEndpoint(delegate, cache, now, url, *endpoint); + RecordHeaderEndpointOutcome( + ProcessEndpoint(delegate, cache, now, url, *endpoint)); } } diff --git a/chromium/net/reporting/reporting_header_parser.h b/chromium/net/reporting/reporting_header_parser.h index fc165f31116..c94f0537227 100644 --- a/chromium/net/reporting/reporting_header_parser.h +++ b/chromium/net/reporting/reporting_header_parser.h @@ -18,6 +18,10 @@ class ReportingContext; class NET_EXPORT ReportingHeaderParser { public: + static void RecordHeaderDiscardedForNoReportingService(); + static void RecordHeaderDiscardedForInvalidSSLInfo(); + static void RecordHeaderDiscardedForCertStatusError(); + static void ParseHeader(ReportingContext* context, const GURL& url, const std::string& json_value); diff --git a/chromium/net/reporting/reporting_network_change_observer.cc b/chromium/net/reporting/reporting_network_change_observer.cc index 6c62b7f57a4..99bb5a66f8a 100644 --- a/chromium/net/reporting/reporting_network_change_observer.cc +++ b/chromium/net/reporting/reporting_network_change_observer.cc @@ -9,6 +9,7 @@ #include "net/reporting/reporting_cache.h" #include "net/reporting/reporting_context.h" #include "net/reporting/reporting_policy.h" +#include "net/reporting/reporting_report.h" namespace net { @@ -38,7 +39,8 @@ class ReportingNetworkChangeObserverImpl return; if (context_->policy().clear_reports_on_network_changes) - context_->cache()->RemoveAllReports(); + context_->cache()->RemoveAllReports( + ReportingReport::Outcome::ERASED_NETWORK_CHANGED); if (context_->policy().clear_clients_on_network_changes) context_->cache()->RemoveAllClients(); diff --git a/chromium/net/reporting/reporting_report.cc b/chromium/net/reporting/reporting_report.cc index b039bc1cd41..37c4a22bd3d 100644 --- a/chromium/net/reporting/reporting_report.cc +++ b/chromium/net/reporting/reporting_report.cc @@ -8,12 +8,22 @@ #include <string> #include <utility> +#include "base/metrics/histogram_macros.h" #include "base/time/time.h" #include "base/values.h" #include "url/gurl.h" namespace net { +namespace { + +void RecordReportOutcome(ReportingReport::Outcome outcome) { + UMA_HISTOGRAM_ENUMERATION("Reporting.ReportOutcome", outcome, + ReportingReport::Outcome::MAX); +} + +} // namespace + ReportingReport::ReportingReport(const GURL& url, const std::string& group, const std::string& type, @@ -25,8 +35,36 @@ ReportingReport::ReportingReport(const GURL& url, type(type), body(std::move(body)), queued(queued), - attempts(attempts) {} + attempts(attempts), + outcome(Outcome::UNKNOWN), + recorded_outcome(false) {} + +ReportingReport::~ReportingReport() { + DCHECK(recorded_outcome); +} + +// static +void ReportingReport::RecordReportDiscardedForNoURLRequestContext() { + RecordReportOutcome(Outcome::DISCARDED_NO_URL_REQUEST_CONTEXT); +} + +// static +void ReportingReport::RecordReportDiscardedForNoReportingService() { + RecordReportOutcome(Outcome::DISCARDED_NO_REPORTING_SERVICE); +} + +void ReportingReport::RecordOutcome(base::TimeTicks now) { + DCHECK(!recorded_outcome); + + RecordReportOutcome(outcome); + + if (outcome == Outcome::DELIVERED) { + UMA_HISTOGRAM_LONG_TIMES_100("Reporting.ReportDeliveredLatency", + now - queued); + UMA_HISTOGRAM_COUNTS_100("Reporting.ReportDeliveredAttempts", attempts); + } -ReportingReport::~ReportingReport() {} + recorded_outcome = true; +} } // namespace net diff --git a/chromium/net/reporting/reporting_report.h b/chromium/net/reporting/reporting_report.h index b1b310171f9..e7fba5d5950 100644 --- a/chromium/net/reporting/reporting_report.h +++ b/chromium/net/reporting/reporting_report.h @@ -21,6 +21,22 @@ namespace net { // An undelivered report. struct NET_EXPORT ReportingReport { public: + // Used in histograms; please add new items at end and do not reorder. + enum class Outcome { + UNKNOWN = 0, + DISCARDED_NO_URL_REQUEST_CONTEXT = 1, + DISCARDED_NO_REPORTING_SERVICE = 2, + ERASED_FAILED = 3, + ERASED_EXPIRED = 4, + ERASED_EVICTED = 5, + ERASED_NETWORK_CHANGED = 6, + ERASED_BROWSING_DATA_REMOVED = 7, + ERASED_REPORTING_SHUT_DOWN = 8, + DELIVERED = 9, + + MAX + }; + ReportingReport(const GURL& url, const std::string& group, const std::string& type, @@ -29,6 +45,11 @@ struct NET_EXPORT ReportingReport { int attempts); ~ReportingReport(); + static void RecordReportDiscardedForNoURLRequestContext(); + static void RecordReportDiscardedForNoReportingService(); + + void RecordOutcome(base::TimeTicks now); + // The URL of the document that triggered the report. (Included in the // delivered report.) GURL url; @@ -51,7 +72,11 @@ struct NET_EXPORT ReportingReport { // attempt. (Not included in the delivered report.) int attempts = 0; + Outcome outcome; + private: + bool recorded_outcome; + DISALLOW_COPY_AND_ASSIGN(ReportingReport); }; diff --git a/chromium/net/reporting/reporting_service.cc b/chromium/net/reporting/reporting_service.cc index 7a548ad3ee5..8be14d66ba6 100644 --- a/chromium/net/reporting/reporting_service.cc +++ b/chromium/net/reporting/reporting_service.cc @@ -51,8 +51,8 @@ class ReportingServiceImpl : public ReportingService { void RemoveBrowsingData( int data_type_mask, base::Callback<bool(const GURL&)> origin_filter) override { - context_->browsing_data_remover()->RemoveBrowsingData(data_type_mask, - origin_filter); + ReportingBrowsingDataRemover::RemoveBrowsingData( + context_->cache(), data_type_mask, origin_filter); } private: diff --git a/chromium/net/reporting/reporting_test_util.h b/chromium/net/reporting/reporting_test_util.h index 9343278954d..488284ee7e5 100644 --- a/chromium/net/reporting/reporting_test_util.h +++ b/chromium/net/reporting/reporting_test_util.h @@ -30,7 +30,6 @@ class Origin; namespace net { -class ReportingBrowsingDataRemover; class ReportingCache; struct ReportingClient; class ReportingGarbageCollector; @@ -172,9 +171,6 @@ class ReportingTestBase : public ::testing::Test { ReportingGarbageCollector* garbage_collector() { return context_->garbage_collector(); } - ReportingBrowsingDataRemover* browsing_data_remover() { - return context_->browsing_data_remover(); - } ReportingPersister* persister() { return context_->persister(); } @@ -199,4 +195,4 @@ class ReportingTestBase : public ::testing::Test { } // namespace net -#endif // NET_REPORING_REPORTING_TEST_UTIL_H_ +#endif // NET_REPORTING_REPORTING_TEST_UTIL_H_ |