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(make_scoped_ptr(new MockCertVerifier
).Pass());
38 storage_
.set_transport_security_state(
39 make_scoped_ptr(new TransportSecurityState
));
40 storage_
.set_proxy_service(ProxyService::CreateFixed(no_proxy
));
41 storage_
.set_ssl_config_service(new SSLConfigServiceDefaults
);
42 storage_
.set_http_server_properties(
43 scoped_ptr
<HttpServerProperties
>(new HttpServerPropertiesImpl()));
45 HttpNetworkSession::Params params
;
46 params
.host_resolver
= host_resolver();
47 params
.cert_verifier
= cert_verifier();
48 params
.transport_security_state
= transport_security_state();
49 params
.proxy_service
= proxy_service();
50 params
.ssl_config_service
= ssl_config_service();
51 params
.http_server_properties
= http_server_properties();
52 scoped_refptr
<HttpNetworkSession
> network_session(
53 new HttpNetworkSession(params
));
54 storage_
.set_http_transaction_factory(
55 make_scoped_ptr(new HttpCache(network_session
.get(),
56 HttpCache::DefaultBackend::InMemory(0)))
58 storage_
.set_job_factory(
59 make_scoped_ptr(new URLRequestJobFactoryImpl()).Pass());
62 ~RequestContext() override
{ AssertNoURLRequests(); }
65 URLRequestContextStorage storage_
;
70 FetchResult(Error net_error
, const std::vector
<uint8_t>& response_body
)
71 : net_error_(net_error
), response_body_(response_body
) {}
73 void VerifySuccess(const std::string
& expected_body
) {
74 EXPECT_EQ(OK
, net_error_
);
75 EXPECT_EQ(expected_body
,
76 std::string(response_body_
.begin(), response_body_
.end()));
79 void VerifyFailure(Error expected_error
) {
80 EXPECT_EQ(expected_error
, net_error_
);
81 EXPECT_EQ(0u, response_body_
.size());
85 const Error net_error_
;
86 const std::vector
<uint8_t> response_body_
;
89 // Helper to synchronously wait for the fetch completion. This is similar to
90 // net's TestCompletionCallback, but built around FetchCallback.
91 class TestFetchCallback
{
94 : callback_(base::Bind(&TestFetchCallback::OnCallback
,
95 base::Unretained(this))) {}
97 const CertNetFetcher::FetchCallback
& callback() const { return callback_
; }
99 scoped_ptr
<FetchResult
> WaitForResult() {
100 DCHECK(quit_closure_
.is_null());
101 while (!HasResult()) {
102 base::RunLoop run_loop
;
103 quit_closure_
= run_loop
.QuitClosure();
105 quit_closure_
.Reset();
107 return result_
.Pass();
110 bool HasResult() const { return result_
.get(); }
112 // Sets an extra action (in addition to recording the result) that is run when
113 // the FetchCallback is invoked.
114 void set_extra_closure(const base::Closure
& closure
) {
115 extra_closure_
= closure
;
119 void OnCallback(Error net_error
, const std::vector
<uint8_t>& response_body
) {
120 DCHECK(!HasResult());
121 result_
.reset(new FetchResult(net_error
, response_body
));
123 if (!extra_closure_
.is_null())
124 extra_closure_
.Run();
126 if (!quit_closure_
.is_null())
130 CertNetFetcher::FetchCallback callback_
;
131 scoped_ptr
<FetchResult
> result_
;
132 base::Closure quit_closure_
;
133 base::Closure extra_closure_
;
138 class CertNetFetcherImplTest
: public PlatformTest
{
140 CertNetFetcherImplTest()
141 : test_server_(SpawnedTestServer::TYPE_HTTP
,
142 SpawnedTestServer::kLocalhost
,
143 base::FilePath(kDocRoot
)) {
144 context_
.set_network_delegate(&network_delegate_
);
148 SpawnedTestServer test_server_
;
149 TestNetworkDelegate network_delegate_
;
150 RequestContext context_
;
153 // Helper to start an AIA fetch using default parameters.
154 WARN_UNUSED_RESULT scoped_ptr
<CertNetFetcher::Request
> StartRequest(
155 CertNetFetcher
* fetcher
,
157 const TestFetchCallback
& callback
) {
158 return fetcher
->FetchCaIssuers(url
, CertNetFetcher::DEFAULT
,
159 CertNetFetcher::DEFAULT
, callback
.callback());
162 // Fetch a few unique URLs using GET in parallel. Each URL has a different body
164 TEST_F(CertNetFetcherImplTest
, ParallelFetchNoDuplicates
) {
165 ASSERT_TRUE(test_server_
.Start());
167 CertNetFetcherImpl
fetcher(&context_
);
168 TestFetchCallback callback1
;
169 TestFetchCallback callback2
;
170 TestFetchCallback callback3
;
172 // Request a URL with Content-Type "application/pkix-cert"
173 GURL url1
= test_server_
.GetURL("files/cert.crt");
174 scoped_ptr
<CertNetFetcher::Request
> request1
=
175 StartRequest(&fetcher
, url1
, callback1
);
177 // Request a URL with Content-Type "application/pkix-crl"
178 GURL url2
= test_server_
.GetURL("files/root.crl");
179 scoped_ptr
<CertNetFetcher::Request
> request2
=
180 StartRequest(&fetcher
, url2
, callback2
);
182 // Request a URL with Content-Type "application/pkcs7-mime"
183 GURL url3
= test_server_
.GetURL("files/certs.p7c");
184 scoped_ptr
<CertNetFetcher::Request
> request3
=
185 StartRequest(&fetcher
, url3
, callback3
);
187 // Wait for all of the requests to complete.
188 scoped_ptr
<FetchResult
> result1
= callback1
.WaitForResult();
189 scoped_ptr
<FetchResult
> result2
= callback2
.WaitForResult();
190 scoped_ptr
<FetchResult
> result3
= callback3
.WaitForResult();
192 // Verify the fetch results.
193 result1
->VerifySuccess("-cert.crt-\n");
194 result2
->VerifySuccess("-root.crl-\n");
195 result3
->VerifySuccess("-certs.p7c-\n");
197 EXPECT_EQ(3, network_delegate_
.created_requests());
200 // Fetch a caIssuers URL which has an unexpected extension and Content-Type.
201 // The extension is .txt and the Content-Type is text/plain. Despite being
202 // unusual this succeeds as the extension and Content-Type are not required to
204 TEST_F(CertNetFetcherImplTest
, ContentTypeDoesntMatter
) {
205 ASSERT_TRUE(test_server_
.Start());
207 CertNetFetcherImpl
fetcher(&context_
);
209 TestFetchCallback callback
;
210 GURL url
= test_server_
.GetURL("files/foo.txt");
211 scoped_ptr
<CertNetFetcher::Request
> request
=
212 StartRequest(&fetcher
, url
, callback
);
213 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
214 result
->VerifySuccess("-foo.txt-\n");
217 // Fetch a URLs whose HTTP response code is not 200. These are considered
219 TEST_F(CertNetFetcherImplTest
, HttpStatusCode
) {
220 ASSERT_TRUE(test_server_
.Start());
222 CertNetFetcherImpl
fetcher(&context_
);
224 // Response was HTTP status 404.
226 TestFetchCallback callback
;
227 GURL url
= test_server_
.GetURL("files/404.html");
228 scoped_ptr
<CertNetFetcher::Request
> request
=
229 StartRequest(&fetcher
, url
, callback
);
230 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
231 result
->VerifyFailure(ERR_FAILED
);
234 // Response was HTTP status 500.
236 TestFetchCallback callback
;
237 GURL url
= test_server_
.GetURL("files/500.html");
238 scoped_ptr
<CertNetFetcher::Request
> request
=
239 StartRequest(&fetcher
, url
, callback
);
240 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
241 result
->VerifyFailure(ERR_FAILED
);
245 // Fetching a URL with a Content-Disposition header should have no effect.
246 TEST_F(CertNetFetcherImplTest
, ContentDisposition
) {
247 ASSERT_TRUE(test_server_
.Start());
249 CertNetFetcherImpl
fetcher(&context_
);
251 TestFetchCallback callback
;
252 GURL url
= test_server_
.GetURL("files/downloadable.js");
253 scoped_ptr
<CertNetFetcher::Request
> request
=
254 StartRequest(&fetcher
, url
, callback
);
255 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
256 result
->VerifySuccess("-downloadable.js-\n");
259 // Verifies that a cachable request will be served from the HTTP cache the
260 // second time it is requested.
261 TEST_F(CertNetFetcherImplTest
, Cache
) {
262 ASSERT_TRUE(test_server_
.Start());
264 CertNetFetcherImpl
fetcher(&context_
);
266 // Fetch a URL whose HTTP headers make it cacheable for 1 hour.
267 GURL
url(test_server_
.GetURL("files/cacheable_1hr.crt"));
269 TestFetchCallback callback
;
271 scoped_ptr
<CertNetFetcher::Request
> request
=
272 StartRequest(&fetcher
, url
, callback
);
273 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
274 result
->VerifySuccess("-cacheable_1hr.crt-\n");
277 EXPECT_EQ(1, network_delegate_
.created_requests());
279 // Kill the HTTP server.
280 ASSERT_TRUE(test_server_
.Stop());
282 // Fetch again -- will fail unless served from cache.
284 TestFetchCallback callback
;
285 scoped_ptr
<CertNetFetcher::Request
> request
=
286 StartRequest(&fetcher
, url
, callback
);
287 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
288 result
->VerifySuccess("-cacheable_1hr.crt-\n");
291 EXPECT_EQ(2, network_delegate_
.created_requests());
294 // Verify that the maximum response body constraints are enforced by fetching a
295 // resource that is larger than the limit.
296 TEST_F(CertNetFetcherImplTest
, TooLarge
) {
297 ASSERT_TRUE(test_server_
.Start());
299 CertNetFetcherImpl
fetcher(&context_
);
301 // This file has a response body 12 bytes long. So setting the maximum to 11
302 // bytes will cause it to fail.
303 GURL
url(test_server_
.GetURL("files/certs.p7c"));
304 TestFetchCallback callback
;
305 scoped_ptr
<CertNetFetcher::Request
> request
= fetcher
.FetchCaIssuers(
306 url
, CertNetFetcher::DEFAULT
, 11, callback
.callback());
308 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
309 result
->VerifyFailure(ERR_FILE_TOO_BIG
);
312 // Set the timeout to 10 milliseconds, and try fetching a URL that takes 5
313 // seconds to complete. It should fail due to a timeout.
314 TEST_F(CertNetFetcherImplTest
, Hang
) {
315 ASSERT_TRUE(test_server_
.Start());
317 CertNetFetcherImpl
fetcher(&context_
);
319 GURL
url(test_server_
.GetURL("slow/certs.p7c?5"));
320 TestFetchCallback callback
;
321 scoped_ptr
<CertNetFetcher::Request
> request
= fetcher
.FetchCaIssuers(
322 url
, 10, CertNetFetcher::DEFAULT
, callback
.callback());
323 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
324 result
->VerifyFailure(ERR_TIMED_OUT
);
327 // Verify that if a response is gzip-encoded it gets inflated before being
328 // returned to the caller.
329 TEST_F(CertNetFetcherImplTest
, Gzip
) {
330 ASSERT_TRUE(test_server_
.Start());
332 CertNetFetcherImpl
fetcher(&context_
);
334 GURL
url(test_server_
.GetURL("files/gzipped_crl"));
335 TestFetchCallback callback
;
336 scoped_ptr
<CertNetFetcher::Request
> request
=
337 StartRequest(&fetcher
, url
, callback
);
338 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
339 result
->VerifySuccess("-gzipped_crl-\n");
342 // Try fetching an unsupported URL scheme (https).
343 TEST_F(CertNetFetcherImplTest
, HttpsNotAllowed
) {
344 ASSERT_TRUE(test_server_
.Start());
346 CertNetFetcherImpl
fetcher(&context_
);
348 GURL
url("https://foopy/foo.crt");
349 TestFetchCallback callback
;
350 scoped_ptr
<CertNetFetcher::Request
> request
=
351 StartRequest(&fetcher
, url
, callback
);
352 // Should NOT complete synchronously despite being a test that could be done
354 EXPECT_FALSE(callback
.HasResult());
355 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
356 result
->VerifyFailure(ERR_DISALLOWED_URL_SCHEME
);
358 // No request was created because the URL scheme was unsupported.
359 EXPECT_EQ(0, network_delegate_
.created_requests());
362 // Try fetching a URL which redirects to https.
363 TEST_F(CertNetFetcherImplTest
, RedirectToHttpsNotAllowed
) {
364 ASSERT_TRUE(test_server_
.Start());
366 CertNetFetcherImpl
fetcher(&context_
);
368 GURL
url(test_server_
.GetURL("files/redirect_https"));
369 TestFetchCallback callback
;
371 scoped_ptr
<CertNetFetcher::Request
> request
=
372 StartRequest(&fetcher
, url
, callback
);
373 scoped_ptr
<FetchResult
> result
= callback
.WaitForResult();
374 result
->VerifyFailure(ERR_DISALLOWED_URL_SCHEME
);
376 EXPECT_EQ(1, network_delegate_
.created_requests());
379 // Try fetching an unsupported URL scheme (https) and then immediately
380 // cancelling. This is a bit special because this codepath needs to post a task.
381 TEST_F(CertNetFetcherImplTest
, CancelHttpsNotAllowed
) {
382 ASSERT_TRUE(test_server_
.Start());
384 CertNetFetcherImpl
fetcher(&context_
);
386 GURL
url("https://foopy/foo.crt");
387 TestFetchCallback callback
;
388 scoped_ptr
<CertNetFetcher::Request
> request
=
389 StartRequest(&fetcher
, url
, callback
);
391 // Cancel the request.
394 // Spin the message loop to increase chance of catching a bug.
395 base::RunLoop().RunUntilIdle();
397 // Should NOT complete synchronously despite being a test that could be done
399 EXPECT_FALSE(callback
.HasResult());
401 EXPECT_EQ(0, network_delegate_
.created_requests());
404 // Start a few requests, and cancel one of them before running the message loop
406 TEST_F(CertNetFetcherImplTest
, CancelBeforeRunningMessageLoop
) {
407 ASSERT_TRUE(test_server_
.Start());
409 CertNetFetcherImpl
fetcher(&context_
);
410 TestFetchCallback callback1
;
411 TestFetchCallback callback2
;
412 TestFetchCallback callback3
;
414 GURL url1
= test_server_
.GetURL("files/cert.crt");
415 scoped_ptr
<CertNetFetcher::Request
> request1
=
416 StartRequest(&fetcher
, url1
, callback1
);
418 GURL url2
= test_server_
.GetURL("files/root.crl");
419 scoped_ptr
<CertNetFetcher::Request
> request2
=
420 StartRequest(&fetcher
, url2
, callback2
);
422 GURL url3
= test_server_
.GetURL("files/certs.p7c");
424 scoped_ptr
<CertNetFetcher::Request
> request3
=
425 StartRequest(&fetcher
, url3
, callback3
);
427 EXPECT_EQ(3, network_delegate_
.created_requests());
428 EXPECT_FALSE(callback1
.HasResult());
429 EXPECT_FALSE(callback2
.HasResult());
430 EXPECT_FALSE(callback3
.HasResult());
432 // Cancel the second request.
435 // Wait for the non-cancelled requests to complete.
436 scoped_ptr
<FetchResult
> result1
= callback1
.WaitForResult();
437 scoped_ptr
<FetchResult
> result3
= callback3
.WaitForResult();
439 // Verify the fetch results.
440 result1
->VerifySuccess("-cert.crt-\n");
441 result3
->VerifySuccess("-certs.p7c-\n");
443 EXPECT_FALSE(callback2
.HasResult());
446 // Start several requests, and cancel one of them after the first has completed.
447 // NOTE: The python test server is single threaded and can only service one
448 // request at a time. After a socket is opened by the server it waits for it to
449 // be completed, and any subsequent request will hang until the first socket is
451 // Cancelling the first request can therefore be problematic, since if
452 // cancellation is done after the socket is opened but before reading/writing,
453 // then the socket is re-cycled and things will be stalled until the cleanup
454 // timer (10 seconds) closes it.
455 // To work around this, the last request is cancelled, and hope that the
456 // requests are given opened sockets in a FIFO order.
457 // TODO(eroman): Make this more robust.
458 TEST_F(CertNetFetcherImplTest
, CancelAfterRunningMessageLoop
) {
459 ASSERT_TRUE(test_server_
.Start());
461 CertNetFetcherImpl
fetcher(&context_
);
462 TestFetchCallback callback1
;
463 TestFetchCallback callback2
;
464 TestFetchCallback callback3
;
466 GURL url1
= test_server_
.GetURL("files/cert.crt");
468 scoped_ptr
<CertNetFetcher::Request
> request1
=
469 StartRequest(&fetcher
, url1
, callback1
);
471 GURL url2
= test_server_
.GetURL("files/certs.p7c");
472 scoped_ptr
<CertNetFetcher::Request
> request2
=
473 StartRequest(&fetcher
, url2
, callback2
);
475 GURL
url3("ftp://www.not.supported.com/foo");
476 scoped_ptr
<CertNetFetcher::Request
> request3
=
477 StartRequest(&fetcher
, url3
, callback3
);
479 EXPECT_FALSE(callback1
.HasResult());
480 EXPECT_FALSE(callback2
.HasResult());
481 EXPECT_FALSE(callback3
.HasResult());
483 // Wait for the ftp request to complete (it should complete right away since
484 // it doesn't even try to connect to the server).
485 scoped_ptr
<FetchResult
> result3
= callback3
.WaitForResult();
486 result3
->VerifyFailure(ERR_DISALLOWED_URL_SCHEME
);
488 // Cancel the second outstanding request.
491 // Wait for the first request to complete.
492 scoped_ptr
<FetchResult
> result2
= callback1
.WaitForResult();
494 // Verify the fetch results.
495 result2
->VerifySuccess("-cert.crt-\n");
498 // Delete a CertNetFetcherImpl with outstanding requests on it.
499 TEST_F(CertNetFetcherImplTest
, DeleteCancels
) {
500 ASSERT_TRUE(test_server_
.Start());
502 scoped_ptr
<CertNetFetcherImpl
> fetcher(new CertNetFetcherImpl(&context_
));
504 GURL
url(test_server_
.GetURL("slow/certs.p7c?20"));
505 TestFetchCallback callback
;
506 scoped_ptr
<CertNetFetcher::Request
> request
=
507 StartRequest(fetcher
.get(), url
, callback
);
509 // Destroy the fetcher before the outstanding request.
513 // Fetch the same URLs in parallel and verify that only 1 request is made per
515 TEST_F(CertNetFetcherImplTest
, ParallelFetchDuplicates
) {
516 ASSERT_TRUE(test_server_
.Start());
518 CertNetFetcherImpl
fetcher(&context_
);
520 GURL url1
= test_server_
.GetURL("files/cert.crt");
521 GURL url2
= test_server_
.GetURL("files/root.crl");
523 // Issue 3 requests for url1, and 3 requests for url2
524 TestFetchCallback callback1
;
525 scoped_ptr
<CertNetFetcher::Request
> request1
=
526 StartRequest(&fetcher
, url1
, callback1
);
528 TestFetchCallback callback2
;
529 scoped_ptr
<CertNetFetcher::Request
> request2
=
530 StartRequest(&fetcher
, url2
, callback2
);
532 TestFetchCallback callback3
;
533 scoped_ptr
<CertNetFetcher::Request
> request3
=
534 StartRequest(&fetcher
, url1
, callback3
);
536 TestFetchCallback callback4
;
537 scoped_ptr
<CertNetFetcher::Request
> request4
=
538 StartRequest(&fetcher
, url2
, callback4
);
540 TestFetchCallback callback5
;
541 scoped_ptr
<CertNetFetcher::Request
> request5
=
542 StartRequest(&fetcher
, url2
, callback5
);
544 TestFetchCallback callback6
;
545 scoped_ptr
<CertNetFetcher::Request
> request6
=
546 StartRequest(&fetcher
, url1
, callback6
);
548 // Cancel all but one of the requests for url1.
552 // Wait for the remaining requests to finish.
553 scoped_ptr
<FetchResult
> result2
= callback2
.WaitForResult();
554 scoped_ptr
<FetchResult
> result4
= callback4
.WaitForResult();
555 scoped_ptr
<FetchResult
> result5
= callback5
.WaitForResult();
556 scoped_ptr
<FetchResult
> result6
= callback6
.WaitForResult();
558 // Verify that none of the cancelled requests for url1 completed (since they
560 EXPECT_FALSE(callback1
.HasResult());
561 EXPECT_FALSE(callback3
.HasResult());
563 // Verify the fetch results.
564 result2
->VerifySuccess("-root.crl-\n");
565 result4
->VerifySuccess("-root.crl-\n");
566 result5
->VerifySuccess("-root.crl-\n");
567 result6
->VerifySuccess("-cert.crt-\n");
569 // Verify that only 2 URLRequests were started even though 6 requests were
571 EXPECT_EQ(2, network_delegate_
.created_requests());
574 // Cancel a request and then start another one for the same URL.
575 TEST_F(CertNetFetcherImplTest
, CancelThenStart
) {
576 ASSERT_TRUE(test_server_
.Start());
578 CertNetFetcherImpl
fetcher(&context_
);
579 TestFetchCallback callback1
;
580 TestFetchCallback callback2
;
581 TestFetchCallback callback3
;
583 GURL url
= test_server_
.GetURL("files/cert.crt");
585 scoped_ptr
<CertNetFetcher::Request
> request1
=
586 StartRequest(&fetcher
, url
, callback1
);
589 scoped_ptr
<CertNetFetcher::Request
> request2
=
590 StartRequest(&fetcher
, url
, callback2
);
592 scoped_ptr
<CertNetFetcher::Request
> request3
=
593 StartRequest(&fetcher
, url
, callback3
);
596 // All but |request2| were canceled.
597 scoped_ptr
<FetchResult
> result
= callback2
.WaitForResult();
599 result
->VerifySuccess("-cert.crt-\n");
601 EXPECT_FALSE(callback1
.HasResult());
602 EXPECT_FALSE(callback3
.HasResult());
604 // One URLRequest that was cancelled, then another right afterwards.
605 EXPECT_EQ(2, network_delegate_
.created_requests());
608 // Start duplicate requests and then cancel all of them.
609 TEST_F(CertNetFetcherImplTest
, CancelAll
) {
610 ASSERT_TRUE(test_server_
.Start());
612 CertNetFetcherImpl
fetcher(&context_
);
613 TestFetchCallback callback
[3];
614 scoped_ptr
<CertNetFetcher::Request
> request
[3];
616 GURL url
= test_server_
.GetURL("files/cert.crt");
618 for (size_t i
= 0; i
< arraysize(callback
); ++i
) {
619 request
[i
] = StartRequest(&fetcher
, url
, callback
[i
]);
622 // Cancel all the requests.
623 for (size_t i
= 0; i
< arraysize(request
); ++i
)
626 EXPECT_EQ(1, network_delegate_
.created_requests());
628 for (size_t i
= 0; i
< arraysize(request
); ++i
)
629 EXPECT_FALSE(callback
[i
].HasResult());
632 void DeleteCertNetFetcher(CertNetFetcher
* fetcher
) {
636 // Delete the CertNetFetcherImpl within a request callback.
637 TEST_F(CertNetFetcherImplTest
, DeleteWithinCallback
) {
638 ASSERT_TRUE(test_server_
.Start());
640 // Deleted by callback2.
641 CertNetFetcher
* fetcher
= new CertNetFetcherImpl(&context_
);
643 GURL url
= test_server_
.GetURL("files/cert.crt");
645 TestFetchCallback callback
[4];
646 scoped_ptr
<CertNetFetcher::Request
> reqs
[4];
647 callback
[1].set_extra_closure(base::Bind(DeleteCertNetFetcher
, fetcher
));
649 for (size_t i
= 0; i
< arraysize(callback
); ++i
)
650 reqs
[i
] = StartRequest(fetcher
, url
, callback
[i
]);
652 EXPECT_EQ(1, network_delegate_
.created_requests());
654 callback
[1].WaitForResult();
656 // Assume requests for the same URL are executed in FIFO order.
657 EXPECT_TRUE(callback
[0].HasResult());
658 EXPECT_FALSE(callback
[2].HasResult());
659 EXPECT_FALSE(callback
[3].HasResult());
662 void FetchRequest(CertNetFetcher
* fetcher
,
664 TestFetchCallback
* callback
,
665 scoped_ptr
<CertNetFetcher::Request
>* request
) {
666 *request
= StartRequest(fetcher
, url
, *callback
);
669 // Make a request during callback for the same URL.
670 TEST_F(CertNetFetcherImplTest
, FetchWithinCallback
) {
671 ASSERT_TRUE(test_server_
.Start());
673 CertNetFetcherImpl
fetcher(&context_
);
675 GURL url
= test_server_
.GetURL("files/cert.crt");
677 TestFetchCallback callback
[5];
678 scoped_ptr
<CertNetFetcher::Request
> req
[5];
679 callback
[1].set_extra_closure(
680 base::Bind(FetchRequest
, &fetcher
, url
, &callback
[4], &req
[4]));
682 for (size_t i
= 0; i
< arraysize(callback
) - 1; ++i
)
683 req
[i
] = StartRequest(&fetcher
, url
, callback
[i
]);
685 EXPECT_EQ(1, network_delegate_
.created_requests());
687 for (size_t i
= 0; i
< arraysize(callback
); ++i
) {
688 scoped_ptr
<FetchResult
> result
= callback
[i
].WaitForResult();
689 result
->VerifySuccess("-cert.crt-\n");
692 // The fetch started within a callback should have started a new request
693 // rather than attaching to the current job.
694 EXPECT_EQ(2, network_delegate_
.created_requests());
697 void CancelRequest(scoped_ptr
<CertNetFetcher::Request
>* request
) {
701 // Cancel a request while executing a callback for the same job.
702 TEST_F(CertNetFetcherImplTest
, CancelWithinCallback
) {
703 ASSERT_TRUE(test_server_
.Start());
705 CertNetFetcherImpl
fetcher(&context_
);
707 GURL url
= test_server_
.GetURL("files/cert.crt");
709 TestFetchCallback callback
[4];
710 scoped_ptr
<CertNetFetcher::Request
> request
[4];
712 for (size_t i
= 0; i
< arraysize(callback
); ++i
)
713 request
[i
] = StartRequest(&fetcher
, url
, callback
[i
]);
715 // Cancel request[2] when the callback for request[1] runs.
716 callback
[1].set_extra_closure(base::Bind(CancelRequest
, &request
[2]));
718 EXPECT_EQ(1, network_delegate_
.created_requests());
720 for (size_t i
= 0; i
< arraysize(request
); ++i
) {
724 scoped_ptr
<FetchResult
> result
= callback
[i
].WaitForResult();
725 result
->VerifySuccess("-cert.crt-\n");
728 // request[2] was cancelled.
729 EXPECT_FALSE(callback
[2].HasResult());
732 // Cancel the final request while executing a callback for the same job. Ensure
733 // that the job is not deleted twice.
734 TEST_F(CertNetFetcherImplTest
, CancelLastRequestWithinCallback
) {
735 ASSERT_TRUE(test_server_
.Start());
737 CertNetFetcherImpl
fetcher(&context_
);
739 GURL url
= test_server_
.GetURL("files/cert.crt");
741 TestFetchCallback callback1
;
742 scoped_ptr
<CertNetFetcher::Request
> request1
=
743 StartRequest(&fetcher
, url
, callback1
);
745 TestFetchCallback callback2
;
746 scoped_ptr
<CertNetFetcher::Request
> request2
=
747 StartRequest(&fetcher
, url
, callback1
);
749 // Cancel request2 when the callback for request1 runs.
750 callback1
.set_extra_closure(base::Bind(CancelRequest
, &request2
));
752 EXPECT_EQ(1, network_delegate_
.created_requests());
754 scoped_ptr
<FetchResult
> result
= callback1
.WaitForResult();
755 result
->VerifySuccess("-cert.crt-\n");
757 // request2 was cancelled.
758 EXPECT_FALSE(callback2
.HasResult());