| OLD | NEW |
| (Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/safe_browsing/certificate_reporting_service_test_utils.
h" |
| 6 |
| 7 #include "base/threading/thread_task_runner_handle.h" |
| 8 #include "components/certificate_reporting/encrypted_cert_logger.pb.h" |
| 9 #include "content/public/browser/browser_thread.h" |
| 10 #include "content/public/test/test_utils.h" |
| 11 #include "crypto/curve25519.h" |
| 12 #include "net/base/upload_bytes_element_reader.h" |
| 13 #include "net/base/upload_data_stream.h" |
| 14 #include "net/test/url_request/url_request_failed_job.h" |
| 15 #include "net/test/url_request/url_request_mock_data_job.h" |
| 16 #include "net/url_request/url_request_filter.h" |
| 17 #include "testing/gtest/include/gtest/gtest.h" |
| 18 |
| 19 namespace { |
| 20 |
| 21 const uint32_t kServerPublicKeyTestVersion = 16; |
| 22 |
| 23 void SetUpURLHandlersOnIOThread( |
| 24 std::unique_ptr<net::URLRequestInterceptor> url_request_interceptor) { |
| 25 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 26 net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance(); |
| 27 filter->AddUrlInterceptor( |
| 28 CertificateReportingService::GetReportingURLForTesting(), |
| 29 std::move(url_request_interceptor)); |
| 30 } |
| 31 |
| 32 std::string GetUploadData(net::URLRequest* request) { |
| 33 const net::UploadDataStream* stream = request->get_upload(); |
| 34 EXPECT_TRUE(stream); |
| 35 EXPECT_TRUE(stream->GetElementReaders()); |
| 36 EXPECT_EQ(1u, stream->GetElementReaders()->size()); |
| 37 const net::UploadBytesElementReader* reader = |
| 38 (*stream->GetElementReaders())[0]->AsBytesReader(); |
| 39 return std::string(reader->bytes(), reader->length()); |
| 40 } |
| 41 |
| 42 std::string GetReportContents(net::URLRequest* request, |
| 43 const uint8_t* server_private_key) { |
| 44 std::string serialized_report(GetUploadData(request)); |
| 45 certificate_reporting::EncryptedCertLoggerRequest encrypted_request; |
| 46 EXPECT_TRUE(encrypted_request.ParseFromString(serialized_report)); |
| 47 EXPECT_EQ(kServerPublicKeyTestVersion, |
| 48 encrypted_request.server_public_key_version()); |
| 49 EXPECT_EQ(certificate_reporting::EncryptedCertLoggerRequest:: |
| 50 AEAD_ECDH_AES_128_CTR_HMAC_SHA256, |
| 51 encrypted_request.algorithm()); |
| 52 std::string decrypted_report; |
| 53 certificate_reporting::ErrorReporter::DecryptErrorReport( |
| 54 server_private_key, encrypted_request, &decrypted_report); |
| 55 return decrypted_report; |
| 56 } |
| 57 |
| 58 } // namespace |
| 59 |
| 60 namespace certificate_reporting_test_utils { |
| 61 |
| 62 DelayableCertReportURLRequestJob::DelayableCertReportURLRequestJob( |
| 63 net::URLRequest* request, |
| 64 net::NetworkDelegate* network_delegate) |
| 65 : net::URLRequestJob(request, network_delegate), weak_factory_(this) {} |
| 66 |
| 67 DelayableCertReportURLRequestJob::~DelayableCertReportURLRequestJob() {} |
| 68 |
| 69 base::WeakPtr<DelayableCertReportURLRequestJob> |
| 70 DelayableCertReportURLRequestJob::GetWeakPtr() { |
| 71 return weak_factory_.GetWeakPtr(); |
| 72 } |
| 73 |
| 74 void DelayableCertReportURLRequestJob::Start() { |
| 75 started_ = true; |
| 76 if (delayed_) { |
| 77 // Do nothing until Resume() is called. |
| 78 return; |
| 79 } |
| 80 Resume(); |
| 81 } |
| 82 |
| 83 int DelayableCertReportURLRequestJob::ReadRawData(net::IOBuffer* buf, |
| 84 int buf_size) { |
| 85 // Report sender ignores responses. Return empty response. |
| 86 return 0; |
| 87 } |
| 88 |
| 89 int DelayableCertReportURLRequestJob::GetResponseCode() const { |
| 90 // Report sender ignores responses. Return empty response. |
| 91 return 200; |
| 92 } |
| 93 |
| 94 void DelayableCertReportURLRequestJob::GetResponseInfo( |
| 95 net::HttpResponseInfo* info) { |
| 96 // Report sender ignores responses. Return empty response. |
| 97 } |
| 98 |
| 99 void DelayableCertReportURLRequestJob::Resume() { |
| 100 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 101 DCHECK(delayed_); |
| 102 if (!started_) { |
| 103 // If Start() hasn't been called yet, then unset |delayed_| so |
| 104 // that when Start() is called, the request will begin |
| 105 // immediately. |
| 106 delayed_ = false; |
| 107 return; |
| 108 } |
| 109 // Start reading asynchronously as would a normal network request. |
| 110 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 111 FROM_HERE, |
| 112 base::Bind(&DelayableCertReportURLRequestJob::NotifyHeadersComplete, |
| 113 weak_factory_.GetWeakPtr())); |
| 114 } |
| 115 |
| 116 CertReportJobInterceptor::CertReportJobInterceptor( |
| 117 ReportSendingResult expected_report_result, |
| 118 const uint8_t* server_private_key) |
| 119 : expected_report_result_(expected_report_result), |
| 120 server_private_key_(server_private_key), |
| 121 weak_factory_(this) {} |
| 122 |
| 123 CertReportJobInterceptor::~CertReportJobInterceptor() {} |
| 124 |
| 125 net::URLRequestJob* CertReportJobInterceptor::MaybeInterceptRequest( |
| 126 net::URLRequest* request, |
| 127 net::NetworkDelegate* network_delegate) const { |
| 128 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 129 |
| 130 const std::string uploaded_report = |
| 131 GetReportContents(request, server_private_key_); |
| 132 content::BrowserThread::PostTask( |
| 133 content::BrowserThread::UI, FROM_HERE, |
| 134 base::Bind(&CertReportJobInterceptor::RequestCreated, |
| 135 weak_factory_.GetWeakPtr(), uploaded_report, |
| 136 expected_report_result_)); |
| 137 |
| 138 if (expected_report_result_ == REPORTS_FAIL) { |
| 139 return new net::URLRequestFailedJob(request, network_delegate, |
| 140 net::ERR_SSL_PROTOCOL_ERROR); |
| 141 } else if (expected_report_result_ == REPORTS_DELAY) { |
| 142 DCHECK(!delayed_request_) << "Supports only one delayed request at a time"; |
| 143 DelayableCertReportURLRequestJob* job = |
| 144 new DelayableCertReportURLRequestJob(request, network_delegate); |
| 145 delayed_request_ = job->GetWeakPtr(); |
| 146 return job; |
| 147 } |
| 148 // Successful url request job. |
| 149 return new net::URLRequestMockDataJob(request, network_delegate, "some data", |
| 150 1, false); |
| 151 } |
| 152 |
| 153 void CertReportJobInterceptor::SetFailureMode( |
| 154 ReportSendingResult expected_report_result) { |
| 155 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 156 content::BrowserThread::PostTask( |
| 157 content::BrowserThread::IO, FROM_HERE, |
| 158 base::Bind(&CertReportJobInterceptor::SetFailureModeOnIOThread, |
| 159 weak_factory_.GetWeakPtr(), expected_report_result)); |
| 160 } |
| 161 |
| 162 void CertReportJobInterceptor::Resume() { |
| 163 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 164 content::BrowserThread::PostTask( |
| 165 content::BrowserThread::IO, FROM_HERE, |
| 166 base::Bind(&CertReportJobInterceptor::ResumeOnIOThread, |
| 167 base::Unretained(this))); |
| 168 } |
| 169 |
| 170 const std::set<std::string>& CertReportJobInterceptor::successful_reports() |
| 171 const { |
| 172 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 173 return successful_reports_; |
| 174 } |
| 175 |
| 176 const std::set<std::string>& CertReportJobInterceptor::failed_reports() const { |
| 177 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 178 return failed_reports_; |
| 179 } |
| 180 |
| 181 const std::set<std::string>& CertReportJobInterceptor::delayed_reports() const { |
| 182 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 183 return delayed_reports_; |
| 184 } |
| 185 |
| 186 void CertReportJobInterceptor::ClearObservedReports() { |
| 187 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 188 successful_reports_.clear(); |
| 189 failed_reports_.clear(); |
| 190 delayed_reports_.clear(); |
| 191 } |
| 192 |
| 193 void CertReportJobInterceptor::SetFailureModeOnIOThread( |
| 194 ReportSendingResult expected_report_result) { |
| 195 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 196 expected_report_result_ = expected_report_result; |
| 197 } |
| 198 |
| 199 void CertReportJobInterceptor::ResumeOnIOThread() { |
| 200 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 201 EXPECT_EQ(REPORTS_DELAY, expected_report_result_); |
| 202 if (delayed_request_) |
| 203 delayed_request_->Resume(); |
| 204 } |
| 205 |
| 206 void CertReportJobInterceptor::RequestCreated( |
| 207 const std::string& uploaded_report, |
| 208 ReportSendingResult expected_report_result) { |
| 209 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 210 switch (expected_report_result) { |
| 211 case REPORTS_SUCCESSFUL: |
| 212 successful_reports_.insert(uploaded_report); |
| 213 break; |
| 214 case REPORTS_FAIL: |
| 215 failed_reports_.insert(uploaded_report); |
| 216 break; |
| 217 case REPORTS_DELAY: |
| 218 delayed_reports_.insert(uploaded_report); |
| 219 break; |
| 220 } |
| 221 } |
| 222 |
| 223 CertificateReportingServiceTestNetworkDelegate:: |
| 224 CertificateReportingServiceTestNetworkDelegate( |
| 225 const base::Callback<void()>& url_request_destroyed_callback) |
| 226 : url_request_destroyed_callback_(url_request_destroyed_callback) {} |
| 227 |
| 228 CertificateReportingServiceTestNetworkDelegate:: |
| 229 ~CertificateReportingServiceTestNetworkDelegate() {} |
| 230 |
| 231 void CertificateReportingServiceTestNetworkDelegate::OnURLRequestDestroyed( |
| 232 net::URLRequest* request) { |
| 233 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 234 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, |
| 235 url_request_destroyed_callback_); |
| 236 } |
| 237 |
| 238 CertificateReportingServiceTestBase::ReportExpectation::ReportExpectation() {} |
| 239 |
| 240 CertificateReportingServiceTestBase::ReportExpectation::ReportExpectation( |
| 241 const ReportExpectation& other) = default; |
| 242 |
| 243 CertificateReportingServiceTestBase::ReportExpectation::~ReportExpectation() {} |
| 244 |
| 245 // static |
| 246 CertificateReportingServiceTestBase::ReportExpectation |
| 247 CertificateReportingServiceTestBase::ReportExpectation::Successful( |
| 248 const std::set<std::string>& reports) { |
| 249 ReportExpectation expectation; |
| 250 expectation.successful_reports = reports; |
| 251 return expectation; |
| 252 } |
| 253 |
| 254 // static |
| 255 CertificateReportingServiceTestBase::ReportExpectation |
| 256 CertificateReportingServiceTestBase::ReportExpectation::Failed( |
| 257 const std::set<std::string>& reports) { |
| 258 ReportExpectation expectation; |
| 259 expectation.failed_reports = reports; |
| 260 return expectation; |
| 261 } |
| 262 |
| 263 // static |
| 264 CertificateReportingServiceTestBase::ReportExpectation |
| 265 CertificateReportingServiceTestBase::ReportExpectation::Delayed( |
| 266 const std::set<std::string>& reports) { |
| 267 ReportExpectation expectation; |
| 268 expectation.delayed_reports = reports; |
| 269 return expectation; |
| 270 } |
| 271 |
| 272 CertificateReportingServiceTestBase::CertificateReportingServiceTestBase() |
| 273 : num_request_deletions_to_wait_for_(0), num_deleted_requests_(0) { |
| 274 memset(server_private_key_, 1, sizeof(server_private_key_)); |
| 275 crypto::curve25519::ScalarBaseMult(server_private_key_, server_public_key_); |
| 276 } |
| 277 |
| 278 CertificateReportingServiceTestBase::~CertificateReportingServiceTestBase() {} |
| 279 |
| 280 void CertificateReportingServiceTestBase::SetUpInterceptor() { |
| 281 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 282 url_request_interceptor_ = |
| 283 new CertReportJobInterceptor(REPORTS_FAIL, server_private_key_); |
| 284 content::BrowserThread::PostTask( |
| 285 content::BrowserThread::IO, FROM_HERE, |
| 286 base::Bind( |
| 287 &CertificateReportingServiceTestBase::SetUpInterceptorOnIOThread, |
| 288 base::Unretained(this), |
| 289 base::Passed(std::unique_ptr<net::URLRequestInterceptor>( |
| 290 url_request_interceptor_)))); |
| 291 } |
| 292 |
| 293 void CertificateReportingServiceTestBase::TearDownInterceptor() { |
| 294 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 295 content::BrowserThread::PostTask( |
| 296 content::BrowserThread::IO, FROM_HERE, |
| 297 base::Bind( |
| 298 &CertificateReportingServiceTestBase::TearDownInterceptorOnIOThread, |
| 299 base::Unretained(this))); |
| 300 } |
| 301 |
| 302 // Changes the behavior of report uploads to fail or succeed. |
| 303 void CertificateReportingServiceTestBase::SetFailureMode( |
| 304 ReportSendingResult expected_report_result) { |
| 305 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 306 url_request_interceptor_->SetFailureMode(expected_report_result); |
| 307 } |
| 308 |
| 309 void CertificateReportingServiceTestBase::ResumeDelayedRequest() { |
| 310 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 311 url_request_interceptor_->Resume(); |
| 312 } |
| 313 |
| 314 void CertificateReportingServiceTestBase::WaitForRequestsDestroyed( |
| 315 const ReportExpectation& expectation) { |
| 316 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 317 DCHECK(!run_loop_); |
| 318 |
| 319 const int num_request_deletions_to_wait_for = |
| 320 expectation.successful_reports.size() + |
| 321 expectation.failed_reports.size() + expectation.delayed_reports.size(); |
| 322 |
| 323 ASSERT_LE(num_deleted_requests_, num_request_deletions_to_wait_for) |
| 324 << "Observed unexpected report"; |
| 325 if (num_deleted_requests_ < num_request_deletions_to_wait_for) { |
| 326 num_request_deletions_to_wait_for_ = num_request_deletions_to_wait_for; |
| 327 run_loop_.reset(new base::RunLoop()); |
| 328 run_loop_->Run(); |
| 329 run_loop_.reset(nullptr); |
| 330 EXPECT_EQ(0, num_deleted_requests_); |
| 331 EXPECT_EQ(0, num_request_deletions_to_wait_for_); |
| 332 } else if (num_deleted_requests_ == num_request_deletions_to_wait_for) { |
| 333 num_deleted_requests_ = 0; |
| 334 num_request_deletions_to_wait_for_ = 0; |
| 335 } |
| 336 EXPECT_EQ(expectation.successful_reports, |
| 337 url_request_interceptor_->successful_reports()); |
| 338 EXPECT_EQ(expectation.failed_reports, |
| 339 url_request_interceptor_->failed_reports()); |
| 340 EXPECT_EQ(expectation.delayed_reports, |
| 341 url_request_interceptor_->delayed_reports()); |
| 342 url_request_interceptor_->ClearObservedReports(); |
| 343 } |
| 344 |
| 345 uint8_t* CertificateReportingServiceTestBase::server_public_key() { |
| 346 return server_public_key_; |
| 347 } |
| 348 |
| 349 uint32_t CertificateReportingServiceTestBase::server_public_key_version() |
| 350 const { |
| 351 return kServerPublicKeyTestVersion; |
| 352 } |
| 353 |
| 354 net::NetworkDelegate* CertificateReportingServiceTestBase::network_delegate() { |
| 355 return network_delegate_.get(); |
| 356 } |
| 357 |
| 358 void CertificateReportingServiceTestBase::SetUpInterceptorOnIOThread( |
| 359 std::unique_ptr<net::URLRequestInterceptor> url_request_interceptor) { |
| 360 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 361 network_delegate_.reset(new CertificateReportingServiceTestNetworkDelegate( |
| 362 base::Bind(&CertificateReportingServiceTestBase::OnURLRequestDestroyed, |
| 363 base::Unretained(this)))); |
| 364 SetUpURLHandlersOnIOThread(std::move(url_request_interceptor)); |
| 365 } |
| 366 |
| 367 void CertificateReportingServiceTestBase::TearDownInterceptorOnIOThread() { |
| 368 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 369 network_delegate_.reset(nullptr); |
| 370 } |
| 371 |
| 372 void CertificateReportingServiceTestBase::OnURLRequestDestroyed() { |
| 373 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 374 num_deleted_requests_++; |
| 375 if (!run_loop_) { |
| 376 return; |
| 377 } |
| 378 EXPECT_LE(num_deleted_requests_, num_request_deletions_to_wait_for_); |
| 379 if (num_deleted_requests_ == num_request_deletions_to_wait_for_) { |
| 380 num_request_deletions_to_wait_for_ = 0; |
| 381 num_deleted_requests_ = 0; |
| 382 run_loop_->Quit(); |
| 383 } |
| 384 } |
| 385 |
| 386 } // namespace certificate_reporting_test_utils |
| OLD | NEW |