1 // Copyright 2015 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.
5 #include "net/cert_net/cert_net_fetcher_impl.h"
9 #include "base/compiler_specific.h"
10 #include "base/run_loop.h"
11 #include "net/cert/mock_cert_verifier.h"
12 #include "net/dns/mock_host_resolver.h"
13 #include "net/http/http_server_properties_impl.h"
14 #include "net/test/spawned_test_server/spawned_test_server.h"
15 #include "net/url_request/url_request_job_factory_impl.h"
16 #include "net/url_request/url_request_test_util.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "testing/platform_test.h"
20 // TODO(eroman): Test that cookies aren't sent.
22 using base::ASCIIToUTF16
;
28 const base::FilePath::CharType kDocRoot
[] =
29 FILE_PATH_LITERAL("net/data/cert_net_fetcher_impl_unittest");
31 // A non-mock URLRequestContext which can access http:// urls.
32 class RequestContext
: public URLRequestContext
{
34 RequestContext() : storage_(this) {
36 storage_
.set_host_resolver(scoped_ptr
<HostResolver
>(new MockHostResolver
));
37 storage_
.set_cert_verifier(new MockCertVerifier
);
38 storage_
.set_transport_security_state(new TransportSecurityState
);
39 storage_
.set_proxy_service(ProxyService::CreateFixed(no_proxy
));
40 storage_
.set_ssl_config_service(new SSLConfigServiceDefaults
);
41 storage_
.set_http_server_properties(
42 scoped_ptr
<HttpServerProperties
>(new HttpServerPropertiesImpl()));
44 HttpNetworkSession::Params params
;
45 params
.host_resolver
= host_resolver();
46 params
.cert_verifier
= cert_verifier();
47 params
.transport_security_state
= transport_security_state();
48 params
.proxy_service
= proxy_service();
49 params
.ssl_config_service
= ssl_config_service();
50 params
.http_server_properties
= http_server_properties();
51 scoped_refptr
<HttpNetworkSession
> network_session(
52 new HttpNetworkSession(params
));
53 storage_
.set_http_transaction_factory(new HttpCache(
54 network_session
.get(), HttpCache::DefaultBackend::InMemory(0)));
55 URLRequestJobFactoryImpl
* job_factory
= new URLRequestJobFactoryImpl();
56 storage_
.set_job_factory(job_factory
);
59 ~RequestContext() override
{ AssertNoURLRequests(); }
62 URLRequestContextStorage storage_
;
67 FetchResult(Error net_error
, const std::vector
<uint8_t>& response_body
)
68 : net_error_(net_error
), response_body_(response_body
) {}
70 void VerifySuccess(const std::string
& expected_body
) {
71 EXPECT_EQ(OK
, net_error_
);
72 EXPECT_EQ(expected_body
,
73 std::string(response_body_
.begin(), response_body_
.end()));
76 void VerifyFailure(Error expected_error
) {
77 EXPECT_EQ(expected_error
, net_error_
);
78 EXPECT_EQ(0u, response_body_
.size());
82 const Error net_error_
;
83 const std::vector
<uint8_t> response_body_
;
86 // Helper to synchronously wait for the fetch completion. This is similar to
87 // net's TestCompletionCallback, but built around FetchCallback.
88 class TestFetchCallback
{
91 : callback_(base::Bind(&TestFetchCallback::OnCallback
,
92 base::Unretained(this))) {}
94 const CertNetFetcher::FetchCallback
& callback() const { return callback_
; }
96 scoped_ptr
<FetchResult
> WaitForResult() {
97 DCHECK(quit_closure_
.is_null());
98 while (!HasResult()) {
99 base::RunLoop run_loop
;
100 quit_closure_
= run_loop
.QuitClosure();
102 quit_closure_
.Reset();
104 return result_
.Pass();
107 bool HasResult() const { return result_
.get(); }
109 // Sets an extra action (in addition to recording the result) that is run when
110 // the FetchCallback is invoked.
111 void set_extra_closure(const base::Closure
& closure
) {
112 extra_closure_
= closure
;
116 void OnCallback(Error net_error
, const std::vector
<uint8_t>& response_body
) {
117 DCHECK(!HasResult());
118 result_
.reset(new FetchResult(net_error
, response_body
));
120 if (!extra_closure_
.is_null())
121 extra_closure_
.Run();
123 if (!quit_closure_
.is_null())
127 CertNetFetcher::FetchCallback callback_
;
128 scoped_ptr
<FetchResult
> result_
;
129 base::Closure quit_closure_
;
130 base::Closure extra_closure_
;
135 class CertNetFetcherImplTest
: public PlatformTest
{
137 CertNetFetcherImplTest()
138 : test_server_(SpawnedTestServer::TYPE_HTTP
,
139 net::SpawnedTestServer::kLocalhost
,
140 base::FilePath(kDocRoot
)) {
141 context_
.set_network_delegate(&network_delegate_
);
145 SpawnedTestServer test_server_
;
146 TestNetworkDelegate network_delegate_
;
147 RequestContext context_
;
150 // Helper to start an AIA fetch using default parameters.
151 WARN_UNUSED_RESULT scoped_ptr
<CertNetFetcher::Request
> StartRequest(
152 CertNetFetcher
* fetcher
,
154 const TestFetchCallback
& callback
) {
155 return fetcher
->FetchCaIssuers(url
, CertNetFetcher::DEFAULT
,
156 CertNetFetcher::DEFAULT
, callback
.callback());
159 // Fetch a few unique URLs using GET in parallel. Each URL has a different body
161 TEST_F(CertNetFetcherImplTest
, ParallelFetchNoDuplicates
) {
162 ASSERT_TRUE(test_server_
.Start());
164 CertNetFetcherImpl
fetcher(&context_
);
165 TestFetchCallback callback1
;
166 TestFetchCallback callback2
;
167 TestFetchCallback callback3
;
169 // Request a URL with Content-Type "application/pkix-cert"
170 GURL url1
= test_server_
.GetURL("files/cert.crt");
171 scoped_ptr
<CertNetFetcher::Request
> request1
=
172 StartRequest(&fetcher
, url1
, callback1
);
174 // Request a URL with Content-Type "application/pkix-crl"
175 GURL url2
= test_server_
.GetURL("files/root.crl");
176 scoped_ptr
<CertNetFetcher::Request
> request2
=
177 StartRequest(&fetcher
, url2
, callback2
);
179 // Request a URL with Content-Type "application/pkcs7-mime"
180 GURL url3
= test_server_
.GetURL("files/certs.p7c");
181 scoped_ptr
<CertNetFetcher::Request
> request3
=
182 StartRequest(&fetcher
, url3
, callback3
);
184 // Wait for all of the requests to complete.
185 scoped_ptr
<FetchResult
> result1
= callback1
.WaitForResult();
186 scoped_ptr
<FetchResult
> result2
= callback2
.WaitForResult();
187 scoped_ptr
<FetchResult
> result3
= callback3
.WaitForResult();
189 // Verify the fetch results.
190 result1
->VerifySuccess("-cert.crt-\n");
191 result2
->VerifySuccess("-root.crl-\n");
192 result3
->VerifySuccess("-certs.p7c-\n");
194 EXPECT_EQ(3, network_delegate_
.created_requests());
197 // Fetch a caIssuers URL which has an unexpected extension and Content-Type.
198 // The extension is .txt and the Content-Type is text/plain. Despite being
199 // unusual this succeeds as the extension and Content-Type are not required to
201 TEST_F(CertNetFetcherImplTest
, ContentTypeDoesntMatter
) {
202 ASSERT_TRUE(test_server_
.Start());
204 CertNetFetcherImpl
fetcher(&context_
);
206 TestFetchCallback callback
;
207 GURL url
= test_server_
.GetURL("files/foo.txt");
208 scoped_ptr
<CertNetFetcher::Request
> request
=
209 StartRequest(&fetcher
, url
, callback
);
210 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
211 result
->VerifySuccess("-foo.txt-\n");
214 // Fetch a URLs whose HTTP response code is not 200. These are considered
216 TEST_F(CertNetFetcherImplTest
, HttpStatusCode
) {
217 ASSERT_TRUE(test_server_
.Start());
219 CertNetFetcherImpl
fetcher(&context_
);
221 // Response was HTTP status 404.
223 TestFetchCallback callback
;
224 GURL url
= test_server_
.GetURL("files/404.html");
225 scoped_ptr
<CertNetFetcher::Request
> request
=
226 StartRequest(&fetcher
, url
, callback
);
227 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
228 result
->VerifyFailure(ERR_FAILED
);
231 // Response was HTTP status 500.
233 TestFetchCallback callback
;
234 GURL url
= test_server_
.GetURL("files/500.html");
235 scoped_ptr
<CertNetFetcher::Request
> request
=
236 StartRequest(&fetcher
, url
, callback
);
237 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
238 result
->VerifyFailure(ERR_FAILED
);
242 // Fetching a URL with a Content-Disposition header should have no effect.
243 TEST_F(CertNetFetcherImplTest
, ContentDisposition
) {
244 ASSERT_TRUE(test_server_
.Start());
246 CertNetFetcherImpl
fetcher(&context_
);
248 TestFetchCallback callback
;
249 GURL url
= test_server_
.GetURL("files/downloadable.js");
250 scoped_ptr
<CertNetFetcher::Request
> request
=
251 StartRequest(&fetcher
, url
, callback
);
252 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
253 result
->VerifySuccess("-downloadable.js-\n");
256 // Verifies that a cachable request will be served from the HTTP cache the
257 // second time it is requested.
258 TEST_F(CertNetFetcherImplTest
, Cache
) {
259 ASSERT_TRUE(test_server_
.Start());
261 CertNetFetcherImpl
fetcher(&context_
);
263 // Fetch a URL whose HTTP headers make it cacheable for 1 hour.
264 GURL
url(test_server_
.GetURL("files/cacheable_1hr.crt"));
266 TestFetchCallback callback
;
268 scoped_ptr
<CertNetFetcher::Request
> request
=
269 StartRequest(&fetcher
, url
, callback
);
270 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
271 result
->VerifySuccess("-cacheable_1hr.crt-\n");
274 EXPECT_EQ(1, network_delegate_
.created_requests());
276 // Kill the HTTP server.
277 ASSERT_TRUE(test_server_
.Stop());
279 // Fetch again -- will fail unless served from cache.
281 TestFetchCallback callback
;
282 scoped_ptr
<CertNetFetcher::Request
> request
=
283 StartRequest(&fetcher
, url
, callback
);
284 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
285 result
->VerifySuccess("-cacheable_1hr.crt-\n");
288 EXPECT_EQ(2, network_delegate_
.created_requests());
291 // Verify that the maximum response body constraints are enforced by fetching a
292 // resource that is larger than the limit.
293 TEST_F(CertNetFetcherImplTest
, TooLarge
) {
294 ASSERT_TRUE(test_server_
.Start());
296 CertNetFetcherImpl
fetcher(&context_
);
298 // This file has a response body 12 bytes long. So setting the maximum to 11
299 // bytes will cause it to fail.
300 GURL
url(test_server_
.GetURL("files/certs.p7c"));
301 TestFetchCallback callback
;
302 scoped_ptr
<CertNetFetcher::Request
> request
= fetcher
.FetchCaIssuers(
303 url
, CertNetFetcher::DEFAULT
, 11, callback
.callback());
305 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
306 result
->VerifyFailure(ERR_FILE_TOO_BIG
);
309 // Set the timeout to 10 milliseconds, and try fetching a URL that takes 5
310 // seconds to complete. It should fail due to a timeout.
311 TEST_F(CertNetFetcherImplTest
, Hang
) {
312 ASSERT_TRUE(test_server_
.Start());
314 CertNetFetcherImpl
fetcher(&context_
);
316 GURL
url(test_server_
.GetURL("slow/certs.p7c?5"));
317 TestFetchCallback callback
;
318 scoped_ptr
<CertNetFetcher::Request
> request
= fetcher
.FetchCaIssuers(
319 url
, 10, CertNetFetcher::DEFAULT
, callback
.callback());
320 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
321 result
->VerifyFailure(ERR_TIMED_OUT
);
324 // Verify that if a response is gzip-encoded it gets inflated before being
325 // returned to the caller.
326 TEST_F(CertNetFetcherImplTest
, Gzip
) {
327 ASSERT_TRUE(test_server_
.Start());
329 CertNetFetcherImpl
fetcher(&context_
);
331 GURL
url(test_server_
.GetURL("files/gzipped_crl"));
332 TestFetchCallback callback
;
333 scoped_ptr
<CertNetFetcher::Request
> request
=
334 StartRequest(&fetcher
, url
, callback
);
335 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
336 result
->VerifySuccess("-gzipped_crl-\n");
339 // Try fetching an unsupported URL scheme (https).
340 TEST_F(CertNetFetcherImplTest
, HttpsNotAllowed
) {
341 ASSERT_TRUE(test_server_
.Start());
343 CertNetFetcherImpl
fetcher(&context_
);
345 GURL
url("https://foopy/foo.crt");
346 TestFetchCallback callback
;
347 scoped_ptr
<CertNetFetcher::Request
> request
=
348 StartRequest(&fetcher
, url
, callback
);
349 // Should NOT complete synchronously despite being a test that could be done
351 EXPECT_FALSE(callback
.HasResult());
352 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
353 result
->VerifyFailure(ERR_DISALLOWED_URL_SCHEME
);
355 // No request was created because the URL scheme was unsupported.
356 EXPECT_EQ(0, network_delegate_
.created_requests());
359 // Try fetching a URL which redirects to https.
360 TEST_F(CertNetFetcherImplTest
, RedirectToHttpsNotAllowed
) {
361 ASSERT_TRUE(test_server_
.Start());
363 CertNetFetcherImpl
fetcher(&context_
);
365 GURL
url(test_server_
.GetURL("files/redirect_https"));
366 TestFetchCallback callback
;
368 scoped_ptr
<CertNetFetcher::Request
> request
=
369 StartRequest(&fetcher
, url
, callback
);
370 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
371 result
->VerifyFailure(ERR_DISALLOWED_URL_SCHEME
);
373 EXPECT_EQ(1, network_delegate_
.created_requests());
376 // Try fetching an unsupported URL scheme (https) and then immediately
377 // cancelling. This is a bit special because this codepath needs to post a task.
378 TEST_F(CertNetFetcherImplTest
, CancelHttpsNotAllowed
) {
379 ASSERT_TRUE(test_server_
.Start());
381 CertNetFetcherImpl
fetcher(&context_
);
383 GURL
url("https://foopy/foo.crt");
384 TestFetchCallback callback
;
385 scoped_ptr
<CertNetFetcher::Request
> request
=
386 StartRequest(&fetcher
, url
, callback
);
388 // Cancel the request.
391 // Spin the message loop to increase chance of catching a bug.
392 base::RunLoop().RunUntilIdle();
394 // Should NOT complete synchronously despite being a test that could be done
396 EXPECT_FALSE(callback
.HasResult());
398 EXPECT_EQ(0, network_delegate_
.created_requests());
401 // Start a few requests, and cancel one of them before running the message loop
403 TEST_F(CertNetFetcherImplTest
, CancelBeforeRunningMessageLoop
) {
404 ASSERT_TRUE(test_server_
.Start());
406 CertNetFetcherImpl
fetcher(&context_
);
407 TestFetchCallback callback1
;
408 TestFetchCallback callback2
;
409 TestFetchCallback callback3
;
411 GURL url1
= test_server_
.GetURL("files/cert.crt");
412 scoped_ptr
<CertNetFetcher::Request
> request1
=
413 StartRequest(&fetcher
, url1
, callback1
);
415 GURL url2
= test_server_
.GetURL("files/root.crl");
416 scoped_ptr
<CertNetFetcher::Request
> request2
=
417 StartRequest(&fetcher
, url2
, callback2
);
419 GURL url3
= test_server_
.GetURL("files/certs.p7c");
421 scoped_ptr
<CertNetFetcher::Request
> request3
=
422 StartRequest(&fetcher
, url3
, callback3
);
424 EXPECT_EQ(3, network_delegate_
.created_requests());
425 EXPECT_FALSE(callback1
.HasResult());
426 EXPECT_FALSE(callback2
.HasResult());
427 EXPECT_FALSE(callback3
.HasResult());
429 // Cancel the second request.
432 // Wait for the non-cancelled requests to complete.
433 scoped_ptr
<FetchResult
> result1
= callback1
.WaitForResult();
434 scoped_ptr
<FetchResult
> result3
= callback3
.WaitForResult();
436 // Verify the fetch results.
437 result1
->VerifySuccess("-cert.crt-\n");
438 result3
->VerifySuccess("-certs.p7c-\n");
440 EXPECT_FALSE(callback2
.HasResult());
443 // Start several requests, and cancel one of them after the first has completed.
444 // NOTE: The python test server is single threaded and can only service one
445 // request at a time. After a socket is opened by the server it waits for it to
446 // be completed, and any subsequent request will hang until the first socket is
448 // Cancelling the first request can therefore be problematic, since if
449 // cancellation is done after the socket is opened but before reading/writing,
450 // then the socket is re-cycled and things will be stalled until the cleanup
451 // timer (10 seconds) closes it.
452 // To work around this, the last request is cancelled, and hope that the
453 // requests are given opened sockets in a FIFO order.
454 // TODO(eroman): Make this more robust.
455 TEST_F(CertNetFetcherImplTest
, CancelAfterRunningMessageLoop
) {
456 ASSERT_TRUE(test_server_
.Start());
458 CertNetFetcherImpl
fetcher(&context_
);
459 TestFetchCallback callback1
;
460 TestFetchCallback callback2
;
461 TestFetchCallback callback3
;
463 GURL url1
= test_server_
.GetURL("files/cert.crt");
465 scoped_ptr
<CertNetFetcher::Request
> request1
=
466 StartRequest(&fetcher
, url1
, callback1
);
468 GURL url2
= test_server_
.GetURL("files/certs.p7c");
469 scoped_ptr
<CertNetFetcher::Request
> request2
=
470 StartRequest(&fetcher
, url2
, callback2
);
472 GURL
url3("ftp://www.not.supported.com/foo");
473 scoped_ptr
<CertNetFetcher::Request
> request3
=
474 StartRequest(&fetcher
, url3
, callback3
);
476 EXPECT_FALSE(callback1
.HasResult());
477 EXPECT_FALSE(callback2
.HasResult());
478 EXPECT_FALSE(callback3
.HasResult());
480 // Wait for the ftp request to complete (it should complete right away since
481 // it doesn't even try to connect to the server).
482 scoped_ptr
<FetchResult
> result3
= callback3
.WaitForResult();
483 result3
->VerifyFailure(ERR_DISALLOWED_URL_SCHEME
);
485 // Cancel the second outstanding request.
488 // Wait for the first request to complete.
489 scoped_ptr
<FetchResult
> result2
= callback1
.WaitForResult();
491 // Verify the fetch results.
492 result2
->VerifySuccess("-cert.crt-\n");
495 // Delete a CertNetFetcherImpl with outstanding requests on it.
496 TEST_F(CertNetFetcherImplTest
, DeleteCancels
) {
497 ASSERT_TRUE(test_server_
.Start());
499 scoped_ptr
<CertNetFetcherImpl
> fetcher(new CertNetFetcherImpl(&context_
));
501 GURL
url(test_server_
.GetURL("slow/certs.p7c?20"));
502 TestFetchCallback callback
;
503 scoped_ptr
<CertNetFetcher::Request
> request
=
504 StartRequest(fetcher
.get(), url
, callback
);
506 // Destroy the fetcher before the outstanding request.
510 // Fetch the same URLs in parallel and verify that only 1 request is made per
512 TEST_F(CertNetFetcherImplTest
, ParallelFetchDuplicates
) {
513 ASSERT_TRUE(test_server_
.Start());
515 CertNetFetcherImpl
fetcher(&context_
);
517 GURL url1
= test_server_
.GetURL("files/cert.crt");
518 GURL url2
= test_server_
.GetURL("files/root.crl");
520 // Issue 3 requests for url1, and 3 requests for url2
521 TestFetchCallback callback1
;
522 scoped_ptr
<CertNetFetcher::Request
> request1
=
523 StartRequest(&fetcher
, url1
, callback1
);
525 TestFetchCallback callback2
;
526 scoped_ptr
<CertNetFetcher::Request
> request2
=
527 StartRequest(&fetcher
, url2
, callback2
);
529 TestFetchCallback callback3
;
530 scoped_ptr
<CertNetFetcher::Request
> request3
=
531 StartRequest(&fetcher
, url1
, callback3
);
533 TestFetchCallback callback4
;
534 scoped_ptr
<CertNetFetcher::Request
> request4
=
535 StartRequest(&fetcher
, url2
, callback4
);
537 TestFetchCallback callback5
;
538 scoped_ptr
<CertNetFetcher::Request
> request5
=
539 StartRequest(&fetcher
, url2
, callback5
);
541 TestFetchCallback callback6
;
542 scoped_ptr
<CertNetFetcher::Request
> request6
=
543 StartRequest(&fetcher
, url1
, callback6
);
545 // Cancel all but one of the requests for url1.
549 // Wait for the remaining requests to finish.
550 scoped_ptr
<FetchResult
> result2
= callback2
.WaitForResult();
551 scoped_ptr
<FetchResult
> result4
= callback4
.WaitForResult();
552 scoped_ptr
<FetchResult
> result5
= callback5
.WaitForResult();
553 scoped_ptr
<FetchResult
> result6
= callback6
.WaitForResult();
555 // Verify that none of the cancelled requests for url1 completed (since they
557 EXPECT_FALSE(callback1
.HasResult());
558 EXPECT_FALSE(callback3
.HasResult());
560 // Verify the fetch results.
561 result2
->VerifySuccess("-root.crl-\n");
562 result4
->VerifySuccess("-root.crl-\n");
563 result5
->VerifySuccess("-root.crl-\n");
564 result6
->VerifySuccess("-cert.crt-\n");
566 // Verify that only 2 URLRequests were started even though 6 requests were
568 EXPECT_EQ(2, network_delegate_
.created_requests());
571 // Cancel a request and then start another one for the same URL.
572 TEST_F(CertNetFetcherImplTest
, CancelThenStart
) {
573 ASSERT_TRUE(test_server_
.Start());
575 CertNetFetcherImpl
fetcher(&context_
);
576 TestFetchCallback callback1
;
577 TestFetchCallback callback2
;
578 TestFetchCallback callback3
;
580 GURL url
= test_server_
.GetURL("files/cert.crt");
582 scoped_ptr
<CertNetFetcher::Request
> request1
=
583 StartRequest(&fetcher
, url
, callback1
);
586 scoped_ptr
<CertNetFetcher::Request
> request2
=
587 StartRequest(&fetcher
, url
, callback2
);
589 scoped_ptr
<CertNetFetcher::Request
> request3
=
590 StartRequest(&fetcher
, url
, callback3
);
593 // All but |request2| were canceled.
594 scoped_ptr
<FetchResult
> result
= callback2
.WaitForResult();
596 result
->VerifySuccess("-cert.crt-\n");
598 EXPECT_FALSE(callback1
.HasResult());
599 EXPECT_FALSE(callback3
.HasResult());
601 // One URLRequest that was cancelled, then another right afterwards.
602 EXPECT_EQ(2, network_delegate_
.created_requests());
605 // Start duplicate requests and then cancel all of them.
606 TEST_F(CertNetFetcherImplTest
, CancelAll
) {
607 ASSERT_TRUE(test_server_
.Start());
609 CertNetFetcherImpl
fetcher(&context_
);
610 TestFetchCallback callback
[3];
611 scoped_ptr
<CertNetFetcher::Request
> request
[3];
613 GURL url
= test_server_
.GetURL("files/cert.crt");
615 for (size_t i
= 0; i
< arraysize(callback
); ++i
) {
616 request
[i
] = StartRequest(&fetcher
, url
, callback
[i
]);
619 // Cancel all the requests.
620 for (size_t i
= 0; i
< arraysize(request
); ++i
)
623 EXPECT_EQ(1, network_delegate_
.created_requests());
625 for (size_t i
= 0; i
< arraysize(request
); ++i
)
626 EXPECT_FALSE(callback
[i
].HasResult());
629 void DeleteCertNetFetcher(CertNetFetcher
* fetcher
) {
633 // Delete the CertNetFetcherImpl within a request callback.
634 TEST_F(CertNetFetcherImplTest
, DeleteWithinCallback
) {
635 ASSERT_TRUE(test_server_
.Start());
637 // Deleted by callback2.
638 CertNetFetcher
* fetcher
= new CertNetFetcherImpl(&context_
);
640 GURL url
= test_server_
.GetURL("files/cert.crt");
642 TestFetchCallback callback
[4];
643 scoped_ptr
<CertNetFetcher::Request
> reqs
[4];
644 callback
[1].set_extra_closure(base::Bind(DeleteCertNetFetcher
, fetcher
));
646 for (size_t i
= 0; i
< arraysize(callback
); ++i
)
647 reqs
[i
] = StartRequest(fetcher
, url
, callback
[i
]);
649 EXPECT_EQ(1, network_delegate_
.created_requests());
651 callback
[1].WaitForResult();
653 // Assume requests for the same URL are executed in FIFO order.
654 EXPECT_TRUE(callback
[0].HasResult());
655 EXPECT_FALSE(callback
[2].HasResult());
656 EXPECT_FALSE(callback
[3].HasResult());
659 void FetchRequest(CertNetFetcher
* fetcher
,
661 TestFetchCallback
* callback
,
662 scoped_ptr
<CertNetFetcher::Request
>* request
) {
663 *request
= StartRequest(fetcher
, url
, *callback
);
666 // Make a request during callback for the same URL.
667 TEST_F(CertNetFetcherImplTest
, FetchWithinCallback
) {
668 ASSERT_TRUE(test_server_
.Start());
670 CertNetFetcherImpl
fetcher(&context_
);
672 GURL url
= test_server_
.GetURL("files/cert.crt");
674 TestFetchCallback callback
[5];
675 scoped_ptr
<CertNetFetcher::Request
> req
[5];
676 callback
[1].set_extra_closure(
677 base::Bind(FetchRequest
, &fetcher
, url
, &callback
[4], &req
[4]));
679 for (size_t i
= 0; i
< arraysize(callback
) - 1; ++i
)
680 req
[i
] = StartRequest(&fetcher
, url
, callback
[i
]);
682 EXPECT_EQ(1, network_delegate_
.created_requests());
684 for (size_t i
= 0; i
< arraysize(callback
); ++i
) {
685 scoped_ptr
<FetchResult
> result
= callback
[i
].WaitForResult();
686 result
->VerifySuccess("-cert.crt-\n");
689 // The fetch started within a callback should have started a new request
690 // rather than attaching to the current job.
691 EXPECT_EQ(2, network_delegate_
.created_requests());
694 void CancelRequest(scoped_ptr
<CertNetFetcher::Request
>* request
) {
698 // Cancel a request while executing a callback for the same job.
699 TEST_F(CertNetFetcherImplTest
, CancelWithinCallback
) {
700 ASSERT_TRUE(test_server_
.Start());
702 CertNetFetcherImpl
fetcher(&context_
);
704 GURL url
= test_server_
.GetURL("files/cert.crt");
706 TestFetchCallback callback
[4];
707 scoped_ptr
<CertNetFetcher::Request
> request
[4];
709 for (size_t i
= 0; i
< arraysize(callback
); ++i
)
710 request
[i
] = StartRequest(&fetcher
, url
, callback
[i
]);
712 // Cancel request[2] when the callback for request[1] runs.
713 callback
[1].set_extra_closure(base::Bind(CancelRequest
, &request
[2]));
715 EXPECT_EQ(1, network_delegate_
.created_requests());
717 for (size_t i
= 0; i
< arraysize(request
); ++i
) {
721 scoped_ptr
<FetchResult
> result
= callback
[i
].WaitForResult();
722 result
->VerifySuccess("-cert.crt-\n");
725 // request[2] was cancelled.
726 EXPECT_FALSE(callback
[2].HasResult());