| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/bind_helpers.h" |
| 5 #include "base/time/clock.h" | 6 #include "base/time/clock.h" |
| 6 #include "base/time/default_clock.h" | 7 #include "base/time/default_clock.h" |
| 7 #include "chrome/browser/safe_browsing/certificate_reporting_service.h" | 8 #include "chrome/browser/safe_browsing/certificate_reporting_service.h" |
| 8 #include "content/public/browser/browser_thread.h" | 9 #include "content/public/browser/browser_thread.h" |
| 9 | 10 |
| 10 namespace { | 11 namespace { |
| 12 |
| 13 // URL to upload invalid certificate chain reports. An HTTP URL is used because |
| 14 // a client seeing an invalid cert might not be able to make an HTTPS connection |
| 15 // to report it. |
| 16 const char kExtendedReportingUploadUrl[] = |
| 17 "http://safebrowsing.googleusercontent.com/safebrowsing/clientreport/"; |
| 18 |
| 11 // Compare function that orders Reports in reverse chronological order (i.e. | 19 // Compare function that orders Reports in reverse chronological order (i.e. |
| 12 // oldest item is last). | 20 // oldest item is last). |
| 13 bool ReportCompareFunc(const CertificateReportingService::Report& item1, | 21 bool ReportCompareFunc(const CertificateReportingService::Report& item1, |
| 14 const CertificateReportingService::Report& item2) { | 22 const CertificateReportingService::Report& item2) { |
| 15 return item1.creation_time > item2.creation_time; | 23 return item1.creation_time > item2.creation_time; |
| 16 } | 24 } |
| 17 | 25 |
| 18 } // namespace | 26 } // namespace |
| 19 | 27 |
| 20 CertificateReportingService::BoundedReportList::BoundedReportList( | 28 CertificateReportingService::BoundedReportList::BoundedReportList( |
| (...skipping 29 matching lines...) Expand all Loading... |
| 50 const std::vector<CertificateReportingService::Report>& | 58 const std::vector<CertificateReportingService::Report>& |
| 51 CertificateReportingService::BoundedReportList::items() const { | 59 CertificateReportingService::BoundedReportList::items() const { |
| 52 DCHECK(thread_checker_.CalledOnValidThread()); | 60 DCHECK(thread_checker_.CalledOnValidThread()); |
| 53 return items_; | 61 return items_; |
| 54 } | 62 } |
| 55 | 63 |
| 56 CertificateReportingService::Reporter::Reporter( | 64 CertificateReportingService::Reporter::Reporter( |
| 57 std::unique_ptr<certificate_reporting::ErrorReporter> error_reporter, | 65 std::unique_ptr<certificate_reporting::ErrorReporter> error_reporter, |
| 58 std::unique_ptr<BoundedReportList> retry_list, | 66 std::unique_ptr<BoundedReportList> retry_list, |
| 59 base::Clock* clock, | 67 base::Clock* clock, |
| 60 base::TimeDelta report_ttl) | 68 base::TimeDelta report_ttl, |
| 69 bool retries_enabled) |
| 61 : error_reporter_(std::move(error_reporter)), | 70 : error_reporter_(std::move(error_reporter)), |
| 62 retry_list_(std::move(retry_list)), | 71 retry_list_(std::move(retry_list)), |
| 63 test_clock_(clock), | 72 clock_(clock), |
| 64 report_ttl_(report_ttl), | 73 report_ttl_(report_ttl), |
| 74 retries_enabled_(retries_enabled), |
| 65 current_report_id_(0), | 75 current_report_id_(0), |
| 66 weak_factory_(this) {} | 76 weak_factory_(this) {} |
| 67 | 77 |
| 68 CertificateReportingService::Reporter::~Reporter() {} | 78 CertificateReportingService::Reporter::~Reporter() {} |
| 69 | 79 |
| 70 void CertificateReportingService::Reporter::Send( | 80 void CertificateReportingService::Reporter::Send( |
| 71 const std::string& serialized_report) { | 81 const std::string& serialized_report) { |
| 72 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 82 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 73 base::Time now = | 83 SendInternal(Report(current_report_id_++, clock_->Now(), serialized_report)); |
| 74 test_clock_ ? test_clock_->Now() : base::Time::NowFromSystemTime(); | |
| 75 SendInternal(Report(current_report_id_++, now, serialized_report)); | |
| 76 } | 84 } |
| 77 | 85 |
| 78 void CertificateReportingService::Reporter::SendPending() { | 86 void CertificateReportingService::Reporter::SendPending() { |
| 79 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 87 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 80 base::Time now = | 88 if (!retries_enabled_) { |
| 81 test_clock_ ? test_clock_->Now() : base::Time::NowFromSystemTime(); | 89 return; |
| 90 } |
| 91 const base::Time now = clock_->Now(); |
| 82 // Copy pending reports and clear the retry list. | 92 // Copy pending reports and clear the retry list. |
| 83 std::vector<Report> items = retry_list_->items(); | 93 std::vector<Report> items = retry_list_->items(); |
| 84 retry_list_->Clear(); | 94 retry_list_->Clear(); |
| 85 for (const Report& report : items) { | 95 for (const Report& report : items) { |
| 86 if (report.creation_time < now - report_ttl_) { | 96 if (report.creation_time < now - report_ttl_) { |
| 87 // Report too old, ignore. | 97 // Report too old, ignore. |
| 88 continue; | 98 continue; |
| 89 } | 99 } |
| 90 SendInternal(report); | 100 SendInternal(report); |
| 91 } | 101 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 111 base::Bind(&CertificateReportingService::Reporter::SuccessCallback, | 121 base::Bind(&CertificateReportingService::Reporter::SuccessCallback, |
| 112 weak_factory_.GetWeakPtr(), report.report_id), | 122 weak_factory_.GetWeakPtr(), report.report_id), |
| 113 base::Bind(&CertificateReportingService::Reporter::ErrorCallback, | 123 base::Bind(&CertificateReportingService::Reporter::ErrorCallback, |
| 114 weak_factory_.GetWeakPtr(), report.report_id)); | 124 weak_factory_.GetWeakPtr(), report.report_id)); |
| 115 } | 125 } |
| 116 | 126 |
| 117 void CertificateReportingService::Reporter::ErrorCallback(int report_id, | 127 void CertificateReportingService::Reporter::ErrorCallback(int report_id, |
| 118 const GURL& url, | 128 const GURL& url, |
| 119 int error) { | 129 int error) { |
| 120 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 130 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 121 auto it = inflight_reports_.find(report_id); | 131 if (retries_enabled_) { |
| 122 DCHECK(it != inflight_reports_.end()); | 132 auto it = inflight_reports_.find(report_id); |
| 123 retry_list_->Add(it->second); | 133 DCHECK(it != inflight_reports_.end()); |
| 134 retry_list_->Add(it->second); |
| 135 } |
| 124 CHECK_GT(inflight_reports_.erase(report_id), 0u); | 136 CHECK_GT(inflight_reports_.erase(report_id), 0u); |
| 125 } | 137 } |
| 126 | 138 |
| 127 void CertificateReportingService::Reporter::SuccessCallback(int report_id) { | 139 void CertificateReportingService::Reporter::SuccessCallback(int report_id) { |
| 128 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 140 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 129 CHECK_GT(inflight_reports_.erase(report_id), 0u); | 141 CHECK_GT(inflight_reports_.erase(report_id), 0u); |
| 130 } | 142 } |
| 143 |
| 144 CertificateReportingService::CertificateReportingService( |
| 145 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter, |
| 146 uint8_t server_public_key[/* 32 */], |
| 147 uint32_t server_public_key_version, |
| 148 size_t max_queued_report_count, |
| 149 base::TimeDelta max_report_age, |
| 150 std::unique_ptr<base::Clock> clock) |
| 151 : enabled_(true), |
| 152 url_request_context_(nullptr), |
| 153 max_queued_report_count_(max_queued_report_count), |
| 154 max_report_age_(max_report_age), |
| 155 clock_(std::move(clock)), |
| 156 made_send_attempt_(false), |
| 157 server_public_key_(server_public_key), |
| 158 server_public_key_version_(server_public_key_version) { |
| 159 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 160 content::BrowserThread::PostTask( |
| 161 content::BrowserThread::IO, FROM_HERE, |
| 162 base::Bind(&CertificateReportingService::InitializeOnIOThread, |
| 163 base::Unretained(this), enabled_, url_request_context_getter, |
| 164 max_queued_report_count_, max_report_age_, clock_.get(), |
| 165 server_public_key_, server_public_key_version_)); |
| 166 } |
| 167 |
| 168 CertificateReportingService::~CertificateReportingService() { |
| 169 DCHECK(!reporter_); |
| 170 } |
| 171 |
| 172 void CertificateReportingService::Shutdown() { |
| 173 // Shutdown will be called twice: Once after SafeBrowsing shuts down, and once |
| 174 // when all KeyedServices shut down. All calls after the first one are no-op. |
| 175 enabled_ = false; |
| 176 Reset(); |
| 177 } |
| 178 |
| 179 void CertificateReportingService::Send(const std::string& serialized_report) { |
| 180 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 181 made_send_attempt_ = true; |
| 182 if (!reporter_) { |
| 183 return; |
| 184 } |
| 185 content::BrowserThread::PostTask( |
| 186 content::BrowserThread::IO, FROM_HERE, |
| 187 base::Bind(&CertificateReportingService::Reporter::Send, |
| 188 base::Unretained(reporter_.get()), serialized_report)); |
| 189 } |
| 190 |
| 191 void CertificateReportingService::SendPending() { |
| 192 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 193 made_send_attempt_ = true; |
| 194 if (!reporter_) { |
| 195 return; |
| 196 } |
| 197 content::BrowserThread::PostTask( |
| 198 content::BrowserThread::IO, FROM_HERE, |
| 199 base::Bind(&CertificateReportingService::Reporter::SendPending, |
| 200 base::Unretained(reporter_.get()))); |
| 201 } |
| 202 |
| 203 void CertificateReportingService::InitializeOnIOThread( |
| 204 bool enabled, |
| 205 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter, |
| 206 size_t max_queued_report_count, |
| 207 base::TimeDelta max_report_age, |
| 208 base::Clock* clock, |
| 209 uint8_t* server_public_key, |
| 210 uint32_t server_public_key_version) { |
| 211 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 212 DCHECK(!url_request_context_); |
| 213 url_request_context_ = url_request_context_getter->GetURLRequestContext(); |
| 214 ResetOnIOThread(enabled, url_request_context_, max_queued_report_count, |
| 215 max_report_age, clock, server_public_key, |
| 216 server_public_key_version); |
| 217 } |
| 218 |
| 219 void CertificateReportingService::SetEnabled(bool enabled) { |
| 220 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 221 enabled_ = enabled; |
| 222 Reset(); |
| 223 } |
| 224 |
| 225 CertificateReportingService::Reporter* |
| 226 CertificateReportingService::GetReporterForTesting() const { |
| 227 return reporter_.get(); |
| 228 } |
| 229 |
| 230 void CertificateReportingService::SetMaxQueuedReportCountForTesting( |
| 231 size_t count) { |
| 232 DCHECK(!made_send_attempt_); |
| 233 max_queued_report_count_ = count; |
| 234 Reset(); |
| 235 } |
| 236 |
| 237 void CertificateReportingService::SetClockForTesting( |
| 238 std::unique_ptr<base::Clock> clock) { |
| 239 DCHECK(!made_send_attempt_); |
| 240 clock_ = std::move(clock); |
| 241 Reset(); |
| 242 } |
| 243 |
| 244 void CertificateReportingService::SetMaxReportAgeForTesting( |
| 245 base::TimeDelta max_report_age) { |
| 246 DCHECK(!made_send_attempt_); |
| 247 max_report_age_ = max_report_age; |
| 248 Reset(); |
| 249 } |
| 250 |
| 251 // static |
| 252 GURL CertificateReportingService::GetReportingURLForTesting() { |
| 253 return GURL(kExtendedReportingUploadUrl); |
| 254 } |
| 255 |
| 256 void CertificateReportingService::Reset() { |
| 257 content::BrowserThread::PostTask( |
| 258 content::BrowserThread::IO, FROM_HERE, |
| 259 base::Bind(&CertificateReportingService::ResetOnIOThread, |
| 260 base::Unretained(this), enabled_, url_request_context_, |
| 261 max_queued_report_count_, max_report_age_, clock_.get(), |
| 262 server_public_key_, server_public_key_version_)); |
| 263 } |
| 264 |
| 265 void CertificateReportingService::ResetOnIOThread( |
| 266 bool enabled, |
| 267 net::URLRequestContext* url_request_context, |
| 268 size_t max_queued_report_count, |
| 269 base::TimeDelta max_report_age, |
| 270 base::Clock* clock, |
| 271 uint8_t* const server_public_key, |
| 272 uint32_t server_public_key_version) { |
| 273 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 274 // url_request_context_ is null during shutdown. |
| 275 if (!enabled || !url_request_context) { |
| 276 reporter_.reset(nullptr); |
| 277 return; |
| 278 } |
| 279 std::unique_ptr<certificate_reporting::ErrorReporter> error_reporter; |
| 280 if (server_public_key) { |
| 281 // Only used in tests. |
| 282 std::unique_ptr<net::ReportSender> report_sender(new net::ReportSender( |
| 283 url_request_context, net::ReportSender::DO_NOT_SEND_COOKIES)); |
| 284 error_reporter.reset(new certificate_reporting::ErrorReporter( |
| 285 GURL(kExtendedReportingUploadUrl), server_public_key, |
| 286 server_public_key_version, std::move(report_sender))); |
| 287 } else { |
| 288 error_reporter.reset(new certificate_reporting::ErrorReporter( |
| 289 url_request_context, GURL(kExtendedReportingUploadUrl), |
| 290 net::ReportSender::DO_NOT_SEND_COOKIES)); |
| 291 } |
| 292 |
| 293 reporter_.reset( |
| 294 new Reporter(std::move(error_reporter), |
| 295 std::unique_ptr<BoundedReportList>( |
| 296 new BoundedReportList(max_queued_report_count)), |
| 297 clock, max_report_age, true /* retries_enabled */)); |
| 298 } |
| OLD | NEW |