Chromium Code Reviews| Index: chrome/browser/ssl/certificate_reporting_service.cc |
| diff --git a/chrome/browser/ssl/certificate_reporting_service.cc b/chrome/browser/ssl/certificate_reporting_service.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4f45f9d951b115ab3e53592e618a45736ceee891 |
| --- /dev/null |
| +++ b/chrome/browser/ssl/certificate_reporting_service.cc |
| @@ -0,0 +1,128 @@ |
| +// Copyright 2016 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 "base/time/clock.h" |
| +#include "base/time/default_clock.h" |
| +#include "chrome/browser/ssl/certificate_reporting_service.h" |
| +#include "content/public/browser/browser_thread.h" |
| + |
| +namespace { |
| +// First item is ordered before the second item if it's newer. |
| +bool ReportCompareFunc(const CertificateReportingService::Report& item1, |
| + const CertificateReportingService::Report& item2) { |
| + return item1.creation_time > item2.creation_time; |
| +} |
| + |
| +} // namespace |
| + |
| +void CertificateReportingService::BoundedReportList::Add(const Report& item) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + DCHECK(items_.size() <= max_size_); |
| + if (items_.size() == max_size_) { |
| + const Report& last = items_.back(); |
| + if (item.creation_time <= last.creation_time) { |
| + // Report older than the oldest item in the queue, ignore. |
|
estark
2016/11/19 00:29:52
The comments in this function are helpful 👍
|
| + return; |
| + } |
| + // Reached the maximum item count, remove the oldest item. |
| + items_.pop_back(); |
| + } |
| + items_.push_back(item); |
| + std::sort(items_.begin(), items_.end(), ReportCompareFunc); |
| +} |
| + |
| +CertificateReportingService::BoundedReportList::BoundedReportList( |
| + size_t max_size) |
| + : max_size_(max_size) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| +} |
| + |
| +void CertificateReportingService::BoundedReportList::Clear() { |
| + items_.clear(); |
| +} |
| + |
| +CertificateReportingService::BoundedReportList::~BoundedReportList() {} |
| + |
| +const std::vector<CertificateReportingService::Report>& |
| +CertificateReportingService::BoundedReportList::items() const { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + return items_; |
| +} |
| + |
| +CertificateReportingService::Reporter::Reporter( |
| + std::unique_ptr<certificate_reporting::ErrorReporter> error_reporter, |
| + std::unique_ptr<BoundedReportList> retry_list, |
| + base::Clock* clock, |
| + base::TimeDelta max_item_age) |
| + : error_reporter_(std::move(error_reporter)), |
| + retry_list_(std::move(retry_list)), |
| + test_clock_(clock), |
| + max_item_age_(max_item_age), |
| + current_report_id_(0), |
| + weak_factory_(this) {} |
| + |
| +void CertificateReportingService::Reporter::Send( |
| + const std::string& serialized_report) { |
| + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| + base::Time now = |
| + test_clock_ ? test_clock_->Now() : base::Time::NowFromSystemTime(); |
| + SendInternal(Report(current_report_id_++, now, serialized_report)); |
| +} |
| + |
| +void CertificateReportingService::Reporter::SendPending() { |
| + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| + base::Time now = |
| + test_clock_ ? test_clock_->Now() : base::Time::NowFromSystemTime(); |
| + // Copy pending reports and clear the retry list. |
| + std::vector<Report> items = retry_list_->items(); |
| + retry_list_->Clear(); |
| + for (const Report& report : items) { |
| + if (report.creation_time < now - max_item_age_) { |
| + // Report too old, ignore. |
| + continue; |
| + } |
| + SendInternal(report); |
| + } |
| + retry_list_->Clear(); |
| +} |
| + |
| +size_t |
| +CertificateReportingService::Reporter::inflight_report_count_for_testing() |
| + const { |
| + return inflight_reports_.size(); |
| +} |
| + |
| +CertificateReportingService::BoundedReportList* |
| +CertificateReportingService::Reporter::GetQueueForTesting() const { |
| + return retry_list_.get(); |
| +} |
| + |
| +CertificateReportingService::Reporter::~Reporter() {} |
| + |
| +void CertificateReportingService::Reporter::SendInternal( |
| + const CertificateReportingService::Report& report) { |
| + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| + inflight_reports_.insert(std::make_pair(report.report_id, report)); |
| + error_reporter_->SendExtendedReportingReport( |
| + report.serialized_report, |
| + base::Bind(&CertificateReportingService::Reporter::SuccessCallback, |
| + weak_factory_.GetWeakPtr(), report.report_id), |
| + base::Bind(&CertificateReportingService::Reporter::ErrorCallback, |
| + weak_factory_.GetWeakPtr(), report.report_id)); |
| +} |
| + |
| +void CertificateReportingService::Reporter::ErrorCallback(int report_id, |
| + const GURL& url, |
| + int error) { |
| + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| + auto it = inflight_reports_.find(report_id); |
| + DCHECK(it != inflight_reports_.end()); |
| + retry_list_->Add(it->second); |
| + CHECK_GT(inflight_reports_.erase(report_id), 0u); |
| +} |
| + |
| +void CertificateReportingService::Reporter::SuccessCallback(int report_id) { |
| + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| + CHECK_GT(inflight_reports_.erase(report_id), 0u); |
| +} |