Roll src/third_party/WebKit 57aef96:a1089e6 (svn 201978:201979)
[chromium-blink-merge.git] / net / cert_net / cert_net_fetcher_impl_unittest.cc
blobe60241840496bf3630473a683c2324dac3b4930a
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"
7 #include <string>
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;
24 namespace net {
26 namespace {
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 {
33 public:
34 RequestContext() : storage_(this) {
35 ProxyConfig no_proxy;
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(); }
61 private:
62 URLRequestContextStorage storage_;
65 class FetchResult {
66 public:
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());
81 private:
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 {
89 public:
90 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();
101 run_loop.Run();
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;
115 private:
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())
124 quit_closure_.Run();
127 CertNetFetcher::FetchCallback callback_;
128 scoped_ptr<FetchResult> result_;
129 base::Closure quit_closure_;
130 base::Closure extra_closure_;
133 } // namespace
135 class CertNetFetcherImplTest : public PlatformTest {
136 public:
137 CertNetFetcherImplTest()
138 : test_server_(SpawnedTestServer::TYPE_HTTP,
139 SpawnedTestServer::kLocalhost,
140 base::FilePath(kDocRoot)) {
141 context_.set_network_delegate(&network_delegate_);
144 protected:
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,
153 const GURL& url,
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
160 // and Content-Type.
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
200 // be meaningful.
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
215 // failures.
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
350 // immediately.
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.
389 request.reset();
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
395 // immediately.
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
402 // again.
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.
430 request2.reset();
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
447 // closed.
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.
486 request2.reset();
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.
507 fetcher.reset();
510 // Fetch the same URLs in parallel and verify that only 1 request is made per
511 // URL.
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.
546 request1.reset();
547 request3.reset();
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
556 // were cancelled).
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
567 // issued.
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);
584 request1.reset();
586 scoped_ptr<CertNetFetcher::Request> request2 =
587 StartRequest(&fetcher, url, callback2);
589 scoped_ptr<CertNetFetcher::Request> request3 =
590 StartRequest(&fetcher, url, callback3);
591 request3.reset();
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)
621 request[i].reset();
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) {
630 delete 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,
660 const GURL& url,
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) {
695 request->reset();
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) {
718 if (i == 2)
719 continue;
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());
729 // Cancel the final request while executing a callback for the same job. Ensure
730 // that the job is not deleted twice.
731 TEST_F(CertNetFetcherImplTest, CancelLastRequestWithinCallback) {
732 ASSERT_TRUE(test_server_.Start());
734 CertNetFetcherImpl fetcher(&context_);
736 GURL url = test_server_.GetURL("files/cert.crt");
738 TestFetchCallback callback1;
739 scoped_ptr<CertNetFetcher::Request> request1 =
740 StartRequest(&fetcher, url, callback1);
742 TestFetchCallback callback2;
743 scoped_ptr<CertNetFetcher::Request> request2 =
744 StartRequest(&fetcher, url, callback1);
746 // Cancel request2 when the callback for request1 runs.
747 callback1.set_extra_closure(base::Bind(CancelRequest, &request2));
749 EXPECT_EQ(1, network_delegate_.created_requests());
751 scoped_ptr<FetchResult> result = callback1.WaitForResult();
752 result->VerifySuccess("-cert.crt-\n");
754 // request2 was cancelled.
755 EXPECT_FALSE(callback2.HasResult());
758 } // namespace net