1 // Copyright 2019 The Chromium Authors
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 "net/cert/coalescing_cert_verifier.h"
6
7 #include <memory>
8
9 #include "base/functional/bind.h"
10 #include "base/test/bind.h"
11 #include "base/test/metrics/histogram_tester.h"
12 #include "net/base/net_errors.h"
13 #include "net/base/test_completion_callback.h"
14 #include "net/cert/mock_cert_verifier.h"
15 #include "net/cert/x509_certificate.h"
16 #include "net/log/net_log_with_source.h"
17 #include "net/test/cert_test_util.h"
18 #include "net/test/gtest_util.h"
19 #include "net/test/test_data_directory.h"
20 #include "net/test/test_with_task_environment.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23
24 using net::test::IsError;
25 using net::test::IsOk;
26
27 namespace net {
28
29 using CoalescingCertVerifierTest = TestWithTaskEnvironment;
30
31 // Tests that synchronous completion does not cause any issues.
TEST_F(CoalescingCertVerifierTest,SyncCompletion)32 TEST_F(CoalescingCertVerifierTest, SyncCompletion) {
33 scoped_refptr<X509Certificate> test_cert(
34 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
35 ASSERT_TRUE(test_cert);
36
37 CertVerifyResult fake_result;
38 fake_result.verified_cert = test_cert;
39
40 std::unique_ptr<MockCertVerifier> mock_verifier_owner =
41 std::make_unique<MockCertVerifier>();
42 MockCertVerifier* mock_verifier = mock_verifier_owner.get();
43 mock_verifier->set_async(false); // Force sync completion.
44 mock_verifier->AddResultForCert(test_cert, fake_result, OK);
45
46 CoalescingCertVerifier verifier(std::move(mock_verifier_owner));
47
48 CertVerifier::RequestParams request_params(test_cert, "www.example.com", 0,
49 /*ocsp_response=*/std::string(),
50 /*sct_list=*/std::string());
51
52 CertVerifyResult result1, result2;
53 TestCompletionCallback callback1, callback2;
54 std::unique_ptr<CertVerifier::Request> request1, request2;
55
56 // Start an (asynchronous) initial request.
57 int error = verifier.Verify(request_params, &result1, callback1.callback(),
58 &request1, NetLogWithSource());
59 ASSERT_THAT(error, IsOk());
60 ASSERT_FALSE(request1);
61 ASSERT_TRUE(result1.verified_cert);
62 }
63
64 // Test that requests with identical parameters only result in a single
65 // underlying verification; that is, the second Request is joined to the
66 // in-progress first Request.
TEST_F(CoalescingCertVerifierTest,InflightJoin)67 TEST_F(CoalescingCertVerifierTest, InflightJoin) {
68 scoped_refptr<X509Certificate> test_cert(
69 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
70 ASSERT_TRUE(test_cert);
71
72 base::HistogramTester histograms;
73
74 CertVerifyResult fake_result;
75 fake_result.verified_cert = test_cert;
76
77 std::unique_ptr<MockCertVerifier> mock_verifier_owner =
78 std::make_unique<MockCertVerifier>();
79 MockCertVerifier* mock_verifier = mock_verifier_owner.get();
80 mock_verifier->set_async(true); // Always complete via PostTask
81 mock_verifier->AddResultForCert(test_cert, fake_result, OK);
82
83 CoalescingCertVerifier verifier(std::move(mock_verifier_owner));
84
85 CertVerifier::RequestParams request_params(test_cert, "www.example.com", 0,
86 /*ocsp_response=*/std::string(),
87 /*sct_list=*/std::string());
88
89 CertVerifyResult result1, result2;
90 TestCompletionCallback callback1, callback2;
91 std::unique_ptr<CertVerifier::Request> request1, request2;
92
93 // Start an (asynchronous) initial request.
94 int error = verifier.Verify(request_params, &result1, callback1.callback(),
95 &request1, NetLogWithSource());
96 ASSERT_THAT(error, IsError(ERR_IO_PENDING));
97 EXPECT_TRUE(request1);
98
99 // Simulate the underlying verifier returning different results if another
100 // verification is done.
101 mock_verifier->ClearRules();
102 mock_verifier->AddResultForCert(test_cert, fake_result, ERR_CERT_REVOKED);
103
104 // Start a second request; this should join the first request.
105 error = verifier.Verify(request_params, &result2, callback2.callback(),
106 &request2, NetLogWithSource());
107 ASSERT_THAT(error, IsError(ERR_IO_PENDING));
108 EXPECT_TRUE(request2);
109
110 // Ensure only one request was ever started.
111 EXPECT_EQ(2u, verifier.requests_for_testing());
112 EXPECT_EQ(1u, verifier.inflight_joins_for_testing());
113
114 // Make sure both results completed.
115 EXPECT_THAT(callback1.WaitForResult(), IsOk());
116 EXPECT_THAT(callback2.WaitForResult(), IsOk());
117
118 // There should only have been one Job started.
119 histograms.ExpectTotalCount("Net.CertVerifier_Job_Latency", 1);
120 histograms.ExpectTotalCount("Net.CertVerifier_First_Job_Latency", 1);
121 }
122
123 // Test that changing configurations between Requests prevents the second
124 // Request from being attached to the first Request. There should be two
125 // Requests to the underlying CertVerifier, and the correct results should be
126 // received by each.
TEST_F(CoalescingCertVerifierTest,DoesNotJoinAfterConfigChange)127 TEST_F(CoalescingCertVerifierTest, DoesNotJoinAfterConfigChange) {
128 scoped_refptr<X509Certificate> test_cert(
129 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
130 ASSERT_TRUE(test_cert);
131
132 base::HistogramTester histograms;
133
134 CertVerifyResult fake_result;
135 fake_result.verified_cert = test_cert;
136
137 std::unique_ptr<MockCertVerifier> mock_verifier_owner =
138 std::make_unique<MockCertVerifier>();
139 MockCertVerifier* mock_verifier = mock_verifier_owner.get();
140 mock_verifier->set_async(true); // Always complete via PostTask
141 mock_verifier->AddResultForCert(test_cert, fake_result, OK);
142
143 CoalescingCertVerifier verifier(std::move(mock_verifier_owner));
144
145 CertVerifier::Config config1;
146 verifier.SetConfig(config1);
147
148 CertVerifier::RequestParams request_params(test_cert, "www.example.com", 0,
149 /*ocsp_response=*/std::string(),
150 /*sct_list=*/std::string());
151
152 CertVerifyResult result1, result2;
153 TestCompletionCallback callback1, callback2;
154 std::unique_ptr<CertVerifier::Request> request1, request2;
155
156 // Start an (asynchronous) initial request.
157 int error = verifier.Verify(request_params, &result1, callback1.callback(),
158 &request1, NetLogWithSource());
159 ASSERT_THAT(error, IsError(ERR_IO_PENDING));
160 EXPECT_TRUE(request1);
161
162 // Change the configuration, and change the result to to simulate the
163 // configuration change affecting behavior.
164 CertVerifier::Config config2;
165 config2.enable_rev_checking = !config1.enable_rev_checking;
166 verifier.SetConfig(config2);
167 mock_verifier->ClearRules();
168 mock_verifier->AddResultForCert(test_cert, fake_result, ERR_CERT_REVOKED);
169
170 // Start a second request; this should not join the first request, as the
171 // config is different.
172 error = verifier.Verify(request_params, &result2, callback2.callback(),
173 &request2, NetLogWithSource());
174 ASSERT_THAT(error, IsError(ERR_IO_PENDING));
175 EXPECT_TRUE(request2);
176
177 // Ensure a total of two requests were started, and neither were joined.
178 EXPECT_EQ(2u, verifier.requests_for_testing());
179 EXPECT_EQ(0u, verifier.inflight_joins_for_testing());
180
181 // Make sure both results completed.
182 EXPECT_THAT(callback1.WaitForResult(), IsOk());
183 EXPECT_THAT(callback2.WaitForResult(), IsError(ERR_CERT_REVOKED));
184
185 // There should have been two separate Jobs.
186 histograms.ExpectTotalCount("Net.CertVerifier_Job_Latency", 2);
187 histograms.ExpectTotalCount("Net.CertVerifier_First_Job_Latency", 1);
188 }
189
190 // Test that the underlying CertVerifier changing configurations and triggering
191 // an OnCertVerifierChanged notification between Requests prevents the second
192 // Request from being attached to the first Request. There should be two
193 // Requests to the underlying CertVerifier, and the correct results should be
194 // received by each.
TEST_F(CoalescingCertVerifierTest,DoesNotJoinAfterUnderlyingVerifierChange)195 TEST_F(CoalescingCertVerifierTest, DoesNotJoinAfterUnderlyingVerifierChange) {
196 scoped_refptr<X509Certificate> test_cert(
197 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
198 ASSERT_TRUE(test_cert);
199
200 base::HistogramTester histograms;
201
202 CertVerifyResult fake_result;
203 fake_result.verified_cert = test_cert;
204
205 std::unique_ptr<MockCertVerifier> mock_verifier_owner =
206 std::make_unique<MockCertVerifier>();
207 MockCertVerifier* mock_verifier = mock_verifier_owner.get();
208 mock_verifier->set_async(true); // Always complete via PostTask
209 mock_verifier->AddResultForCert(test_cert, fake_result, OK);
210
211 CoalescingCertVerifier verifier(std::move(mock_verifier_owner));
212
213 mock_verifier->SimulateOnCertVerifierChanged();
214
215 CertVerifier::RequestParams request_params(test_cert, "www.example.com", 0,
216 /*ocsp_response=*/std::string(),
217 /*sct_list=*/std::string());
218
219 CertVerifyResult result1, result2;
220 TestCompletionCallback callback1, callback2;
221 std::unique_ptr<CertVerifier::Request> request1, request2;
222
223 // Start an (asynchronous) initial request.
224 int error = verifier.Verify(request_params, &result1, callback1.callback(),
225 &request1, NetLogWithSource());
226 ASSERT_THAT(error, IsError(ERR_IO_PENDING));
227 EXPECT_TRUE(request1);
228
229 // Change the configuration, and change the result to to simulate the
230 // configuration change affecting behavior.
231 mock_verifier->SimulateOnCertVerifierChanged();
232 mock_verifier->ClearRules();
233 mock_verifier->AddResultForCert(test_cert, fake_result, ERR_CERT_REVOKED);
234
235 // Start a second request; this should not join the first request, as the
236 // config is different.
237 error = verifier.Verify(request_params, &result2, callback2.callback(),
238 &request2, NetLogWithSource());
239 ASSERT_THAT(error, IsError(ERR_IO_PENDING));
240 EXPECT_TRUE(request2);
241
242 // Ensure a total of two requests were started, and neither were joined.
243 EXPECT_EQ(2u, verifier.requests_for_testing());
244 EXPECT_EQ(0u, verifier.inflight_joins_for_testing());
245
246 // Make sure both results completed.
247 EXPECT_THAT(callback1.WaitForResult(), IsOk());
248 EXPECT_THAT(callback2.WaitForResult(), IsError(ERR_CERT_REVOKED));
249
250 // There should have been two separate Jobs.
251 histograms.ExpectTotalCount("Net.CertVerifier_Job_Latency", 2);
252 histograms.ExpectTotalCount("Net.CertVerifier_First_Job_Latency", 1);
253 }
254
TEST_F(CoalescingCertVerifierTest,ObserverIsForwarded)255 TEST_F(CoalescingCertVerifierTest, ObserverIsForwarded) {
256 auto mock_cert_verifier_owner = std::make_unique<MockCertVerifier>();
257 MockCertVerifier* mock_cert_verifier = mock_cert_verifier_owner.get();
258 CoalescingCertVerifier verifier(std::move(mock_cert_verifier_owner));
259
260 CertVerifierObserverCounter observer_(&verifier);
261 EXPECT_EQ(observer_.change_count(), 0u);
262 // A CertVerifierChanged event on the wrapped verifier should be forwarded to
263 // observers registered on CoalescingCertVerifier.
264 mock_cert_verifier->SimulateOnCertVerifierChanged();
265 EXPECT_EQ(observer_.change_count(), 1u);
266 }
267
268 // Test that when two Requests are attached to the same Job, it's safe to
269 // delete the second Request while processing the response to the first. The
270 // second Request should not cause the second callback to be called.
TEST_F(CoalescingCertVerifierTest,DeleteSecondRequestDuringFirstCompletion)271 TEST_F(CoalescingCertVerifierTest, DeleteSecondRequestDuringFirstCompletion) {
272 scoped_refptr<X509Certificate> test_cert(
273 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
274 ASSERT_TRUE(test_cert);
275
276 CertVerifyResult fake_result;
277 fake_result.verified_cert = test_cert;
278
279 std::unique_ptr<MockCertVerifier> mock_verifier_owner =
280 std::make_unique<MockCertVerifier>();
281 MockCertVerifier* mock_verifier = mock_verifier_owner.get();
282 mock_verifier->set_async(true); // Always complete via PostTask
283 mock_verifier->AddResultForCert(test_cert, fake_result, OK);
284
285 CoalescingCertVerifier verifier(std::move(mock_verifier_owner));
286
287 CertVerifier::RequestParams request_params(test_cert, "www.example.com", 0,
288 /*ocsp_response=*/std::string(),
289 /*sct_list=*/std::string());
290
291 CertVerifyResult result1, result2;
292 TestCompletionCallback callback1, callback2;
293 std::unique_ptr<CertVerifier::Request> request1, request2;
294
295 // Start an (asynchronous) initial request. When this request is completed,
296 // it will delete (reset) |request2|, which should prevent it from being
297 // called.
298 int error = verifier.Verify(
299 request_params, &result1,
300 base::BindLambdaForTesting([&callback1, &request2](int result) {
301 request2.reset();
302 callback1.callback().Run(result);
303 }),
304 &request1, NetLogWithSource());
305 ASSERT_THAT(error, IsError(ERR_IO_PENDING));
306 EXPECT_TRUE(request1);
307
308 // Start a second request; this should join the first request.
309 error = verifier.Verify(request_params, &result2, callback2.callback(),
310 &request2, NetLogWithSource());
311 ASSERT_THAT(error, IsError(ERR_IO_PENDING));
312 EXPECT_TRUE(request2);
313
314 // Ensure only one underlying verification was started.
315 ASSERT_EQ(2u, verifier.requests_for_testing());
316 ASSERT_EQ(1u, verifier.inflight_joins_for_testing());
317
318 // Make sure that only the first callback is invoked; because the second
319 // CertVerifier::Request was deleted during processing the first's callback,
320 // the second callback should not be invoked.
321 EXPECT_THAT(callback1.WaitForResult(), IsOk());
322 ASSERT_FALSE(callback2.have_result());
323 ASSERT_FALSE(request2);
324
325 // While CoalescingCertVerifier doesn't use PostTask, make sure to flush the
326 // tasks as well, in case the implementation changes in the future.
327 RunUntilIdle();
328 ASSERT_FALSE(callback2.have_result());
329 ASSERT_FALSE(request2);
330 }
331
332 // Test that it's safe to delete the CoalescingCertVerifier during completion,
333 // even when there are outstanding Requests to be processed. The additional
334 // Requests should not invoke the user callback once the
335 // CoalescingCertVerifier is deleted.
TEST_F(CoalescingCertVerifierTest,DeleteVerifierDuringCompletion)336 TEST_F(CoalescingCertVerifierTest, DeleteVerifierDuringCompletion) {
337 scoped_refptr<X509Certificate> test_cert(
338 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
339 ASSERT_TRUE(test_cert);
340
341 CertVerifyResult fake_result;
342 fake_result.verified_cert = test_cert;
343
344 std::unique_ptr<MockCertVerifier> mock_verifier_owner =
345 std::make_unique<MockCertVerifier>();
346 MockCertVerifier* mock_verifier = mock_verifier_owner.get();
347 mock_verifier->set_async(true); // Always complete via PostTask
348 mock_verifier->AddResultForCert(test_cert, fake_result, OK);
349
350 auto verifier =
351 std::make_unique<CoalescingCertVerifier>(std::move(mock_verifier_owner));
352
353 CertVerifier::RequestParams request_params(test_cert, "www.example.com", 0,
354 /*ocsp_response=*/std::string(),
355 /*sct_list=*/std::string());
356
357 CertVerifyResult result1, result2;
358 TestCompletionCallback callback1, callback2;
359 std::unique_ptr<CertVerifier::Request> request1, request2;
360
361 // Start an (asynchronous) initial request. When this request is completed,
362 // it will delete (reset) |request2|, which should prevent it from being
363 // called.
364 int error = verifier->Verify(
365 request_params, &result1,
366 base::BindLambdaForTesting([&callback1, &verifier](int result) {
367 verifier.reset();
368 callback1.callback().Run(result);
369 }),
370 &request1, NetLogWithSource());
371 ASSERT_THAT(error, IsError(ERR_IO_PENDING));
372 EXPECT_TRUE(request1);
373
374 // Start a second request; this should join the first request.
375 error = verifier->Verify(request_params, &result2, callback2.callback(),
376 &request2, NetLogWithSource());
377 ASSERT_THAT(error, IsError(ERR_IO_PENDING));
378 EXPECT_TRUE(request2);
379
380 // Ensure only one underlying verification was started.
381 ASSERT_EQ(2u, verifier->requests_for_testing());
382 ASSERT_EQ(1u, verifier->inflight_joins_for_testing());
383
384 // Make sure that only the first callback is invoked. This will delete the
385 // underlying CoalescingCertVerifier, which should prevent the second
386 // request's callback from being invoked.
387 EXPECT_THAT(callback1.WaitForResult(), IsOk());
388 ASSERT_FALSE(callback2.have_result());
389 ASSERT_TRUE(request2);
390
391 // While CoalescingCertVerifier doesn't use PostTask, make sure to flush the
392 // tasks as well, in case the implementation changes in the future.
393 RunUntilIdle();
394 ASSERT_FALSE(callback2.have_result());
395 ASSERT_TRUE(request2);
396 }
397
398 // Test that it's safe to delete a Request before the underlying verifier has
399 // completed. This is a guard against memory safety (e.g. when this Request
400 // is the last/only Request remaining).
TEST_F(CoalescingCertVerifierTest,DeleteRequestBeforeCompletion)401 TEST_F(CoalescingCertVerifierTest, DeleteRequestBeforeCompletion) {
402 scoped_refptr<X509Certificate> test_cert(
403 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
404 ASSERT_TRUE(test_cert);
405
406 CertVerifyResult fake_result;
407 fake_result.verified_cert = test_cert;
408
409 std::unique_ptr<MockCertVerifier> mock_verifier_owner =
410 std::make_unique<MockCertVerifier>();
411 MockCertVerifier* mock_verifier = mock_verifier_owner.get();
412 mock_verifier->set_async(true); // Always complete via PostTask
413 mock_verifier->AddResultForCert(test_cert, fake_result, OK);
414
415 CoalescingCertVerifier verifier(std::move(mock_verifier_owner));
416
417 CertVerifier::RequestParams request_params(test_cert, "www.example.com", 0,
418 /*ocsp_response=*/std::string(),
419 /*sct_list=*/std::string());
420
421 CertVerifyResult result1;
422 TestCompletionCallback callback1;
423 std::unique_ptr<CertVerifier::Request> request1;
424
425 // Start an (asynchronous) initial request.
426 int error = verifier.Verify(request_params, &result1, callback1.callback(),
427 &request1, NetLogWithSource());
428 ASSERT_THAT(error, IsError(ERR_IO_PENDING));
429 EXPECT_TRUE(request1);
430
431 // Abandon the request before it's completed.
432 request1.reset();
433 EXPECT_FALSE(callback1.have_result());
434
435 // Make sure the request never completes / the callback is never invoked.
436 RunUntilIdle();
437 EXPECT_FALSE(callback1.have_result());
438 }
439
440 // Test that it's safe to delete a Request before the underlying verifier has
441 // completed. This is a correctness test, to ensure that other Requests are
442 // still notified.
TEST_F(CoalescingCertVerifierTest,DeleteFirstRequestBeforeCompletionStillCompletesSecondRequest)443 TEST_F(CoalescingCertVerifierTest,
444 DeleteFirstRequestBeforeCompletionStillCompletesSecondRequest) {
445 scoped_refptr<X509Certificate> test_cert(
446 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
447 ASSERT_TRUE(test_cert);
448
449 CertVerifyResult fake_result;
450 fake_result.verified_cert = test_cert;
451
452 std::unique_ptr<MockCertVerifier> mock_verifier_owner =
453 std::make_unique<MockCertVerifier>();
454 MockCertVerifier* mock_verifier = mock_verifier_owner.get();
455 mock_verifier->set_async(true); // Always complete via PostTask
456 mock_verifier->AddResultForCert(test_cert, fake_result, OK);
457
458 CoalescingCertVerifier verifier(std::move(mock_verifier_owner));
459
460 CertVerifier::RequestParams request_params(test_cert, "www.example.com", 0,
461 /*ocsp_response=*/std::string(),
462 /*sct_list=*/std::string());
463
464 CertVerifyResult result1, result2;
465 TestCompletionCallback callback1, callback2;
466 std::unique_ptr<CertVerifier::Request> request1, request2;
467
468 // Start an (asynchronous) initial request.
469 int error = verifier.Verify(request_params, &result1, callback1.callback(),
470 &request1, NetLogWithSource());
471 ASSERT_THAT(error, IsError(ERR_IO_PENDING));
472 EXPECT_TRUE(request1);
473
474 // Start a second request; this should join the first request.
475 error = verifier.Verify(request_params, &result2, callback2.callback(),
476 &request2, NetLogWithSource());
477 ASSERT_THAT(error, IsError(ERR_IO_PENDING));
478 EXPECT_TRUE(request2);
479
480 // Ensure only one underlying verification was started.
481 ASSERT_EQ(2u, verifier.requests_for_testing());
482 ASSERT_EQ(1u, verifier.inflight_joins_for_testing());
483
484 // Abandon the first request before it's completed.
485 request1.reset();
486
487 // Make sure the first request never completes / the callback is never
488 // invoked, while the second request completes normally.
489 EXPECT_THAT(callback2.WaitForResult(), IsOk());
490 EXPECT_FALSE(callback1.have_result());
491
492 // Simulate the second request going away during processing.
493 request2.reset();
494
495 // Flush any events, although there should not be any.
496 RunUntilIdle();
497 EXPECT_FALSE(callback1.have_result());
498 }
499
TEST_F(CoalescingCertVerifierTest,DeleteRequestDuringCompletion)500 TEST_F(CoalescingCertVerifierTest, DeleteRequestDuringCompletion) {
501 scoped_refptr<X509Certificate> test_cert(
502 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
503 ASSERT_TRUE(test_cert);
504
505 CertVerifyResult fake_result;
506 fake_result.verified_cert = test_cert;
507
508 std::unique_ptr<MockCertVerifier> mock_verifier_owner =
509 std::make_unique<MockCertVerifier>();
510 MockCertVerifier* mock_verifier = mock_verifier_owner.get();
511 mock_verifier->set_async(true); // Always complete via PostTask
512 mock_verifier->AddResultForCert(test_cert, fake_result, OK);
513
514 CoalescingCertVerifier verifier(std::move(mock_verifier_owner));
515
516 CertVerifier::RequestParams request_params(test_cert, "www.example.com", 0,
517 /*ocsp_response=*/std::string(),
518 /*sct_list=*/std::string());
519
520 CertVerifyResult result1;
521 TestCompletionCallback callback1;
522 std::unique_ptr<CertVerifier::Request> request1;
523
524 // Start an (asynchronous) initial request.
525 int error = verifier.Verify(
526 request_params, &result1,
527 base::BindLambdaForTesting([&callback1, &request1](int result) {
528 // Delete the Request during the completion callback. This should be
529 // perfectly safe, and not cause any memory trouble, because the
530 // Request was already detached from the Job prior to being invoked.
531 request1.reset();
532 callback1.callback().Run(result);
533 }),
534 &request1, NetLogWithSource());
535 ASSERT_THAT(error, IsError(ERR_IO_PENDING));
536 EXPECT_TRUE(request1);
537
538 // The result should be available, even though the request is deleted
539 // during the result processing. This should not cause any memory errors.
540 EXPECT_THAT(callback1.WaitForResult(), IsOk());
541 }
542
TEST_F(CoalescingCertVerifierTest,DeleteVerifierBeforeRequest)543 TEST_F(CoalescingCertVerifierTest, DeleteVerifierBeforeRequest) {
544 scoped_refptr<X509Certificate> test_cert(
545 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
546 ASSERT_TRUE(test_cert);
547
548 base::HistogramTester histograms;
549
550 CertVerifyResult fake_result;
551 fake_result.verified_cert = test_cert;
552
553 std::unique_ptr<MockCertVerifier> mock_verifier_owner =
554 std::make_unique<MockCertVerifier>();
555 MockCertVerifier* mock_verifier = mock_verifier_owner.get();
556 mock_verifier->set_async(true); // Always complete via PostTask
557 mock_verifier->AddResultForCert(test_cert, fake_result, OK);
558
559 auto verifier =
560 std::make_unique<CoalescingCertVerifier>(std::move(mock_verifier_owner));
561
562 CertVerifier::RequestParams request_params(test_cert, "www.example.com", 0,
563 /*ocsp_response=*/std::string(),
564 /*sct_list=*/std::string());
565
566 CertVerifyResult result1;
567 TestCompletionCallback callback1;
568 std::unique_ptr<CertVerifier::Request> request1;
569
570 // Start an (asynchronous) initial request.
571 int error = verifier->Verify(request_params, &result1, callback1.callback(),
572 &request1, NetLogWithSource());
573 ASSERT_THAT(error, IsError(ERR_IO_PENDING));
574 EXPECT_TRUE(request1);
575
576 // Delete the CoalescingCertVerifier first. This should orphan all
577 // outstanding Requests and delete all associated Jobs.
578 verifier.reset();
579
580 // Flush any pending tasks; there should not be any, at this point, but use
581 // it in case the implementation changes.
582 RunUntilIdle();
583
584 // Make sure the callback was never called.
585 EXPECT_FALSE(callback1.have_result());
586
587 // Delete the Request. This should be a no-op as the Request was orphaned
588 // when the CoalescingCertVerifier was deleted.
589 request1.reset();
590
591 // There should not have been any histograms logged.
592 histograms.ExpectTotalCount("Net.CertVerifier_Job_Latency", 0);
593 histograms.ExpectTotalCount("Net.CertVerifier_First_Job_Latency", 0);
594 }
595
596 } // namespace net
597