Chromium Code Reviews| 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 { |
| 11 // Compare function that orders Reports in reverse chronological order (i.e. | 12 // Compare function that orders Reports in reverse chronological order (i.e. |
| 12 // oldest item is last). | 13 // oldest item is last). |
| 13 bool ReportCompareFunc(const CertificateReportingService::Report& item1, | 14 bool ReportCompareFunc(const CertificateReportingService::Report& item1, |
| 14 const CertificateReportingService::Report& item2) { | 15 const CertificateReportingService::Report& item2) { |
| 15 return item1.creation_time > item2.creation_time; | 16 return item1.creation_time > item2.creation_time; |
| 16 } | 17 } |
| 17 | 18 |
| 18 } // namespace | 19 } // namespace |
| 19 | 20 |
| 21 // static | |
| 22 const char CertificateReportingService::kExtendedReportingUploadUrlInsecure[] = | |
| 23 "http://safebrowsing.googleusercontent.com/safebrowsing/clientreport/"; | |
| 24 | |
| 20 CertificateReportingService::BoundedReportList::BoundedReportList( | 25 CertificateReportingService::BoundedReportList::BoundedReportList( |
| 21 size_t max_size) | 26 size_t max_size) |
| 22 : max_size_(max_size) { | 27 : max_size_(max_size) { |
| 23 CHECK(max_size <= 20) | 28 CHECK(max_size <= 20) |
| 24 << "Current implementation is not efficient for a large list."; | 29 << "Current implementation is not efficient for a large list."; |
| 25 DCHECK(thread_checker_.CalledOnValidThread()); | 30 DCHECK(thread_checker_.CalledOnValidThread()); |
| 26 } | 31 } |
| 27 | 32 |
| 28 CertificateReportingService::BoundedReportList::~BoundedReportList() {} | 33 CertificateReportingService::BoundedReportList::~BoundedReportList() {} |
| 29 | 34 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 50 const std::vector<CertificateReportingService::Report>& | 55 const std::vector<CertificateReportingService::Report>& |
| 51 CertificateReportingService::BoundedReportList::items() const { | 56 CertificateReportingService::BoundedReportList::items() const { |
| 52 DCHECK(thread_checker_.CalledOnValidThread()); | 57 DCHECK(thread_checker_.CalledOnValidThread()); |
| 53 return items_; | 58 return items_; |
| 54 } | 59 } |
| 55 | 60 |
| 56 CertificateReportingService::Reporter::Reporter( | 61 CertificateReportingService::Reporter::Reporter( |
| 57 std::unique_ptr<certificate_reporting::ErrorReporter> error_reporter, | 62 std::unique_ptr<certificate_reporting::ErrorReporter> error_reporter, |
| 58 std::unique_ptr<BoundedReportList> retry_list, | 63 std::unique_ptr<BoundedReportList> retry_list, |
| 59 base::Clock* clock, | 64 base::Clock* clock, |
| 60 base::TimeDelta report_ttl) | 65 base::TimeDelta report_ttl, |
| 66 EventObserver* event_observer, | |
| 67 bool retries_enabled) | |
| 61 : error_reporter_(std::move(error_reporter)), | 68 : error_reporter_(std::move(error_reporter)), |
| 62 retry_list_(std::move(retry_list)), | 69 retry_list_(std::move(retry_list)), |
| 63 test_clock_(clock), | 70 test_clock_(clock), |
| 64 report_ttl_(report_ttl), | 71 report_ttl_(report_ttl), |
| 72 event_observer_(event_observer), | |
| 73 retries_enabled_(retries_enabled), | |
| 65 current_report_id_(0), | 74 current_report_id_(0), |
| 66 weak_factory_(this) {} | 75 weak_factory_(this) {} |
| 67 | 76 |
| 68 CertificateReportingService::Reporter::~Reporter() {} | 77 CertificateReportingService::Reporter::~Reporter() {} |
| 69 | 78 |
| 70 void CertificateReportingService::Reporter::Send( | 79 void CertificateReportingService::Reporter::Send( |
| 71 const std::string& serialized_report) { | 80 const std::string& serialized_report) { |
| 72 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 81 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 73 base::Time now = | 82 base::Time now = |
| 74 test_clock_ ? test_clock_->Now() : base::Time::NowFromSystemTime(); | 83 test_clock_ ? test_clock_->Now() : base::Time::NowFromSystemTime(); |
| 75 SendInternal(Report(current_report_id_++, now, serialized_report)); | 84 SendInternal(Report(current_report_id_++, now, serialized_report)); |
| 76 } | 85 } |
| 77 | 86 |
| 78 void CertificateReportingService::Reporter::SendPending() { | 87 void CertificateReportingService::Reporter::SendPending() { |
| 79 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 88 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 89 if (!retries_enabled_) { | |
| 90 return; | |
| 91 } | |
| 80 base::Time now = | 92 base::Time now = |
| 81 test_clock_ ? test_clock_->Now() : base::Time::NowFromSystemTime(); | 93 test_clock_ ? test_clock_->Now() : base::Time::NowFromSystemTime(); |
| 82 // Copy pending reports and clear the retry list. | 94 // Copy pending reports and clear the retry list. |
| 83 std::vector<Report> items = retry_list_->items(); | 95 std::vector<Report> items = retry_list_->items(); |
| 84 retry_list_->Clear(); | 96 retry_list_->Clear(); |
| 85 for (const Report& report : items) { | 97 for (const Report& report : items) { |
| 86 if (report.creation_time < now - report_ttl_) { | 98 if (report.creation_time < now - report_ttl_) { |
| 87 // Report too old, ignore. | 99 // Report too old, ignore. |
| 88 continue; | 100 continue; |
| 89 } | 101 } |
| 90 SendInternal(report); | 102 SendInternal(report); |
| 91 } | 103 } |
| 92 } | 104 } |
| 93 | 105 |
| 94 size_t | 106 size_t |
| 95 CertificateReportingService::Reporter::inflight_report_count_for_testing() | 107 CertificateReportingService::Reporter::inflight_report_count_for_testing() |
| 96 const { | 108 const { |
| 97 return inflight_reports_.size(); | 109 return inflight_reports_.size(); |
| 98 } | 110 } |
| 99 | 111 |
| 100 CertificateReportingService::BoundedReportList* | 112 CertificateReportingService::BoundedReportList* |
| 101 CertificateReportingService::Reporter::GetQueueForTesting() const { | 113 CertificateReportingService::Reporter::GetQueueForTesting() const { |
| 102 return retry_list_.get(); | 114 return retry_list_.get(); |
| 103 } | 115 } |
| 104 | 116 |
| 117 void CertificateReportingService::Reporter::SetEventObserverForTesting( | |
| 118 EventObserver* observer) { | |
| 119 event_observer_ = observer; | |
| 120 } | |
| 121 | |
| 105 void CertificateReportingService::Reporter::SendInternal( | 122 void CertificateReportingService::Reporter::SendInternal( |
| 106 const CertificateReportingService::Report& report) { | 123 const CertificateReportingService::Report& report) { |
| 107 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 124 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 108 inflight_reports_.insert(std::make_pair(report.report_id, report)); | 125 inflight_reports_.insert(std::make_pair(report.report_id, report)); |
| 109 error_reporter_->SendExtendedReportingReport( | 126 error_reporter_->SendExtendedReportingReport( |
| 110 report.serialized_report, | 127 report.serialized_report, |
| 111 base::Bind(&CertificateReportingService::Reporter::SuccessCallback, | 128 base::Bind(&CertificateReportingService::Reporter::SuccessCallback, |
| 112 weak_factory_.GetWeakPtr(), report.report_id), | 129 weak_factory_.GetWeakPtr(), report.report_id), |
| 113 base::Bind(&CertificateReportingService::Reporter::ErrorCallback, | 130 base::Bind(&CertificateReportingService::Reporter::ErrorCallback, |
| 114 weak_factory_.GetWeakPtr(), report.report_id)); | 131 weak_factory_.GetWeakPtr(), report.report_id)); |
| 115 } | 132 } |
| 116 | 133 |
| 117 void CertificateReportingService::Reporter::ErrorCallback(int report_id, | 134 void CertificateReportingService::Reporter::ErrorCallback(int report_id, |
| 118 const GURL& url, | 135 const GURL& url, |
| 119 int error) { | 136 int error) { |
| 120 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 137 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 121 auto it = inflight_reports_.find(report_id); | 138 if (retries_enabled_) { |
| 122 DCHECK(it != inflight_reports_.end()); | 139 auto it = inflight_reports_.find(report_id); |
| 123 retry_list_->Add(it->second); | 140 DCHECK(it != inflight_reports_.end()); |
| 141 retry_list_->Add(it->second); | |
| 142 } | |
| 124 CHECK_GT(inflight_reports_.erase(report_id), 0u); | 143 CHECK_GT(inflight_reports_.erase(report_id), 0u); |
| 144 content::BrowserThread::PostTask( | |
| 145 content::BrowserThread::UI, FROM_HERE, | |
| 146 base::Bind(&CertificateReportingService::EventObserver::OnSendComplete, | |
| 147 base::Unretained(event_observer_), report_id, false)); | |
| 125 } | 148 } |
| 126 | 149 |
| 127 void CertificateReportingService::Reporter::SuccessCallback(int report_id) { | 150 void CertificateReportingService::Reporter::SuccessCallback(int report_id) { |
| 128 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 151 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 129 CHECK_GT(inflight_reports_.erase(report_id), 0u); | 152 CHECK_GT(inflight_reports_.erase(report_id), 0u); |
| 153 content::BrowserThread::PostTask( | |
| 154 content::BrowserThread::UI, FROM_HERE, | |
| 155 base::Bind(&CertificateReportingService::EventObserver::OnSendComplete, | |
| 156 base::Unretained(event_observer_), report_id, true)); | |
| 130 } | 157 } |
| 158 | |
| 159 CertificateReportingService::CertificateReportingService( | |
| 160 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter, | |
| 161 std::unique_ptr<EventObserver> event_observer, | |
| 162 size_t max_queued_report_count, | |
| 163 base::TimeDelta max_report_age, | |
| 164 base::Clock* test_clock) | |
| 165 : enabled_(true), | |
| 166 url_request_context_(nullptr), | |
| 167 event_observer_(std::move(event_observer)), | |
| 168 max_queued_report_count_(max_queued_report_count), | |
| 169 max_report_age_(max_report_age), | |
| 170 test_clock_(test_clock), | |
| 171 made_send_attempt_(false) { | |
| 172 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 173 content::BrowserThread::PostTaskAndReply( | |
| 174 content::BrowserThread::IO, FROM_HERE, | |
| 175 base::Bind(&CertificateReportingService::InitializeOnIOThread, | |
| 176 base::Unretained(this), enabled_, url_request_context_getter, | |
| 177 max_queued_report_count_, max_report_age_, test_clock_, | |
| 178 nullptr /* error_reporter */), | |
|
Jialiu Lin
2016/11/30 22:18:06
Maybe add a TODO here to indicate that "nullptr" n
meacer
2016/11/30 23:39:40
Looks like the parameter was just wrong, it should
| |
| 179 base::Bind(&EventObserver::OnReset, | |
| 180 base::Unretained(event_observer_.get()))); | |
| 181 } | |
| 182 | |
| 183 CertificateReportingService::~CertificateReportingService() { | |
| 184 DCHECK(!reporter_); | |
| 185 } | |
| 186 | |
| 187 void CertificateReportingService::Shutdown() { | |
| 188 // Shutdown will be called twice: Once after SafeBrowsing shuts down, and once | |
| 189 // when all KeyedServices shut down. All calls after the first one is a no-op. | |
| 190 enabled_ = false; | |
| 191 | |
| 192 Reset(base::Bind(&EventObserver::OnReset, | |
| 193 base::Unretained(event_observer_.get()))); | |
| 194 } | |
| 195 | |
| 196 void CertificateReportingService::Send(const std::string& serialized_report) { | |
| 197 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 198 made_send_attempt_ = true; | |
| 199 if (!reporter_) { | |
| 200 DidAttemptSend(false); | |
| 201 return; | |
| 202 } | |
| 203 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 204 content::BrowserThread::PostTaskAndReply( | |
| 205 content::BrowserThread::IO, FROM_HERE, | |
| 206 base::Bind(&CertificateReportingService::Reporter::Send, | |
| 207 base::Unretained(reporter_.get()), serialized_report), | |
| 208 base::Bind(&CertificateReportingService::DidAttemptSend, | |
| 209 base::Unretained(this), true)); | |
| 210 } | |
| 211 | |
| 212 void CertificateReportingService::SendPending() { | |
| 213 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 214 made_send_attempt_ = true; | |
| 215 if (!reporter_) { | |
| 216 DidAttemptSend(false); | |
| 217 return; | |
| 218 } | |
| 219 content::BrowserThread::PostTaskAndReply( | |
| 220 content::BrowserThread::IO, FROM_HERE, | |
| 221 base::Bind(&CertificateReportingService::Reporter::SendPending, | |
| 222 base::Unretained(reporter_.get())), | |
| 223 base::Bind(&CertificateReportingService::DidAttemptSend, | |
| 224 base::Unretained(this), true)); | |
| 225 } | |
| 226 | |
| 227 void CertificateReportingService::InitializeOnIOThread( | |
| 228 bool enabled, | |
| 229 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter, | |
| 230 size_t max_queued_report_count, | |
| 231 base::TimeDelta max_report_age, | |
| 232 base::Clock* test_clock, | |
| 233 EventObserver* event_observer) { | |
| 234 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
| 235 DCHECK(!url_request_context_); | |
| 236 url_request_context_ = url_request_context_getter->GetURLRequestContext(); | |
| 237 ResetOnIOThread(enabled, url_request_context_, max_queued_report_count, | |
| 238 max_report_age, test_clock, event_observer); | |
| 239 } | |
| 240 | |
| 241 void CertificateReportingService::DidAttemptSend(bool sent) { | |
| 242 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 243 event_observer_->OnSendAttempt(sent); | |
| 244 } | |
| 245 | |
| 246 void CertificateReportingService::SetEnabled(bool enabled) { | |
| 247 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 248 enabled_ = enabled; | |
| 249 Reset(base::Bind(&EventObserver::OnReset, | |
| 250 base::Unretained(event_observer_.get()))); | |
| 251 } | |
| 252 | |
| 253 CertificateReportingService::Reporter* | |
| 254 CertificateReportingService::get_reporter_for_testing() const { | |
| 255 return reporter_.get(); | |
| 256 } | |
| 257 | |
| 258 void CertificateReportingService::SetEventObserverForTesting( | |
| 259 std::unique_ptr<CertificateReportingService::EventObserver> observer) { | |
| 260 event_observer_ = std::move(observer); | |
| 261 // reporter_ can be null if reporting is disabled. | |
| 262 if (reporter_) { | |
| 263 reporter_->SetEventObserverForTesting(event_observer_.get()); | |
| 264 } | |
| 265 } | |
| 266 | |
| 267 void CertificateReportingService::SetMaxQueuedReportCountForTesting( | |
| 268 size_t count) { | |
| 269 DCHECK(!made_send_attempt_); | |
| 270 max_queued_report_count_ = count; | |
| 271 Reset(base::Bind(base::DoNothing)); | |
| 272 } | |
| 273 | |
| 274 void CertificateReportingService::SetClockForTesting(base::Clock* clock) { | |
| 275 DCHECK(!made_send_attempt_); | |
| 276 test_clock_ = clock; | |
| 277 Reset(base::Bind(base::DoNothing)); | |
| 278 } | |
| 279 | |
| 280 void CertificateReportingService::SetMaxReportAgeForTesting( | |
| 281 base::TimeDelta max_report_age) { | |
| 282 DCHECK(!made_send_attempt_); | |
| 283 max_report_age_ = max_report_age; | |
| 284 Reset(base::Bind(base::DoNothing)); | |
| 285 } | |
| 286 | |
| 287 void CertificateReportingService::Reset( | |
| 288 const base::Callback<void()>& callback) { | |
| 289 content::BrowserThread::PostTaskAndReply( | |
| 290 content::BrowserThread::IO, FROM_HERE, | |
| 291 base::Bind(&CertificateReportingService::ResetOnIOThread, | |
| 292 base::Unretained(this), enabled_, url_request_context_, | |
| 293 max_queued_report_count_, max_report_age_, test_clock_, | |
| 294 event_observer_.get()), | |
| 295 callback); | |
| 296 } | |
| 297 | |
| 298 void CertificateReportingService::ResetOnIOThread( | |
| 299 bool enabled, | |
| 300 net::URLRequestContext* url_request_context, | |
| 301 size_t max_queued_report_count, | |
| 302 base::TimeDelta max_report_age, | |
| 303 base::Clock* test_clock, | |
| 304 EventObserver* event_observer) { | |
| 305 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
| 306 // url_request_context_ is null during shutdown. | |
| 307 if (!enabled || !url_request_context) { | |
| 308 reporter_.reset(nullptr); | |
| 309 return; | |
| 310 } | |
| 311 reporter_.reset(new Reporter( | |
| 312 std::unique_ptr<certificate_reporting::ErrorReporter>( | |
| 313 new certificate_reporting::ErrorReporter( | |
| 314 url_request_context, GURL(kExtendedReportingUploadUrlInsecure), | |
| 315 net::ReportSender::DO_NOT_SEND_COOKIES)), | |
| 316 std::unique_ptr<BoundedReportList>( | |
| 317 new BoundedReportList(max_queued_report_count)), | |
| 318 test_clock, max_report_age, event_observer, true /* retries_enabled */)); | |
| 319 } | |
| OLD | NEW |