1 // Copyright (c) 2013 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 "content/browser/loader/resource_loader.h"
7 #include "base/files/file.h"
8 #include "base/files/file_util.h"
9 #include "base/location.h"
10 #include "base/macros.h"
11 #include "base/run_loop.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "content/browser/browser_thread_impl.h"
15 #include "content/browser/loader/redirect_to_file_resource_handler.h"
16 #include "content/browser/loader/resource_loader_delegate.h"
17 #include "content/common/ssl_status_serialization.h"
18 #include "content/public/browser/cert_store.h"
19 #include "content/public/browser/client_certificate_delegate.h"
20 #include "content/public/browser/resource_request_info.h"
21 #include "content/public/common/content_paths.h"
22 #include "content/public/common/resource_response.h"
23 #include "content/public/test/mock_resource_context.h"
24 #include "content/public/test/test_browser_context.h"
25 #include "content/public/test/test_browser_thread_bundle.h"
26 #include "content/public/test/test_renderer_host.h"
27 #include "content/test/test_content_browser_client.h"
28 #include "content/test/test_web_contents.h"
29 #include "ipc/ipc_message.h"
30 #include "net/base/chunked_upload_data_stream.h"
31 #include "net/base/io_buffer.h"
32 #include "net/base/mock_file_stream.h"
33 #include "net/base/net_errors.h"
34 #include "net/base/request_priority.h"
35 #include "net/base/test_data_directory.h"
36 #include "net/base/upload_bytes_element_reader.h"
37 #include "net/cert/x509_certificate.h"
38 #include "net/ssl/client_cert_store.h"
39 #include "net/ssl/ssl_cert_request_info.h"
40 #include "net/test/cert_test_util.h"
41 #include "net/test/embedded_test_server/embedded_test_server.h"
42 #include "net/url_request/url_request.h"
43 #include "net/url_request/url_request_filter.h"
44 #include "net/url_request/url_request_interceptor.h"
45 #include "net/url_request/url_request_job_factory.h"
46 #include "net/url_request/url_request_job_factory_impl.h"
47 #include "net/url_request/url_request_test_job.h"
48 #include "net/url_request/url_request_test_util.h"
49 #include "storage/browser/blob/shareable_file_reference.h"
50 #include "testing/gtest/include/gtest/gtest.h"
52 using storage::ShareableFileReference
;
57 // Stub client certificate store that returns a preset list of certificates for
58 // each request and records the arguments of the most recent request for later
60 class ClientCertStoreStub
: public net::ClientCertStore
{
62 // Creates a new ClientCertStoreStub that returns |response| on query. It
63 // saves the number of requests and most recently certificate authorities list
64 // in |requested_authorities| and |request_count|, respectively. The caller is
65 // responsible for ensuring those pointers outlive the ClientCertStoreStub.
67 // TODO(ppi): Make the stub independent from the internal representation of
68 // SSLCertRequestInfo. For now it seems that we can neither save the
69 // scoped_refptr<> (since it is never passed to us) nor copy the entire
70 // CertificateRequestInfo (since there is no copy constructor).
71 ClientCertStoreStub(const net::CertificateList
& response
,
73 std::vector
<std::string
>* requested_authorities
)
74 : response_(response
),
75 requested_authorities_(requested_authorities
),
76 request_count_(request_count
) {
77 requested_authorities_
->clear();
81 ~ClientCertStoreStub() override
{}
83 // net::ClientCertStore:
84 void GetClientCerts(const net::SSLCertRequestInfo
& cert_request_info
,
85 net::CertificateList
* selected_certs
,
86 const base::Closure
& callback
) override
{
87 *requested_authorities_
= cert_request_info
.cert_authorities
;
90 *selected_certs
= response_
;
95 const net::CertificateList response_
;
96 std::vector
<std::string
>* requested_authorities_
;
100 // Client certificate store which destroys its resource loader before the
101 // asynchronous GetClientCerts callback is called.
102 class LoaderDestroyingCertStore
: public net::ClientCertStore
{
104 // Creates a client certificate store which, when looked up, posts a task to
105 // reset |loader| and then call the callback. The caller is responsible for
106 // ensuring the pointers remain valid until the process is complete.
107 explicit LoaderDestroyingCertStore(scoped_ptr
<ResourceLoader
>* loader
)
110 // net::ClientCertStore:
111 void GetClientCerts(const net::SSLCertRequestInfo
& cert_request_info
,
112 net::CertificateList
* selected_certs
,
113 const base::Closure
& callback
) override
{
114 // Don't destroy |loader_| while it's on the stack.
115 base::ThreadTaskRunnerHandle::Get()->PostTask(
116 FROM_HERE
, base::Bind(&LoaderDestroyingCertStore::DoCallback
,
117 base::Unretained(loader_
), callback
));
121 static void DoCallback(scoped_ptr
<ResourceLoader
>* loader
,
122 const base::Closure
& callback
) {
127 scoped_ptr
<ResourceLoader
>* loader_
;
130 // A mock URLRequestJob which simulates an SSL client auth request.
131 class MockClientCertURLRequestJob
: public net::URLRequestTestJob
{
133 MockClientCertURLRequestJob(net::URLRequest
* request
,
134 net::NetworkDelegate
* network_delegate
)
135 : net::URLRequestTestJob(request
, network_delegate
) {}
137 static std::vector
<std::string
> test_authorities() {
138 return std::vector
<std::string
>(1, "dummy");
141 // net::URLRequestTestJob:
142 void Start() override
{
143 scoped_refptr
<net::SSLCertRequestInfo
> cert_request_info(
144 new net::SSLCertRequestInfo
);
145 cert_request_info
->cert_authorities
= test_authorities();
146 base::ThreadTaskRunnerHandle::Get()->PostTask(
148 base::Bind(&MockClientCertURLRequestJob::NotifyCertificateRequested
,
149 this, cert_request_info
));
152 void ContinueWithCertificate(net::X509Certificate
* cert
) override
{
153 net::URLRequestTestJob::Start();
157 ~MockClientCertURLRequestJob() override
{}
159 DISALLOW_COPY_AND_ASSIGN(MockClientCertURLRequestJob
);
162 class MockClientCertJobProtocolHandler
163 : public net::URLRequestJobFactory::ProtocolHandler
{
165 // URLRequestJobFactory::ProtocolHandler implementation:
166 net::URLRequestJob
* MaybeCreateJob(
167 net::URLRequest
* request
,
168 net::NetworkDelegate
* network_delegate
) const override
{
169 return new MockClientCertURLRequestJob(request
, network_delegate
);
173 // Set up dummy values to use in test HTTPS requests.
175 scoped_refptr
<net::X509Certificate
> GetTestCert() {
176 return net::ImportCertFromFile(net::GetTestCertsDirectory(),
177 "test_mail_google_com.pem");
180 const net::CertStatus kTestCertError
= net::CERT_STATUS_DATE_INVALID
;
181 const int kTestSecurityBits
= 256;
182 // SSL3 TLS_DHE_RSA_WITH_AES_256_CBC_SHA
183 const int kTestConnectionStatus
= 0x300039;
185 // A mock URLRequestJob which simulates an HTTPS request.
186 class MockHTTPSURLRequestJob
: public net::URLRequestTestJob
{
188 MockHTTPSURLRequestJob(net::URLRequest
* request
,
189 net::NetworkDelegate
* network_delegate
,
190 const std::string
& response_headers
,
191 const std::string
& response_data
,
193 : net::URLRequestTestJob(request
,
199 // net::URLRequestTestJob:
200 void GetResponseInfo(net::HttpResponseInfo
* info
) override
{
201 // Get the original response info, but override the SSL info.
202 net::URLRequestJob::GetResponseInfo(info
);
203 info
->ssl_info
.cert
= GetTestCert();
204 info
->ssl_info
.cert_status
= kTestCertError
;
205 info
->ssl_info
.security_bits
= kTestSecurityBits
;
206 info
->ssl_info
.connection_status
= kTestConnectionStatus
;
210 ~MockHTTPSURLRequestJob() override
{}
212 DISALLOW_COPY_AND_ASSIGN(MockHTTPSURLRequestJob
);
215 const char kRedirectHeaders
[] =
216 "HTTP/1.1 302 Found\0"
217 "Location: https://example.test\0"
220 class MockHTTPSJobURLRequestInterceptor
: public net::URLRequestInterceptor
{
222 MockHTTPSJobURLRequestInterceptor(bool redirect
) : redirect_(redirect
) {}
223 ~MockHTTPSJobURLRequestInterceptor() override
{}
225 // net::URLRequestInterceptor:
226 net::URLRequestJob
* MaybeInterceptRequest(
227 net::URLRequest
* request
,
228 net::NetworkDelegate
* network_delegate
) const override
{
229 std::string headers
=
230 redirect_
? std::string(kRedirectHeaders
, arraysize(kRedirectHeaders
))
231 : net::URLRequestTestJob::test_headers();
232 return new MockHTTPSURLRequestJob(request
, network_delegate
, headers
,
233 "dummy response", true);
240 // Arbitrary read buffer size.
241 const int kReadBufSize
= 1024;
243 // Dummy implementation of ResourceHandler, instance of which is needed to
244 // initialize ResourceLoader.
245 class ResourceHandlerStub
: public ResourceHandler
{
247 explicit ResourceHandlerStub(net::URLRequest
* request
)
248 : ResourceHandler(request
),
249 read_buffer_(new net::IOBuffer(kReadBufSize
)),
250 defer_request_on_will_start_(false),
252 cancel_on_read_completed_(false),
254 received_on_will_read_(false),
255 received_eof_(false),
256 received_response_completed_(false),
257 received_request_redirected_(false),
258 total_bytes_downloaded_(0),
259 upload_position_(0) {}
261 // If true, defers the resource load in OnWillStart.
262 void set_defer_request_on_will_start(bool defer_request_on_will_start
) {
263 defer_request_on_will_start_
= defer_request_on_will_start
;
266 // If true, expect OnWillRead / OnReadCompleted pairs for handling
267 // data. Otherwise, expect OnDataDownloaded.
268 void set_expect_reads(bool expect_reads
) { expect_reads_
= expect_reads
; }
270 // If true, cancel the request in OnReadCompleted by returning false.
271 void set_cancel_on_read_completed(bool cancel_on_read_completed
) {
272 cancel_on_read_completed_
= cancel_on_read_completed
;
275 // If true, cancel the request in OnReadCompleted by returning false.
276 void set_defer_eof(bool defer_eof
) { defer_eof_
= defer_eof
; }
278 const GURL
& start_url() const { return start_url_
; }
279 ResourceResponse
* response() const { return response_
.get(); }
280 ResourceResponse
* redirect_response() const {
281 return redirect_response_
.get();
283 bool received_response_completed() const {
284 return received_response_completed_
;
286 bool received_request_redirected() const {
287 return received_request_redirected_
;
289 const net::URLRequestStatus
& status() const { return status_
; }
290 int total_bytes_downloaded() const { return total_bytes_downloaded_
; }
293 controller()->Resume();
296 // Waits until OnUploadProgress is called and returns the upload position.
297 uint64
WaitForUploadProgress() {
298 wait_for_progress_loop_
.reset(new base::RunLoop());
299 wait_for_progress_loop_
->Run();
300 wait_for_progress_loop_
.reset();
301 return upload_position_
;
304 // ResourceHandler implementation:
305 bool OnUploadProgress(uint64 position
, uint64 size
) override
{
306 EXPECT_LE(position
, size
);
307 EXPECT_GT(position
, upload_position_
);
308 upload_position_
= position
;
309 if (wait_for_progress_loop_
)
310 wait_for_progress_loop_
->Quit();
314 bool OnRequestRedirected(const net::RedirectInfo
& redirect_info
,
315 ResourceResponse
* response
,
316 bool* defer
) override
{
317 redirect_response_
= response
;
318 received_request_redirected_
= true;
322 bool OnResponseStarted(ResourceResponse
* response
, bool* defer
) override
{
323 EXPECT_FALSE(response_
.get());
324 response_
= response
;
328 bool OnWillStart(const GURL
& url
, bool* defer
) override
{
329 EXPECT_TRUE(start_url_
.is_empty());
331 *defer
= defer_request_on_will_start_
;
335 bool OnBeforeNetworkStart(const GURL
& url
, bool* defer
) override
{
339 bool OnWillRead(scoped_refptr
<net::IOBuffer
>* buf
,
341 int min_size
) override
{
342 EXPECT_TRUE(expect_reads_
);
343 EXPECT_FALSE(received_on_will_read_
);
344 EXPECT_FALSE(received_eof_
);
345 EXPECT_FALSE(received_response_completed_
);
348 *buf_size
= kReadBufSize
;
349 received_on_will_read_
= true;
353 bool OnReadCompleted(int bytes_read
, bool* defer
) override
{
354 EXPECT_TRUE(received_on_will_read_
);
355 EXPECT_TRUE(expect_reads_
);
356 EXPECT_FALSE(received_response_completed_
);
358 if (bytes_read
== 0) {
359 received_eof_
= true;
366 // Need another OnWillRead() call before seeing an OnReadCompleted().
367 received_on_will_read_
= false;
369 return !cancel_on_read_completed_
;
372 void OnResponseCompleted(const net::URLRequestStatus
& status
,
373 const std::string
& security_info
,
374 bool* defer
) override
{
375 EXPECT_FALSE(received_response_completed_
);
376 if (status
.is_success() && expect_reads_
)
377 EXPECT_TRUE(received_eof_
);
379 received_response_completed_
= true;
383 void OnDataDownloaded(int bytes_downloaded
) override
{
384 EXPECT_FALSE(expect_reads_
);
385 total_bytes_downloaded_
+= bytes_downloaded
;
389 scoped_refptr
<net::IOBuffer
> read_buffer_
;
391 bool defer_request_on_will_start_
;
393 bool cancel_on_read_completed_
;
397 scoped_refptr
<ResourceResponse
> response_
;
398 scoped_refptr
<ResourceResponse
> redirect_response_
;
399 bool received_on_will_read_
;
401 bool received_response_completed_
;
402 bool received_request_redirected_
;
403 net::URLRequestStatus status_
;
404 int total_bytes_downloaded_
;
405 scoped_ptr
<base::RunLoop
> wait_for_progress_loop_
;
406 uint64 upload_position_
;
409 // Test browser client that captures calls to SelectClientCertificates and
410 // records the arguments of the most recent call for later inspection.
411 class SelectCertificateBrowserClient
: public TestContentBrowserClient
{
413 SelectCertificateBrowserClient() : call_count_(0) {}
415 void SelectClientCertificate(
416 WebContents
* web_contents
,
417 net::SSLCertRequestInfo
* cert_request_info
,
418 scoped_ptr
<ClientCertificateDelegate
> delegate
) override
{
420 passed_certs_
= cert_request_info
->client_certs
;
421 delegate_
= delegate
.Pass();
424 int call_count() { return call_count_
; }
425 net::CertificateList
passed_certs() { return passed_certs_
; }
427 void ContinueWithCertificate(net::X509Certificate
* cert
) {
428 delegate_
->ContinueWithCertificate(cert
);
432 void CancelCertificateSelection() { delegate_
.reset(); }
435 net::CertificateList passed_certs_
;
437 scoped_ptr
<ClientCertificateDelegate
> delegate_
;
440 class ResourceContextStub
: public MockResourceContext
{
442 explicit ResourceContextStub(net::URLRequestContext
* test_request_context
)
443 : MockResourceContext(test_request_context
) {}
445 scoped_ptr
<net::ClientCertStore
> CreateClientCertStore() override
{
446 return dummy_cert_store_
.Pass();
449 void SetClientCertStore(scoped_ptr
<net::ClientCertStore
> store
) {
450 dummy_cert_store_
= store
.Pass();
454 scoped_ptr
<net::ClientCertStore
> dummy_cert_store_
;
457 // Wraps a ChunkedUploadDataStream to behave as non-chunked to enable upload
458 // progress reporting.
459 class NonChunkedUploadDataStream
: public net::UploadDataStream
{
461 explicit NonChunkedUploadDataStream(uint64 size
)
462 : net::UploadDataStream(false, 0), stream_(0), size_(size
) {}
464 void AppendData(const char* data
) {
465 stream_
.AppendData(data
, strlen(data
), false);
469 int InitInternal() override
{
471 stream_
.Init(base::Bind(&NonChunkedUploadDataStream::OnInitCompleted
,
472 base::Unretained(this)));
476 int ReadInternal(net::IOBuffer
* buf
, int buf_len
) override
{
477 return stream_
.Read(buf
, buf_len
,
478 base::Bind(&NonChunkedUploadDataStream::OnReadCompleted
,
479 base::Unretained(this)));
482 void ResetInternal() override
{ stream_
.Reset(); }
484 net::ChunkedUploadDataStream stream_
;
487 DISALLOW_COPY_AND_ASSIGN(NonChunkedUploadDataStream
);
490 // Fails to create a temporary file with the given error.
491 void CreateTemporaryError(
492 base::File::Error error
,
493 const CreateTemporaryFileStreamCallback
& callback
) {
494 base::ThreadTaskRunnerHandle::Get()->PostTask(
496 base::Bind(callback
, error
, base::Passed(scoped_ptr
<net::FileStream
>()),
497 scoped_refptr
<ShareableFileReference
>()));
502 class ResourceLoaderTest
: public testing::Test
,
503 public ResourceLoaderDelegate
{
506 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP
),
507 resource_context_(&test_url_request_context_
),
508 raw_ptr_resource_handler_(NULL
),
509 raw_ptr_to_request_(NULL
) {
510 test_url_request_context_
.set_job_factory(&job_factory_
);
513 GURL
test_url() const { return net::URLRequestTestJob::test_url_1(); }
515 std::string
test_data() const {
516 return net::URLRequestTestJob::test_data_1();
519 // Waits until upload progress reaches |target_position|
520 void WaitForUploadProgress(uint64 target_position
) {
522 uint64 position
= raw_ptr_resource_handler_
->WaitForUploadProgress();
523 EXPECT_LE(position
, target_position
);
524 loader_
->OnUploadProgressACK();
525 if (position
== target_position
)
530 virtual net::URLRequestJobFactory::ProtocolHandler
* CreateProtocolHandler() {
531 return net::URLRequestTestJob::CreateProtocolHandler();
534 virtual scoped_ptr
<ResourceHandler
> WrapResourceHandler(
535 scoped_ptr
<ResourceHandlerStub
> leaf_handler
,
536 net::URLRequest
* request
) {
537 return leaf_handler
.Pass();
540 // Replaces loader_ with a new one for |request|.
541 void SetUpResourceLoader(scoped_ptr
<net::URLRequest
> request
) {
542 raw_ptr_to_request_
= request
.get();
544 RenderFrameHost
* rfh
= web_contents_
->GetMainFrame();
545 ResourceRequestInfo::AllocateForTesting(
546 request
.get(), RESOURCE_TYPE_MAIN_FRAME
, &resource_context_
,
547 rfh
->GetProcess()->GetID(), rfh
->GetRenderViewHost()->GetRoutingID(),
548 rfh
->GetRoutingID(), true /* is_main_frame */,
549 false /* parent_is_main_frame */, true /* allow_download */,
550 false /* is_async */);
551 scoped_ptr
<ResourceHandlerStub
> resource_handler(
552 new ResourceHandlerStub(request
.get()));
553 raw_ptr_resource_handler_
= resource_handler
.get();
554 loader_
.reset(new ResourceLoader(
556 WrapResourceHandler(resource_handler
.Pass(), raw_ptr_to_request_
),
560 void SetUp() override
{
561 job_factory_
.SetProtocolHandler("test", CreateProtocolHandler());
563 browser_context_
.reset(new TestBrowserContext());
564 scoped_refptr
<SiteInstance
> site_instance
=
565 SiteInstance::Create(browser_context_
.get());
567 TestWebContents::Create(browser_context_
.get(), site_instance
.get()));
569 scoped_ptr
<net::URLRequest
> request(
570 resource_context_
.GetRequestContext()->CreateRequest(
572 net::DEFAULT_PRIORITY
,
573 nullptr /* delegate */));
574 SetUpResourceLoader(request
.Pass());
577 void TearDown() override
{
578 // Destroy the WebContents and pump the event loop before destroying
579 // |rvh_test_enabler_| and |thread_bundle_|. This lets asynchronous cleanup
581 web_contents_
.reset();
582 base::RunLoop().RunUntilIdle();
585 // ResourceLoaderDelegate:
586 ResourceDispatcherHostLoginDelegate
* CreateLoginDelegate(
587 ResourceLoader
* loader
,
588 net::AuthChallengeInfo
* auth_info
) override
{
591 bool HandleExternalProtocol(ResourceLoader
* loader
,
592 const GURL
& url
) override
{
595 void DidStartRequest(ResourceLoader
* loader
) override
{}
596 void DidReceiveRedirect(ResourceLoader
* loader
,
597 const GURL
& new_url
) override
{}
598 void DidReceiveResponse(ResourceLoader
* loader
) override
{}
599 void DidFinishLoading(ResourceLoader
* loader
) override
{}
601 TestBrowserThreadBundle thread_bundle_
;
602 RenderViewHostTestEnabler rvh_test_enabler_
;
604 net::URLRequestJobFactoryImpl job_factory_
;
605 net::TestURLRequestContext test_url_request_context_
;
606 ResourceContextStub resource_context_
;
607 scoped_ptr
<TestBrowserContext
> browser_context_
;
608 scoped_ptr
<TestWebContents
> web_contents_
;
610 // The ResourceLoader owns the URLRequest and the ResourceHandler.
611 ResourceHandlerStub
* raw_ptr_resource_handler_
;
612 net::URLRequest
* raw_ptr_to_request_
;
613 scoped_ptr
<ResourceLoader
> loader_
;
616 class ClientCertResourceLoaderTest
: public ResourceLoaderTest
{
618 net::URLRequestJobFactory::ProtocolHandler
* CreateProtocolHandler() override
{
619 return new MockClientCertJobProtocolHandler
;
623 // A ResourceLoaderTest that intercepts https://example.test and
624 // https://example-redirect.test URLs and sets SSL info on the
625 // responses. The latter serves a Location: header in the response.
626 class HTTPSSecurityInfoResourceLoaderTest
: public ResourceLoaderTest
{
628 HTTPSSecurityInfoResourceLoaderTest()
629 : ResourceLoaderTest(),
630 test_https_url_("https://example.test"),
631 test_https_redirect_url_("https://example-redirect.test") {}
633 ~HTTPSSecurityInfoResourceLoaderTest() override
{}
635 const GURL
& test_https_url() const { return test_https_url_
; }
636 const GURL
& test_https_redirect_url() const {
637 return test_https_redirect_url_
;
641 void SetUp() override
{
642 ResourceLoaderTest::SetUp();
643 net::URLRequestFilter::GetInstance()->ClearHandlers();
644 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
645 "https", "example.test",
646 scoped_ptr
<net::URLRequestInterceptor
>(
647 new MockHTTPSJobURLRequestInterceptor(false /* redirect */)));
648 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
649 "https", "example-redirect.test",
650 scoped_ptr
<net::URLRequestInterceptor
>(
651 new MockHTTPSJobURLRequestInterceptor(true /* redirect */)));
655 const GURL test_https_url_
;
656 const GURL test_https_redirect_url_
;
659 // Tests that client certificates are requested with ClientCertStore lookup.
660 TEST_F(ClientCertResourceLoaderTest
, WithStoreLookup
) {
661 // Set up the test client cert store.
662 int store_request_count
;
663 std::vector
<std::string
> store_requested_authorities
;
664 net::CertificateList
dummy_certs(1, scoped_refptr
<net::X509Certificate
>(
665 new net::X509Certificate("test", "test", base::Time(), base::Time())));
666 scoped_ptr
<ClientCertStoreStub
> test_store(new ClientCertStoreStub(
667 dummy_certs
, &store_request_count
, &store_requested_authorities
));
668 resource_context_
.SetClientCertStore(test_store
.Pass());
670 // Plug in test content browser client.
671 SelectCertificateBrowserClient test_client
;
672 ContentBrowserClient
* old_client
= SetBrowserClientForTesting(&test_client
);
674 // Start the request and wait for it to pause.
675 loader_
->StartRequest();
676 base::RunLoop().RunUntilIdle();
678 EXPECT_FALSE(raw_ptr_resource_handler_
->received_response_completed());
680 // Check if the test store was queried against correct |cert_authorities|.
681 EXPECT_EQ(1, store_request_count
);
682 EXPECT_EQ(MockClientCertURLRequestJob::test_authorities(),
683 store_requested_authorities
);
685 // Check if the retrieved certificates were passed to the content browser
687 EXPECT_EQ(1, test_client
.call_count());
688 EXPECT_EQ(dummy_certs
, test_client
.passed_certs());
690 // Continue the request.
691 test_client
.ContinueWithCertificate(dummy_certs
[0].get());
692 base::RunLoop().RunUntilIdle();
693 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
694 EXPECT_EQ(net::OK
, raw_ptr_resource_handler_
->status().error());
696 // Restore the original content browser client.
697 SetBrowserClientForTesting(old_client
);
700 // Tests that client certificates are requested on a platform with NULL
702 TEST_F(ClientCertResourceLoaderTest
, WithNullStore
) {
703 // Plug in test content browser client.
704 SelectCertificateBrowserClient test_client
;
705 ContentBrowserClient
* old_client
= SetBrowserClientForTesting(&test_client
);
707 // Start the request and wait for it to pause.
708 loader_
->StartRequest();
709 base::RunLoop().RunUntilIdle();
711 // Check if the SelectClientCertificate was called on the content browser
713 EXPECT_EQ(1, test_client
.call_count());
714 EXPECT_EQ(net::CertificateList(), test_client
.passed_certs());
716 // Continue the request.
717 scoped_refptr
<net::X509Certificate
> cert(
718 new net::X509Certificate("test", "test", base::Time(), base::Time()));
719 test_client
.ContinueWithCertificate(cert
.get());
720 base::RunLoop().RunUntilIdle();
721 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
722 EXPECT_EQ(net::OK
, raw_ptr_resource_handler_
->status().error());
724 // Restore the original content browser client.
725 SetBrowserClientForTesting(old_client
);
728 // Tests that the ContentBrowserClient may cancel a certificate request.
729 TEST_F(ClientCertResourceLoaderTest
, CancelSelection
) {
730 // Plug in test content browser client.
731 SelectCertificateBrowserClient test_client
;
732 ContentBrowserClient
* old_client
= SetBrowserClientForTesting(&test_client
);
734 // Start the request and wait for it to pause.
735 loader_
->StartRequest();
736 base::RunLoop().RunUntilIdle();
738 // Check if the SelectClientCertificate was called on the content browser
740 EXPECT_EQ(1, test_client
.call_count());
741 EXPECT_EQ(net::CertificateList(), test_client
.passed_certs());
743 // Cancel the request.
744 test_client
.CancelCertificateSelection();
745 base::RunLoop().RunUntilIdle();
746 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
747 EXPECT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED
,
748 raw_ptr_resource_handler_
->status().error());
750 // Restore the original content browser client.
751 SetBrowserClientForTesting(old_client
);
754 // Verifies that requests without WebContents attached abort.
755 TEST_F(ClientCertResourceLoaderTest
, NoWebContents
) {
756 // Destroy the WebContents before starting the request.
757 web_contents_
.reset();
759 // Plug in test content browser client.
760 SelectCertificateBrowserClient test_client
;
761 ContentBrowserClient
* old_client
= SetBrowserClientForTesting(&test_client
);
763 // Start the request and wait for it to pause.
764 loader_
->StartRequest();
765 base::RunLoop().RunUntilIdle();
767 // Check that SelectClientCertificate wasn't called and the request aborted.
768 EXPECT_EQ(0, test_client
.call_count());
769 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
770 EXPECT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED
,
771 raw_ptr_resource_handler_
->status().error());
773 // Restore the original content browser client.
774 SetBrowserClientForTesting(old_client
);
777 // Verifies that ClientCertStore's callback doesn't crash if called after the
778 // loader is destroyed.
779 TEST_F(ClientCertResourceLoaderTest
, StoreAsyncCancel
) {
780 scoped_ptr
<LoaderDestroyingCertStore
> test_store(
781 new LoaderDestroyingCertStore(&loader_
));
782 resource_context_
.SetClientCertStore(test_store
.Pass());
784 loader_
->StartRequest();
785 base::RunLoop().RunUntilIdle();
786 EXPECT_FALSE(loader_
);
788 // Pump the event loop to ensure nothing asynchronous crashes either.
789 base::RunLoop().RunUntilIdle();
792 TEST_F(ResourceLoaderTest
, ResumeCancelledRequest
) {
793 raw_ptr_resource_handler_
->set_defer_request_on_will_start(true);
795 loader_
->StartRequest();
796 loader_
->CancelRequest(true);
797 static_cast<ResourceController
*>(loader_
.get())->Resume();
800 // Tests that no invariants are broken if a ResourceHandler cancels during
802 TEST_F(ResourceLoaderTest
, CancelOnReadCompleted
) {
803 raw_ptr_resource_handler_
->set_cancel_on_read_completed(true);
805 loader_
->StartRequest();
806 base::RunLoop().RunUntilIdle();
808 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
809 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
810 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
811 raw_ptr_resource_handler_
->status().status());
814 // Tests that no invariants are broken if a ResourceHandler defers EOF.
815 TEST_F(ResourceLoaderTest
, DeferEOF
) {
816 raw_ptr_resource_handler_
->set_defer_eof(true);
818 loader_
->StartRequest();
819 base::RunLoop().RunUntilIdle();
821 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
822 EXPECT_FALSE(raw_ptr_resource_handler_
->received_response_completed());
824 raw_ptr_resource_handler_
->Resume();
825 base::RunLoop().RunUntilIdle();
827 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
828 EXPECT_EQ(net::URLRequestStatus::SUCCESS
,
829 raw_ptr_resource_handler_
->status().status());
832 // Tests that progress is reported correctly while uploading.
833 // TODO(andresantoso): Add test for the redirect case.
834 TEST_F(ResourceLoaderTest
, UploadProgress
) {
835 // Set up a test server.
836 net::test_server::EmbeddedTestServer server
;
837 ASSERT_TRUE(server
.InitializeAndWaitUntilReady());
839 PathService::Get(content::DIR_TEST_DATA
, &path
);
840 server
.ServeFilesFromDirectory(path
);
842 scoped_ptr
<net::URLRequest
> request(
843 resource_context_
.GetRequestContext()->CreateRequest(
844 server
.GetURL("/title1.html"),
845 net::DEFAULT_PRIORITY
,
846 nullptr /* delegate */));
849 auto stream
= new NonChunkedUploadDataStream(10);
850 request
->set_upload(make_scoped_ptr(stream
));
852 SetUpResourceLoader(request
.Pass());
853 loader_
->StartRequest();
855 stream
->AppendData("xx");
856 WaitForUploadProgress(2);
858 stream
->AppendData("yyy");
859 WaitForUploadProgress(5);
861 stream
->AppendData("zzzzz");
862 WaitForUploadProgress(10);
865 class ResourceLoaderRedirectToFileTest
: public ResourceLoaderTest
{
867 ResourceLoaderRedirectToFileTest()
868 : file_stream_(NULL
),
869 redirect_to_file_resource_handler_(NULL
) {
872 base::FilePath
temp_path() const { return temp_path_
; }
873 ShareableFileReference
* deletable_file() const {
874 return deletable_file_
.get();
876 net::testing::MockFileStream
* file_stream() const { return file_stream_
; }
877 RedirectToFileResourceHandler
* redirect_to_file_resource_handler() const {
878 return redirect_to_file_resource_handler_
;
881 void ReleaseLoader() {
883 deletable_file_
= NULL
;
887 scoped_ptr
<ResourceHandler
> WrapResourceHandler(
888 scoped_ptr
<ResourceHandlerStub
> leaf_handler
,
889 net::URLRequest
* request
) override
{
890 leaf_handler
->set_expect_reads(false);
892 // Make a temporary file.
893 CHECK(base::CreateTemporaryFile(&temp_path_
));
894 int flags
= base::File::FLAG_WRITE
| base::File::FLAG_TEMPORARY
|
895 base::File::FLAG_CREATE_ALWAYS
| base::File::FLAG_ASYNC
;
896 base::File
file(temp_path_
, flags
);
897 CHECK(file
.IsValid());
899 // Create mock file streams and a ShareableFileReference.
900 scoped_ptr
<net::testing::MockFileStream
> file_stream(
901 new net::testing::MockFileStream(file
.Pass(),
902 base::ThreadTaskRunnerHandle::Get()));
903 file_stream_
= file_stream
.get();
904 deletable_file_
= ShareableFileReference::GetOrCreate(
906 ShareableFileReference::DELETE_ON_FINAL_RELEASE
,
907 BrowserThread::GetMessageLoopProxyForThread(
908 BrowserThread::FILE).get());
910 // Inject them into the handler.
911 scoped_ptr
<RedirectToFileResourceHandler
> handler(
912 new RedirectToFileResourceHandler(leaf_handler
.Pass(), request
));
913 redirect_to_file_resource_handler_
= handler
.get();
914 handler
->SetCreateTemporaryFileStreamFunctionForTesting(
915 base::Bind(&ResourceLoaderRedirectToFileTest::PostCallback
,
916 base::Unretained(this),
917 base::Passed(&file_stream
)));
918 return handler
.Pass();
923 scoped_ptr
<net::FileStream
> file_stream
,
924 const CreateTemporaryFileStreamCallback
& callback
) {
925 base::ThreadTaskRunnerHandle::Get()->PostTask(
926 FROM_HERE
, base::Bind(callback
, base::File::FILE_OK
,
927 base::Passed(&file_stream
), deletable_file_
));
930 base::FilePath temp_path_
;
931 scoped_refptr
<ShareableFileReference
> deletable_file_
;
932 // These are owned by the ResourceLoader.
933 net::testing::MockFileStream
* file_stream_
;
934 RedirectToFileResourceHandler
* redirect_to_file_resource_handler_
;
937 // Tests that a RedirectToFileResourceHandler works and forwards everything
939 TEST_F(ResourceLoaderRedirectToFileTest
, Basic
) {
940 // Run it to completion.
941 loader_
->StartRequest();
942 base::RunLoop().RunUntilIdle();
944 // Check that the handler forwarded all information to the downstream handler.
945 EXPECT_EQ(temp_path(),
946 raw_ptr_resource_handler_
->response()->head
.download_file_path
);
947 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
948 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
949 EXPECT_EQ(net::URLRequestStatus::SUCCESS
,
950 raw_ptr_resource_handler_
->status().status());
951 EXPECT_EQ(test_data().size(), static_cast<size_t>(
952 raw_ptr_resource_handler_
->total_bytes_downloaded()));
954 // Check that the data was written to the file.
955 std::string contents
;
956 ASSERT_TRUE(base::ReadFileToString(temp_path(), &contents
));
957 EXPECT_EQ(test_data(), contents
);
959 // Release the loader and the saved reference to file. The file should be gone
962 base::RunLoop().RunUntilIdle();
963 EXPECT_FALSE(base::PathExists(temp_path()));
966 // Tests that RedirectToFileResourceHandler handles errors in creating the
968 TEST_F(ResourceLoaderRedirectToFileTest
, CreateTemporaryError
) {
969 // Swap out the create temporary function.
970 redirect_to_file_resource_handler()->
971 SetCreateTemporaryFileStreamFunctionForTesting(
972 base::Bind(&CreateTemporaryError
, base::File::FILE_ERROR_FAILED
));
974 // Run it to completion.
975 loader_
->StartRequest();
976 base::RunLoop().RunUntilIdle();
978 // To downstream, the request was canceled.
979 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
980 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
981 raw_ptr_resource_handler_
->status().status());
982 EXPECT_EQ(0, raw_ptr_resource_handler_
->total_bytes_downloaded());
985 // Tests that RedirectToFileResourceHandler handles synchronous write errors.
986 TEST_F(ResourceLoaderRedirectToFileTest
, WriteError
) {
987 file_stream()->set_forced_error(net::ERR_FAILED
);
989 // Run it to completion.
990 loader_
->StartRequest();
991 base::RunLoop().RunUntilIdle();
993 // To downstream, the request was canceled sometime after it started, but
994 // before any data was written.
995 EXPECT_EQ(temp_path(),
996 raw_ptr_resource_handler_
->response()->head
.download_file_path
);
997 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
998 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
999 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
1000 raw_ptr_resource_handler_
->status().status());
1001 EXPECT_EQ(0, raw_ptr_resource_handler_
->total_bytes_downloaded());
1003 // Release the loader. The file should be gone now.
1005 base::RunLoop().RunUntilIdle();
1006 EXPECT_FALSE(base::PathExists(temp_path()));
1009 // Tests that RedirectToFileResourceHandler handles asynchronous write errors.
1010 TEST_F(ResourceLoaderRedirectToFileTest
, WriteErrorAsync
) {
1011 file_stream()->set_forced_error_async(net::ERR_FAILED
);
1013 // Run it to completion.
1014 loader_
->StartRequest();
1015 base::RunLoop().RunUntilIdle();
1017 // To downstream, the request was canceled sometime after it started, but
1018 // before any data was written.
1019 EXPECT_EQ(temp_path(),
1020 raw_ptr_resource_handler_
->response()->head
.download_file_path
);
1021 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
1022 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
1023 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
1024 raw_ptr_resource_handler_
->status().status());
1025 EXPECT_EQ(0, raw_ptr_resource_handler_
->total_bytes_downloaded());
1027 // Release the loader. The file should be gone now.
1029 base::RunLoop().RunUntilIdle();
1030 EXPECT_FALSE(base::PathExists(temp_path()));
1033 // Tests that RedirectToFileHandler defers completion if there are outstanding
1034 // writes and accounts for errors which occur in that time.
1035 TEST_F(ResourceLoaderRedirectToFileTest
, DeferCompletion
) {
1036 // Program the MockFileStream to error asynchronously, but throttle the
1038 file_stream()->set_forced_error_async(net::ERR_FAILED
);
1039 file_stream()->ThrottleCallbacks();
1041 // Run it as far as it will go.
1042 loader_
->StartRequest();
1043 base::RunLoop().RunUntilIdle();
1045 // At this point, the request should have completed.
1046 EXPECT_EQ(net::URLRequestStatus::SUCCESS
,
1047 raw_ptr_to_request_
->status().status());
1049 // However, the resource loader stack is stuck somewhere after receiving the
1051 EXPECT_EQ(temp_path(),
1052 raw_ptr_resource_handler_
->response()->head
.download_file_path
);
1053 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
1054 EXPECT_FALSE(raw_ptr_resource_handler_
->received_response_completed());
1055 EXPECT_EQ(0, raw_ptr_resource_handler_
->total_bytes_downloaded());
1057 // Now, release the floodgates.
1058 file_stream()->ReleaseCallbacks();
1059 base::RunLoop().RunUntilIdle();
1061 // Although the URLRequest was successful, the leaf handler sees a failure
1062 // because the write never completed.
1063 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
1064 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
1065 raw_ptr_resource_handler_
->status().status());
1067 // Release the loader. The file should be gone now.
1069 base::RunLoop().RunUntilIdle();
1070 EXPECT_FALSE(base::PathExists(temp_path()));
1073 // Tests that a RedirectToFileResourceHandler behaves properly when the
1074 // downstream handler defers OnWillStart.
1075 TEST_F(ResourceLoaderRedirectToFileTest
, DownstreamDeferStart
) {
1076 // Defer OnWillStart.
1077 raw_ptr_resource_handler_
->set_defer_request_on_will_start(true);
1079 // Run as far as we'll go.
1080 loader_
->StartRequest();
1081 base::RunLoop().RunUntilIdle();
1083 // The request should have stopped at OnWillStart.
1084 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
1085 EXPECT_FALSE(raw_ptr_resource_handler_
->response());
1086 EXPECT_FALSE(raw_ptr_resource_handler_
->received_response_completed());
1087 EXPECT_EQ(0, raw_ptr_resource_handler_
->total_bytes_downloaded());
1089 // Now resume the request. Now we complete.
1090 raw_ptr_resource_handler_
->Resume();
1091 base::RunLoop().RunUntilIdle();
1093 // Check that the handler forwarded all information to the downstream handler.
1094 EXPECT_EQ(temp_path(),
1095 raw_ptr_resource_handler_
->response()->head
.download_file_path
);
1096 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
1097 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
1098 EXPECT_EQ(net::URLRequestStatus::SUCCESS
,
1099 raw_ptr_resource_handler_
->status().status());
1100 EXPECT_EQ(test_data().size(), static_cast<size_t>(
1101 raw_ptr_resource_handler_
->total_bytes_downloaded()));
1103 // Check that the data was written to the file.
1104 std::string contents
;
1105 ASSERT_TRUE(base::ReadFileToString(temp_path(), &contents
));
1106 EXPECT_EQ(test_data(), contents
);
1108 // Release the loader. The file should be gone now.
1110 base::RunLoop().RunUntilIdle();
1111 EXPECT_FALSE(base::PathExists(temp_path()));
1114 // Test that an HTTPS resource has the expected security info attached
1116 TEST_F(HTTPSSecurityInfoResourceLoaderTest
, SecurityInfoOnHTTPSResource
) {
1117 // Start the request and wait for it to finish.
1118 scoped_ptr
<net::URLRequest
> request(
1119 resource_context_
.GetRequestContext()->CreateRequest(
1120 test_https_url(), net::DEFAULT_PRIORITY
, nullptr /* delegate */));
1121 SetUpResourceLoader(request
.Pass());
1123 // Send the request and wait until it completes.
1124 loader_
->StartRequest();
1125 base::RunLoop().RunUntilIdle();
1126 ASSERT_EQ(net::URLRequestStatus::SUCCESS
,
1127 raw_ptr_to_request_
->status().status());
1128 ASSERT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
1130 ResourceResponse
* response
= raw_ptr_resource_handler_
->response();
1131 ASSERT_TRUE(response
);
1133 // Deserialize the security info from the response and check that it
1135 SSLStatus deserialized
;
1137 DeserializeSecurityInfo(response
->head
.security_info
, &deserialized
));
1139 // Expect a BROKEN security style because the cert status has errors.
1140 EXPECT_EQ(content::SECURITY_STYLE_AUTHENTICATION_BROKEN
,
1141 deserialized
.security_style
);
1142 scoped_refptr
<net::X509Certificate
> cert
;
1144 CertStore::GetInstance()->RetrieveCert(deserialized
.cert_id
, &cert
));
1145 EXPECT_TRUE(cert
->Equals(GetTestCert().get()));
1147 EXPECT_EQ(kTestCertError
, deserialized
.cert_status
);
1148 EXPECT_EQ(kTestConnectionStatus
, deserialized
.connection_status
);
1149 EXPECT_EQ(kTestSecurityBits
, deserialized
.security_bits
);
1152 // Test that an HTTPS redirect response has the expected security info
1154 TEST_F(HTTPSSecurityInfoResourceLoaderTest
,
1155 SecurityInfoOnHTTPSRedirectResource
) {
1156 // Start the request and wait for it to finish.
1157 scoped_ptr
<net::URLRequest
> request(
1158 resource_context_
.GetRequestContext()->CreateRequest(
1159 test_https_redirect_url(), net::DEFAULT_PRIORITY
,
1160 nullptr /* delegate */));
1161 SetUpResourceLoader(request
.Pass());
1163 // Send the request and wait until it completes.
1164 loader_
->StartRequest();
1165 base::RunLoop().RunUntilIdle();
1166 ASSERT_EQ(net::URLRequestStatus::SUCCESS
,
1167 raw_ptr_to_request_
->status().status());
1168 ASSERT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
1169 ASSERT_TRUE(raw_ptr_resource_handler_
->received_request_redirected());
1171 ResourceResponse
* redirect_response
=
1172 raw_ptr_resource_handler_
->redirect_response();
1173 ASSERT_TRUE(redirect_response
);
1175 // Deserialize the security info from the redirect response and check
1176 // that it is as expected.
1177 SSLStatus deserialized
;
1178 ASSERT_TRUE(DeserializeSecurityInfo(redirect_response
->head
.security_info
,
1181 // Expect a BROKEN security style because the cert status has errors.
1182 EXPECT_EQ(content::SECURITY_STYLE_AUTHENTICATION_BROKEN
,
1183 deserialized
.security_style
);
1184 scoped_refptr
<net::X509Certificate
> cert
;
1186 CertStore::GetInstance()->RetrieveCert(deserialized
.cert_id
, &cert
));
1187 EXPECT_TRUE(cert
->Equals(GetTestCert().get()));
1189 EXPECT_EQ(kTestCertError
, deserialized
.cert_status
);
1190 EXPECT_EQ(kTestConnectionStatus
, deserialized
.connection_status
);
1191 EXPECT_EQ(kTestSecurityBits
, deserialized
.security_bits
);
1194 } // namespace content