• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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