Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(196)

Side by Side Diff: chrome/browser/safe_browsing/certificate_reporting_service_test_utils.cc

Issue 2543523002: Implement main CertificateReportingService code and add unit tests. (Closed)
Patch Set: Cleanup Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance();
26 filter->AddUrlInterceptor(
27 GURL(CertificateReportingService::kExtendedReportingUploadUrlInsecure),
28 std::move(url_request_interceptor));
29 }
30
31 std::string GetUploadData(net::URLRequest* request) {
32 const net::UploadDataStream* stream = request->get_upload();
33 EXPECT_TRUE(stream);
34 EXPECT_TRUE(stream->GetElementReaders());
35 EXPECT_EQ(1u, stream->GetElementReaders()->size());
36 const net::UploadBytesElementReader* reader =
37 (*stream->GetElementReaders())[0]->AsBytesReader();
38 return std::string(reader->bytes(), reader->length());
39 }
40
41 std::string GetReportContents(net::URLRequest* request,
42 const uint8_t* server_private_key) {
43 std::string serialized_report(GetUploadData(request));
44 certificate_reporting::EncryptedCertLoggerRequest encrypted_request;
45 EXPECT_TRUE(encrypted_request.ParseFromString(serialized_report));
46 EXPECT_EQ(kServerPublicKeyTestVersion,
47 encrypted_request.server_public_key_version());
48 EXPECT_EQ(certificate_reporting::EncryptedCertLoggerRequest::
49 AEAD_ECDH_AES_128_CTR_HMAC_SHA256,
50 encrypted_request.algorithm());
51 std::string decrypted_report;
52 certificate_reporting::ErrorReporter::DecryptErrorReport(
53 server_private_key, encrypted_request, &decrypted_report);
54 return decrypted_report;
55 }
56
57 } // namespace
58
59 namespace certificate_reporting_test_utils {
60
61 CertificateReportingServiceTestNetworkDelegate::
estark 2016/12/07 00:42:55 nit: I think the order of things here doesn't matc
meacer 2016/12/07 21:37:33 Done.
62 CertificateReportingServiceTestNetworkDelegate(
63 const base::Callback<void(net::URLRequest* request)>&
64 url_request_destroyed_callback)
65 : url_request_destroyed_callback_(url_request_destroyed_callback) {}
66
67 CertificateReportingServiceTestNetworkDelegate::
68 ~CertificateReportingServiceTestNetworkDelegate() {}
69
70 void CertificateReportingServiceTestNetworkDelegate::OnURLRequestDestroyed(
71 net::URLRequest* request) {
72 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
73 content::BrowserThread::PostTask(
74 content::BrowserThread::UI, FROM_HERE,
75 base::Bind(url_request_destroyed_callback_, request));
estark 2016/12/07 00:42:55 Is it safe to pass URLRequests to the UI thread?
meacer 2016/12/07 21:37:33 Removed the request.
76 }
77
78 DelayableCertReportURLRequestJob::DelayableCertReportURLRequestJob(
79 net::URLRequest* request,
80 net::NetworkDelegate* network_delegate)
81 : net::URLRequestJob(request, network_delegate), weak_factory_(this) {}
82
83 DelayableCertReportURLRequestJob::~DelayableCertReportURLRequestJob() {}
84
85 void DelayableCertReportURLRequestJob::Start() {
86 started_ = true;
87 if (delayed_) {
88 // Do nothing until Resume() is called.
89 return;
90 }
91 Resume();
92 }
93
94 int DelayableCertReportURLRequestJob::ReadRawData(net::IOBuffer* buf,
95 int buf_size) {
96 return 0;
97 }
98
99 int DelayableCertReportURLRequestJob::GetResponseCode() const {
100 return 200;
101 }
102
103 void DelayableCertReportURLRequestJob::GetResponseInfo(
104 net::HttpResponseInfo* info) {}
estark 2016/12/07 00:42:55 nit: maybe put a comment here explaining that the
meacer 2016/12/07 21:37:33 Done.
105
106 void DelayableCertReportURLRequestJob::Resume() {
107 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
108 DCHECK(delayed_);
109 if (!started_) {
110 // If Start() hasn't been called yet, then unset |delayed_| so
111 // that when Start() is called, the request will begin
112 // immediately.
113 delayed_ = false;
114 return;
115 }
116 // Start reading asynchronously as would a normal network request.
117 base::ThreadTaskRunnerHandle::Get()->PostTask(
118 FROM_HERE,
119 base::Bind(&DelayableCertReportURLRequestJob::NotifyHeadersComplete,
120 weak_factory_.GetWeakPtr()));
121 }
122
123 void CertReportJobInterceptor::RequestCreated(
124 const std::string& uploaded_report,
125 ReportSendingResult expected_report_result) {
126 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
127 switch (expected_report_result) {
128 case REPORTS_SUCCESSFUL:
129 successful_reports_.insert(uploaded_report);
130 break;
131 case REPORTS_FAIL:
132 failed_reports_.insert(uploaded_report);
133 break;
134 case REPORTS_DELAY:
135 delayed_reports_.insert(uploaded_report);
136 break;
137 }
138 }
139
140 void CertReportJobInterceptor::Clear() {
141 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
142 successful_reports_.clear();
143 failed_reports_.clear();
144 delayed_reports_.clear();
145 }
146
147 CertReportJobInterceptor::CertReportJobInterceptor(
148 ReportSendingResult expected_report_result,
149 const uint8_t* server_private_key)
150 : expected_report_result_(expected_report_result),
151 server_private_key_(server_private_key),
152 weak_factory_(this) {}
153
154 CertReportJobInterceptor::~CertReportJobInterceptor() {}
155
156 net::URLRequestJob* CertReportJobInterceptor::MaybeInterceptRequest(
157 net::URLRequest* request,
158 net::NetworkDelegate* network_delegate) const {
159 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
160
161 const std::string uploaded_report =
162 GetReportContents(request, server_private_key_);
163 content::BrowserThread::PostTask(
164 content::BrowserThread::UI, FROM_HERE,
165 base::Bind(&CertReportJobInterceptor::RequestCreated,
166 weak_factory_.GetWeakPtr(), uploaded_report,
167 expected_report_result_));
168
169 if (expected_report_result_ == REPORTS_FAIL) {
170 return new net::URLRequestFailedJob(request, network_delegate,
171 net::ERR_SSL_PROTOCOL_ERROR);
172 } else if (expected_report_result_ == REPORTS_DELAY) {
173 DCHECK(!delayed_request_) << "Supports only one delayed request at a time";
174 DelayableCertReportURLRequestJob* job =
175 new DelayableCertReportURLRequestJob(request, network_delegate);
176 delayed_request_ = job->GetWeakPtr();
177 return job;
178 }
179 // Successful url request job.
180 return new net::URLRequestMockDataJob(request, network_delegate, "some data",
181 1, false);
182 }
183
184 void CertReportJobInterceptor::SetFailureMode(
185 ReportSendingResult expected_report_result) {
186 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
187 content::BrowserThread::PostTask(
188 content::BrowserThread::IO, FROM_HERE,
189 base::Bind(&CertReportJobInterceptor::SetFailureModeOnIOThread,
190 weak_factory_.GetWeakPtr(), expected_report_result));
191 }
192
193 void CertReportJobInterceptor::Resume() {
194 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
195 content::BrowserThread::PostTask(
196 content::BrowserThread::IO, FROM_HERE,
197 base::Bind(&CertReportJobInterceptor::ResumeOnIOThread,
198 weak_factory_.GetWeakPtr()));
199 }
200
201 const std::set<std::string>& CertReportJobInterceptor::successful_reports()
202 const {
203 return successful_reports_;
204 }
205
206 const std::set<std::string>& CertReportJobInterceptor::failed_reports() const {
207 return failed_reports_;
208 }
209
210 const std::set<std::string>& CertReportJobInterceptor::delayed_reports() const {
211 return delayed_reports_;
212 }
213
214 void CertReportJobInterceptor::SetFailureModeOnIOThread(
215 ReportSendingResult expected_report_result) {
216 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
217 expected_report_result_ = expected_report_result;
218 }
219
220 void CertReportJobInterceptor::ResumeOnIOThread() {
221 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
222 EXPECT_EQ(REPORTS_DELAY, expected_report_result_);
223 if (delayed_request_)
224 delayed_request_->Resume();
225 }
226
227 CertificateReportingServiceTestBase::CertificateReportingServiceTestBase()
228 : network_delegate_(
229 base::Bind(&CertificateReportingServiceTestBase::OnRequestDeleted,
230 base::Unretained(this))),
231 num_request_deletions_to_wait_for_(0),
232 num_deleted_requests_(0) {
233 memset(server_private_key_, 1, sizeof(server_private_key_));
234 crypto::curve25519::ScalarBaseMult(server_private_key_, server_public_key_);
235 }
236
237 CertificateReportingServiceTestBase::~CertificateReportingServiceTestBase() {}
238
239 void CertificateReportingServiceTestBase::SetUpInterceptor() {
240 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
241 url_request_interceptor_ =
242 new certificate_reporting_test_utils::CertReportJobInterceptor(
243 certificate_reporting_test_utils::REPORTS_FAIL, server_private_key_);
244
245 content::BrowserThread::PostTask(
246 content::BrowserThread::IO, FROM_HERE,
247 base::Bind(&SetUpURLHandlersOnIOThread,
248 base::Passed(std::unique_ptr<net::URLRequestInterceptor>(
249 url_request_interceptor_))));
250 }
251
252 void CertificateReportingServiceTestBase::ClearObservedReports() {
253 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
254 url_request_interceptor_->Clear();
255 }
256
257 uint32_t CertificateReportingServiceTestBase::server_public_key_version()
258 const {
259 return kServerPublicKeyTestVersion;
260 }
261
262 // Changes the behavior of report uploads to fail or succeed.
263 void CertificateReportingServiceTestBase::SetFailureMode(
264 certificate_reporting_test_utils::ReportSendingResult
265 expected_report_result) {
266 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
267 url_request_interceptor_->SetFailureMode(expected_report_result);
268 }
269
270 void CertificateReportingServiceTestBase::OnRequestDeleted(
271 net::URLRequest* request) {
272 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
273 num_deleted_requests_++;
274 if (!run_loop_) {
275 return;
276 }
277 EXPECT_LE(num_deleted_requests_, num_request_deletions_to_wait_for_);
278 if (num_deleted_requests_ == num_request_deletions_to_wait_for_) {
279 num_request_deletions_to_wait_for_ = 0;
280 num_deleted_requests_ = 0;
281 run_loop_->Quit();
282 }
283 }
284
285 CertificateReportingServiceTestBase::ReportExpectation::ReportExpectation() {}
286
287 CertificateReportingServiceTestBase::ReportExpectation::~ReportExpectation() {}
288
289 CertificateReportingServiceTestBase::ReportExpectation&
290 CertificateReportingServiceTestBase::ReportExpectation::Successful(
estark 2016/12/07 00:42:55 Oh, cool, I've never seen this pattern in chrome b
meacer 2016/12/07 21:37:33 Yes, but the unit tests only check for a single ty
291 const std::set<std::string>& reports) {
292 successful_reports = reports;
293 return *this;
294 }
295
296 CertificateReportingServiceTestBase::ReportExpectation&
297 CertificateReportingServiceTestBase::ReportExpectation::Failed(
298 const std::set<std::string>& reports) {
299 failed_reports = reports;
300 return *this;
301 }
302
303 CertificateReportingServiceTestBase::ReportExpectation&
304 CertificateReportingServiceTestBase::ReportExpectation::Delayed(
305 const std::set<std::string>& reports) {
306 delayed_reports = reports;
307 return *this;
308 }
309
310 void CertificateReportingServiceTestBase::WaitForRequestDeletions(
311 const ReportExpectation& expectation) {
312 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
313 DCHECK(!run_loop_);
314
315 const int num_request_deletions_to_wait_for =
316 expectation.successful_reports.size() +
317 expectation.failed_reports.size() + expectation.delayed_reports.size();
318
319 if (num_deleted_requests_ < num_request_deletions_to_wait_for) {
320 num_request_deletions_to_wait_for_ = num_request_deletions_to_wait_for;
321 run_loop_.reset(new base::RunLoop());
322 run_loop_->Run();
323 EXPECT_EQ(0, num_deleted_requests_);
324 EXPECT_EQ(0, num_request_deletions_to_wait_for_);
325 } else if (num_deleted_requests_ == num_request_deletions_to_wait_for) {
326 num_deleted_requests_ = 0;
327 num_request_deletions_to_wait_for_ = 0;
328 } else {
329 NOTREACHED() << "Observed unexpected report";
estark 2016/12/07 00:42:55 nit: maybe make this an ASSERT_LE above line 319
meacer 2016/12/07 21:37:33 Done.
330 }
331
332 EXPECT_EQ(expectation.successful_reports,
333 url_request_interceptor_->successful_reports());
334 EXPECT_EQ(expectation.failed_reports,
335 url_request_interceptor_->failed_reports());
336 EXPECT_EQ(expectation.delayed_reports,
337 url_request_interceptor_->delayed_reports());
338 ClearObservedReports();
339 }
340
341 void CertificateReportingServiceTestBase::ResumeDelayedRequest() {
342 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
343 url_request_interceptor_->Resume();
344 }
345
346 } // namespace certificate_reporting_test_utils
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698