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/public/browser/client_certificate_delegate.h"
18 #include "content/public/browser/resource_request_info.h"
19 #include "content/public/common/content_paths.h"
20 #include "content/public/common/resource_response.h"
21 #include "content/public/test/mock_resource_context.h"
22 #include "content/public/test/test_browser_context.h"
23 #include "content/public/test/test_browser_thread_bundle.h"
24 #include "content/public/test/test_renderer_host.h"
25 #include "content/test/test_content_browser_client.h"
26 #include "content/test/test_web_contents.h"
27 #include "ipc/ipc_message.h"
28 #include "net/base/chunked_upload_data_stream.h"
29 #include "net/base/io_buffer.h"
30 #include "net/base/mock_file_stream.h"
31 #include "net/base/net_errors.h"
32 #include "net/base/request_priority.h"
33 #include "net/base/upload_bytes_element_reader.h"
34 #include "net/cert/x509_certificate.h"
35 #include "net/ssl/client_cert_store.h"
36 #include "net/ssl/ssl_cert_request_info.h"
37 #include "net/test/embedded_test_server/embedded_test_server.h"
38 #include "net/url_request/url_request.h"
39 #include "net/url_request/url_request_job_factory.h"
40 #include "net/url_request/url_request_job_factory_impl.h"
41 #include "net/url_request/url_request_test_job.h"
42 #include "net/url_request/url_request_test_util.h"
43 #include "storage/browser/blob/shareable_file_reference.h"
44 #include "testing/gtest/include/gtest/gtest.h"
46 using storage::ShareableFileReference
;
51 // Stub client certificate store that returns a preset list of certificates for
52 // each request and records the arguments of the most recent request for later
54 class ClientCertStoreStub
: public net::ClientCertStore
{
56 // Creates a new ClientCertStoreStub that returns |response| on query. It
57 // saves the number of requests and most recently certificate authorities list
58 // in |requested_authorities| and |request_count|, respectively. The caller is
59 // responsible for ensuring those pointers outlive the ClientCertStoreStub.
61 // TODO(ppi): Make the stub independent from the internal representation of
62 // SSLCertRequestInfo. For now it seems that we can neither save the
63 // scoped_refptr<> (since it is never passed to us) nor copy the entire
64 // CertificateRequestInfo (since there is no copy constructor).
65 ClientCertStoreStub(const net::CertificateList
& response
,
67 std::vector
<std::string
>* requested_authorities
)
68 : response_(response
),
69 requested_authorities_(requested_authorities
),
70 request_count_(request_count
) {
71 requested_authorities_
->clear();
75 ~ClientCertStoreStub() override
{}
77 // net::ClientCertStore:
78 void GetClientCerts(const net::SSLCertRequestInfo
& cert_request_info
,
79 net::CertificateList
* selected_certs
,
80 const base::Closure
& callback
) override
{
81 *requested_authorities_
= cert_request_info
.cert_authorities
;
84 *selected_certs
= response_
;
89 const net::CertificateList response_
;
90 std::vector
<std::string
>* requested_authorities_
;
94 // Client certificate store which destroys its resource loader before the
95 // asynchronous GetClientCerts callback is called.
96 class LoaderDestroyingCertStore
: public net::ClientCertStore
{
98 // Creates a client certificate store which, when looked up, posts a task to
99 // reset |loader| and then call the callback. The caller is responsible for
100 // ensuring the pointers remain valid until the process is complete.
101 explicit LoaderDestroyingCertStore(scoped_ptr
<ResourceLoader
>* loader
)
104 // net::ClientCertStore:
105 void GetClientCerts(const net::SSLCertRequestInfo
& cert_request_info
,
106 net::CertificateList
* selected_certs
,
107 const base::Closure
& callback
) override
{
108 // Don't destroy |loader_| while it's on the stack.
109 base::ThreadTaskRunnerHandle::Get()->PostTask(
110 FROM_HERE
, base::Bind(&LoaderDestroyingCertStore::DoCallback
,
111 base::Unretained(loader_
), callback
));
115 static void DoCallback(scoped_ptr
<ResourceLoader
>* loader
,
116 const base::Closure
& callback
) {
121 scoped_ptr
<ResourceLoader
>* loader_
;
124 // A mock URLRequestJob which simulates an SSL client auth request.
125 class MockClientCertURLRequestJob
: public net::URLRequestTestJob
{
127 MockClientCertURLRequestJob(net::URLRequest
* request
,
128 net::NetworkDelegate
* network_delegate
)
129 : net::URLRequestTestJob(request
, network_delegate
) {}
131 static std::vector
<std::string
> test_authorities() {
132 return std::vector
<std::string
>(1, "dummy");
135 // net::URLRequestTestJob:
136 void Start() override
{
137 scoped_refptr
<net::SSLCertRequestInfo
> cert_request_info(
138 new net::SSLCertRequestInfo
);
139 cert_request_info
->cert_authorities
= test_authorities();
140 base::ThreadTaskRunnerHandle::Get()->PostTask(
142 base::Bind(&MockClientCertURLRequestJob::NotifyCertificateRequested
,
143 this, cert_request_info
));
146 void ContinueWithCertificate(net::X509Certificate
* cert
) override
{
147 net::URLRequestTestJob::Start();
151 ~MockClientCertURLRequestJob() override
{}
153 DISALLOW_COPY_AND_ASSIGN(MockClientCertURLRequestJob
);
156 class MockClientCertJobProtocolHandler
157 : public net::URLRequestJobFactory::ProtocolHandler
{
159 // URLRequestJobFactory::ProtocolHandler implementation:
160 net::URLRequestJob
* MaybeCreateJob(
161 net::URLRequest
* request
,
162 net::NetworkDelegate
* network_delegate
) const override
{
163 return new MockClientCertURLRequestJob(request
, network_delegate
);
167 // Arbitrary read buffer size.
168 const int kReadBufSize
= 1024;
170 // Dummy implementation of ResourceHandler, instance of which is needed to
171 // initialize ResourceLoader.
172 class ResourceHandlerStub
: public ResourceHandler
{
174 explicit ResourceHandlerStub(net::URLRequest
* request
)
175 : ResourceHandler(request
),
176 read_buffer_(new net::IOBuffer(kReadBufSize
)),
177 defer_request_on_will_start_(false),
179 cancel_on_read_completed_(false),
181 received_on_will_read_(false),
182 received_eof_(false),
183 received_response_completed_(false),
184 total_bytes_downloaded_(0),
185 upload_position_(0) {
188 // If true, defers the resource load in OnWillStart.
189 void set_defer_request_on_will_start(bool defer_request_on_will_start
) {
190 defer_request_on_will_start_
= defer_request_on_will_start
;
193 // If true, expect OnWillRead / OnReadCompleted pairs for handling
194 // data. Otherwise, expect OnDataDownloaded.
195 void set_expect_reads(bool expect_reads
) { expect_reads_
= expect_reads
; }
197 // If true, cancel the request in OnReadCompleted by returning false.
198 void set_cancel_on_read_completed(bool cancel_on_read_completed
) {
199 cancel_on_read_completed_
= cancel_on_read_completed
;
202 // If true, cancel the request in OnReadCompleted by returning false.
203 void set_defer_eof(bool defer_eof
) { defer_eof_
= defer_eof
; }
205 const GURL
& start_url() const { return start_url_
; }
206 ResourceResponse
* response() const { return response_
.get(); }
207 bool received_response_completed() const {
208 return received_response_completed_
;
210 const net::URLRequestStatus
& status() const { return status_
; }
211 int total_bytes_downloaded() const { return total_bytes_downloaded_
; }
214 controller()->Resume();
217 // Waits until OnUploadProgress is called and returns the upload position.
218 uint64
WaitForUploadProgress() {
219 wait_for_progress_loop_
.reset(new base::RunLoop());
220 wait_for_progress_loop_
->Run();
221 wait_for_progress_loop_
.reset();
222 return upload_position_
;
225 // ResourceHandler implementation:
226 bool OnUploadProgress(uint64 position
, uint64 size
) override
{
227 EXPECT_LE(position
, size
);
228 EXPECT_GT(position
, upload_position_
);
229 upload_position_
= position
;
230 if (wait_for_progress_loop_
)
231 wait_for_progress_loop_
->Quit();
235 bool OnRequestRedirected(const net::RedirectInfo
& redirect_info
,
236 ResourceResponse
* response
,
237 bool* defer
) override
{
242 bool OnResponseStarted(ResourceResponse
* response
, bool* defer
) override
{
243 EXPECT_FALSE(response_
.get());
244 response_
= response
;
248 bool OnWillStart(const GURL
& url
, bool* defer
) override
{
249 EXPECT_TRUE(start_url_
.is_empty());
251 *defer
= defer_request_on_will_start_
;
255 bool OnBeforeNetworkStart(const GURL
& url
, bool* defer
) override
{
259 bool OnWillRead(scoped_refptr
<net::IOBuffer
>* buf
,
261 int min_size
) override
{
262 EXPECT_TRUE(expect_reads_
);
263 EXPECT_FALSE(received_on_will_read_
);
264 EXPECT_FALSE(received_eof_
);
265 EXPECT_FALSE(received_response_completed_
);
268 *buf_size
= kReadBufSize
;
269 received_on_will_read_
= true;
273 bool OnReadCompleted(int bytes_read
, bool* defer
) override
{
274 EXPECT_TRUE(received_on_will_read_
);
275 EXPECT_TRUE(expect_reads_
);
276 EXPECT_FALSE(received_response_completed_
);
278 if (bytes_read
== 0) {
279 received_eof_
= true;
286 // Need another OnWillRead() call before seeing an OnReadCompleted().
287 received_on_will_read_
= false;
289 return !cancel_on_read_completed_
;
292 void OnResponseCompleted(const net::URLRequestStatus
& status
,
293 const std::string
& security_info
,
294 bool* defer
) override
{
295 EXPECT_FALSE(received_response_completed_
);
296 if (status
.is_success() && expect_reads_
)
297 EXPECT_TRUE(received_eof_
);
299 received_response_completed_
= true;
303 void OnDataDownloaded(int bytes_downloaded
) override
{
304 EXPECT_FALSE(expect_reads_
);
305 total_bytes_downloaded_
+= bytes_downloaded
;
309 scoped_refptr
<net::IOBuffer
> read_buffer_
;
311 bool defer_request_on_will_start_
;
313 bool cancel_on_read_completed_
;
317 scoped_refptr
<ResourceResponse
> response_
;
318 bool received_on_will_read_
;
320 bool received_response_completed_
;
321 net::URLRequestStatus status_
;
322 int total_bytes_downloaded_
;
323 scoped_ptr
<base::RunLoop
> wait_for_progress_loop_
;
324 uint64 upload_position_
;
327 // Test browser client that captures calls to SelectClientCertificates and
328 // records the arguments of the most recent call for later inspection.
329 class SelectCertificateBrowserClient
: public TestContentBrowserClient
{
331 SelectCertificateBrowserClient() : call_count_(0) {}
333 void SelectClientCertificate(
334 WebContents
* web_contents
,
335 net::SSLCertRequestInfo
* cert_request_info
,
336 scoped_ptr
<ClientCertificateDelegate
> delegate
) override
{
338 passed_certs_
= cert_request_info
->client_certs
;
339 delegate_
= delegate
.Pass();
342 int call_count() { return call_count_
; }
343 net::CertificateList
passed_certs() { return passed_certs_
; }
345 void ContinueWithCertificate(net::X509Certificate
* cert
) {
346 delegate_
->ContinueWithCertificate(cert
);
350 void CancelCertificateSelection() { delegate_
.reset(); }
353 net::CertificateList passed_certs_
;
355 scoped_ptr
<ClientCertificateDelegate
> delegate_
;
358 class ResourceContextStub
: public MockResourceContext
{
360 explicit ResourceContextStub(net::URLRequestContext
* test_request_context
)
361 : MockResourceContext(test_request_context
) {}
363 scoped_ptr
<net::ClientCertStore
> CreateClientCertStore() override
{
364 return dummy_cert_store_
.Pass();
367 void SetClientCertStore(scoped_ptr
<net::ClientCertStore
> store
) {
368 dummy_cert_store_
= store
.Pass();
372 scoped_ptr
<net::ClientCertStore
> dummy_cert_store_
;
375 // Wraps a ChunkedUploadDataStream to behave as non-chunked to enable upload
376 // progress reporting.
377 class NonChunkedUploadDataStream
: public net::UploadDataStream
{
379 explicit NonChunkedUploadDataStream(uint64 size
)
380 : net::UploadDataStream(false, 0), stream_(0), size_(size
) {}
382 void AppendData(const char* data
) {
383 stream_
.AppendData(data
, strlen(data
), false);
387 int InitInternal() override
{
389 stream_
.Init(base::Bind(&NonChunkedUploadDataStream::OnInitCompleted
,
390 base::Unretained(this)));
394 int ReadInternal(net::IOBuffer
* buf
, int buf_len
) override
{
395 return stream_
.Read(buf
, buf_len
,
396 base::Bind(&NonChunkedUploadDataStream::OnReadCompleted
,
397 base::Unretained(this)));
400 void ResetInternal() override
{ stream_
.Reset(); }
402 net::ChunkedUploadDataStream stream_
;
405 DISALLOW_COPY_AND_ASSIGN(NonChunkedUploadDataStream
);
408 // Fails to create a temporary file with the given error.
409 void CreateTemporaryError(
410 base::File::Error error
,
411 const CreateTemporaryFileStreamCallback
& callback
) {
412 base::ThreadTaskRunnerHandle::Get()->PostTask(
414 base::Bind(callback
, error
, base::Passed(scoped_ptr
<net::FileStream
>()),
415 scoped_refptr
<ShareableFileReference
>()));
420 class ResourceLoaderTest
: public testing::Test
,
421 public ResourceLoaderDelegate
{
424 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP
),
425 resource_context_(&test_url_request_context_
),
426 raw_ptr_resource_handler_(NULL
),
427 raw_ptr_to_request_(NULL
) {
428 test_url_request_context_
.set_job_factory(&job_factory_
);
431 GURL
test_url() const { return net::URLRequestTestJob::test_url_1(); }
433 std::string
test_data() const {
434 return net::URLRequestTestJob::test_data_1();
437 // Waits until upload progress reaches |target_position|
438 void WaitForUploadProgress(uint64 target_position
) {
440 uint64 position
= raw_ptr_resource_handler_
->WaitForUploadProgress();
441 EXPECT_LE(position
, target_position
);
442 loader_
->OnUploadProgressACK();
443 if (position
== target_position
)
448 virtual net::URLRequestJobFactory::ProtocolHandler
* CreateProtocolHandler() {
449 return net::URLRequestTestJob::CreateProtocolHandler();
452 virtual scoped_ptr
<ResourceHandler
> WrapResourceHandler(
453 scoped_ptr
<ResourceHandlerStub
> leaf_handler
,
454 net::URLRequest
* request
) {
455 return leaf_handler
.Pass();
458 // Replaces loader_ with a new one for |request|.
459 void SetUpResourceLoader(scoped_ptr
<net::URLRequest
> request
) {
460 raw_ptr_to_request_
= request
.get();
462 RenderFrameHost
* rfh
= web_contents_
->GetMainFrame();
463 ResourceRequestInfo::AllocateForTesting(
464 request
.get(), RESOURCE_TYPE_MAIN_FRAME
, &resource_context_
,
465 rfh
->GetProcess()->GetID(), rfh
->GetRenderViewHost()->GetRoutingID(),
466 rfh
->GetRoutingID(), true /* is_main_frame */,
467 false /* parent_is_main_frame */, true /* allow_download */,
468 false /* is_async */);
469 scoped_ptr
<ResourceHandlerStub
> resource_handler(
470 new ResourceHandlerStub(request
.get()));
471 raw_ptr_resource_handler_
= resource_handler
.get();
472 loader_
.reset(new ResourceLoader(
474 WrapResourceHandler(resource_handler
.Pass(), raw_ptr_to_request_
),
478 void SetUp() override
{
479 job_factory_
.SetProtocolHandler("test", CreateProtocolHandler());
481 browser_context_
.reset(new TestBrowserContext());
482 scoped_refptr
<SiteInstance
> site_instance
=
483 SiteInstance::Create(browser_context_
.get());
485 TestWebContents::Create(browser_context_
.get(), site_instance
.get()));
487 scoped_ptr
<net::URLRequest
> request(
488 resource_context_
.GetRequestContext()->CreateRequest(
490 net::DEFAULT_PRIORITY
,
491 nullptr /* delegate */));
492 SetUpResourceLoader(request
.Pass());
495 void TearDown() override
{
496 // Destroy the WebContents and pump the event loop before destroying
497 // |rvh_test_enabler_| and |thread_bundle_|. This lets asynchronous cleanup
499 web_contents_
.reset();
500 base::RunLoop().RunUntilIdle();
503 // ResourceLoaderDelegate:
504 ResourceDispatcherHostLoginDelegate
* CreateLoginDelegate(
505 ResourceLoader
* loader
,
506 net::AuthChallengeInfo
* auth_info
) override
{
509 bool HandleExternalProtocol(ResourceLoader
* loader
,
510 const GURL
& url
) override
{
513 void DidStartRequest(ResourceLoader
* loader
) override
{}
514 void DidReceiveRedirect(ResourceLoader
* loader
,
515 const GURL
& new_url
) override
{}
516 void DidReceiveResponse(ResourceLoader
* loader
) override
{}
517 void DidFinishLoading(ResourceLoader
* loader
) override
{}
519 TestBrowserThreadBundle thread_bundle_
;
520 RenderViewHostTestEnabler rvh_test_enabler_
;
522 net::URLRequestJobFactoryImpl job_factory_
;
523 net::TestURLRequestContext test_url_request_context_
;
524 ResourceContextStub resource_context_
;
525 scoped_ptr
<TestBrowserContext
> browser_context_
;
526 scoped_ptr
<TestWebContents
> web_contents_
;
528 // The ResourceLoader owns the URLRequest and the ResourceHandler.
529 ResourceHandlerStub
* raw_ptr_resource_handler_
;
530 net::URLRequest
* raw_ptr_to_request_
;
531 scoped_ptr
<ResourceLoader
> loader_
;
534 class ClientCertResourceLoaderTest
: public ResourceLoaderTest
{
536 net::URLRequestJobFactory::ProtocolHandler
* CreateProtocolHandler() override
{
537 return new MockClientCertJobProtocolHandler
;
541 // Tests that client certificates are requested with ClientCertStore lookup.
542 TEST_F(ClientCertResourceLoaderTest
, WithStoreLookup
) {
543 // Set up the test client cert store.
544 int store_request_count
;
545 std::vector
<std::string
> store_requested_authorities
;
546 net::CertificateList
dummy_certs(1, scoped_refptr
<net::X509Certificate
>(
547 new net::X509Certificate("test", "test", base::Time(), base::Time())));
548 scoped_ptr
<ClientCertStoreStub
> test_store(new ClientCertStoreStub(
549 dummy_certs
, &store_request_count
, &store_requested_authorities
));
550 resource_context_
.SetClientCertStore(test_store
.Pass());
552 // Plug in test content browser client.
553 SelectCertificateBrowserClient test_client
;
554 ContentBrowserClient
* old_client
= SetBrowserClientForTesting(&test_client
);
556 // Start the request and wait for it to pause.
557 loader_
->StartRequest();
558 base::RunLoop().RunUntilIdle();
560 EXPECT_FALSE(raw_ptr_resource_handler_
->received_response_completed());
562 // Check if the test store was queried against correct |cert_authorities|.
563 EXPECT_EQ(1, store_request_count
);
564 EXPECT_EQ(MockClientCertURLRequestJob::test_authorities(),
565 store_requested_authorities
);
567 // Check if the retrieved certificates were passed to the content browser
569 EXPECT_EQ(1, test_client
.call_count());
570 EXPECT_EQ(dummy_certs
, test_client
.passed_certs());
572 // Continue the request.
573 test_client
.ContinueWithCertificate(dummy_certs
[0].get());
574 base::RunLoop().RunUntilIdle();
575 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
576 EXPECT_EQ(net::OK
, raw_ptr_resource_handler_
->status().error());
578 // Restore the original content browser client.
579 SetBrowserClientForTesting(old_client
);
582 // Tests that client certificates are requested on a platform with NULL
584 TEST_F(ClientCertResourceLoaderTest
, WithNullStore
) {
585 // Plug in test content browser client.
586 SelectCertificateBrowserClient test_client
;
587 ContentBrowserClient
* old_client
= SetBrowserClientForTesting(&test_client
);
589 // Start the request and wait for it to pause.
590 loader_
->StartRequest();
591 base::RunLoop().RunUntilIdle();
593 // Check if the SelectClientCertificate was called on the content browser
595 EXPECT_EQ(1, test_client
.call_count());
596 EXPECT_EQ(net::CertificateList(), test_client
.passed_certs());
598 // Continue the request.
599 scoped_refptr
<net::X509Certificate
> cert(
600 new net::X509Certificate("test", "test", base::Time(), base::Time()));
601 test_client
.ContinueWithCertificate(cert
.get());
602 base::RunLoop().RunUntilIdle();
603 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
604 EXPECT_EQ(net::OK
, raw_ptr_resource_handler_
->status().error());
606 // Restore the original content browser client.
607 SetBrowserClientForTesting(old_client
);
610 // Tests that the ContentBrowserClient may cancel a certificate request.
611 TEST_F(ClientCertResourceLoaderTest
, CancelSelection
) {
612 // Plug in test content browser client.
613 SelectCertificateBrowserClient test_client
;
614 ContentBrowserClient
* old_client
= SetBrowserClientForTesting(&test_client
);
616 // Start the request and wait for it to pause.
617 loader_
->StartRequest();
618 base::RunLoop().RunUntilIdle();
620 // Check if the SelectClientCertificate was called on the content browser
622 EXPECT_EQ(1, test_client
.call_count());
623 EXPECT_EQ(net::CertificateList(), test_client
.passed_certs());
625 // Cancel the request.
626 test_client
.CancelCertificateSelection();
627 base::RunLoop().RunUntilIdle();
628 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
629 EXPECT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED
,
630 raw_ptr_resource_handler_
->status().error());
632 // Restore the original content browser client.
633 SetBrowserClientForTesting(old_client
);
636 // Verifies that requests without WebContents attached abort.
637 TEST_F(ClientCertResourceLoaderTest
, NoWebContents
) {
638 // Destroy the WebContents before starting the request.
639 web_contents_
.reset();
641 // Plug in test content browser client.
642 SelectCertificateBrowserClient test_client
;
643 ContentBrowserClient
* old_client
= SetBrowserClientForTesting(&test_client
);
645 // Start the request and wait for it to pause.
646 loader_
->StartRequest();
647 base::RunLoop().RunUntilIdle();
649 // Check that SelectClientCertificate wasn't called and the request aborted.
650 EXPECT_EQ(0, test_client
.call_count());
651 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
652 EXPECT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED
,
653 raw_ptr_resource_handler_
->status().error());
655 // Restore the original content browser client.
656 SetBrowserClientForTesting(old_client
);
659 // Verifies that ClientCertStore's callback doesn't crash if called after the
660 // loader is destroyed.
661 TEST_F(ClientCertResourceLoaderTest
, StoreAsyncCancel
) {
662 scoped_ptr
<LoaderDestroyingCertStore
> test_store(
663 new LoaderDestroyingCertStore(&loader_
));
664 resource_context_
.SetClientCertStore(test_store
.Pass());
666 loader_
->StartRequest();
667 base::RunLoop().RunUntilIdle();
668 EXPECT_FALSE(loader_
);
670 // Pump the event loop to ensure nothing asynchronous crashes either.
671 base::RunLoop().RunUntilIdle();
674 TEST_F(ResourceLoaderTest
, ResumeCancelledRequest
) {
675 raw_ptr_resource_handler_
->set_defer_request_on_will_start(true);
677 loader_
->StartRequest();
678 loader_
->CancelRequest(true);
679 static_cast<ResourceController
*>(loader_
.get())->Resume();
682 // Tests that no invariants are broken if a ResourceHandler cancels during
684 TEST_F(ResourceLoaderTest
, CancelOnReadCompleted
) {
685 raw_ptr_resource_handler_
->set_cancel_on_read_completed(true);
687 loader_
->StartRequest();
688 base::RunLoop().RunUntilIdle();
690 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
691 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
692 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
693 raw_ptr_resource_handler_
->status().status());
696 // Tests that no invariants are broken if a ResourceHandler defers EOF.
697 TEST_F(ResourceLoaderTest
, DeferEOF
) {
698 raw_ptr_resource_handler_
->set_defer_eof(true);
700 loader_
->StartRequest();
701 base::RunLoop().RunUntilIdle();
703 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
704 EXPECT_FALSE(raw_ptr_resource_handler_
->received_response_completed());
706 raw_ptr_resource_handler_
->Resume();
707 base::RunLoop().RunUntilIdle();
709 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
710 EXPECT_EQ(net::URLRequestStatus::SUCCESS
,
711 raw_ptr_resource_handler_
->status().status());
714 // Tests that progress is reported correctly while uploading.
715 // TODO(andresantoso): Add test for the redirect case.
716 TEST_F(ResourceLoaderTest
, UploadProgress
) {
717 // Set up a test server.
718 net::test_server::EmbeddedTestServer server
;
719 ASSERT_TRUE(server
.InitializeAndWaitUntilReady());
721 PathService::Get(content::DIR_TEST_DATA
, &path
);
722 server
.ServeFilesFromDirectory(path
);
724 scoped_ptr
<net::URLRequest
> request(
725 resource_context_
.GetRequestContext()->CreateRequest(
726 server
.GetURL("/title1.html"),
727 net::DEFAULT_PRIORITY
,
728 nullptr /* delegate */));
731 auto stream
= new NonChunkedUploadDataStream(10);
732 request
->set_upload(make_scoped_ptr(stream
));
734 SetUpResourceLoader(request
.Pass());
735 loader_
->StartRequest();
737 stream
->AppendData("xx");
738 WaitForUploadProgress(2);
740 stream
->AppendData("yyy");
741 WaitForUploadProgress(5);
743 stream
->AppendData("zzzzz");
744 WaitForUploadProgress(10);
747 class ResourceLoaderRedirectToFileTest
: public ResourceLoaderTest
{
749 ResourceLoaderRedirectToFileTest()
750 : file_stream_(NULL
),
751 redirect_to_file_resource_handler_(NULL
) {
754 base::FilePath
temp_path() const { return temp_path_
; }
755 ShareableFileReference
* deletable_file() const {
756 return deletable_file_
.get();
758 net::testing::MockFileStream
* file_stream() const { return file_stream_
; }
759 RedirectToFileResourceHandler
* redirect_to_file_resource_handler() const {
760 return redirect_to_file_resource_handler_
;
763 void ReleaseLoader() {
765 deletable_file_
= NULL
;
769 scoped_ptr
<ResourceHandler
> WrapResourceHandler(
770 scoped_ptr
<ResourceHandlerStub
> leaf_handler
,
771 net::URLRequest
* request
) override
{
772 leaf_handler
->set_expect_reads(false);
774 // Make a temporary file.
775 CHECK(base::CreateTemporaryFile(&temp_path_
));
776 int flags
= base::File::FLAG_WRITE
| base::File::FLAG_TEMPORARY
|
777 base::File::FLAG_CREATE_ALWAYS
| base::File::FLAG_ASYNC
;
778 base::File
file(temp_path_
, flags
);
779 CHECK(file
.IsValid());
781 // Create mock file streams and a ShareableFileReference.
782 scoped_ptr
<net::testing::MockFileStream
> file_stream(
783 new net::testing::MockFileStream(file
.Pass(),
784 base::ThreadTaskRunnerHandle::Get()));
785 file_stream_
= file_stream
.get();
786 deletable_file_
= ShareableFileReference::GetOrCreate(
788 ShareableFileReference::DELETE_ON_FINAL_RELEASE
,
789 BrowserThread::GetMessageLoopProxyForThread(
790 BrowserThread::FILE).get());
792 // Inject them into the handler.
793 scoped_ptr
<RedirectToFileResourceHandler
> handler(
794 new RedirectToFileResourceHandler(leaf_handler
.Pass(), request
));
795 redirect_to_file_resource_handler_
= handler
.get();
796 handler
->SetCreateTemporaryFileStreamFunctionForTesting(
797 base::Bind(&ResourceLoaderRedirectToFileTest::PostCallback
,
798 base::Unretained(this),
799 base::Passed(&file_stream
)));
800 return handler
.Pass();
805 scoped_ptr
<net::FileStream
> file_stream
,
806 const CreateTemporaryFileStreamCallback
& callback
) {
807 base::ThreadTaskRunnerHandle::Get()->PostTask(
808 FROM_HERE
, base::Bind(callback
, base::File::FILE_OK
,
809 base::Passed(&file_stream
), deletable_file_
));
812 base::FilePath temp_path_
;
813 scoped_refptr
<ShareableFileReference
> deletable_file_
;
814 // These are owned by the ResourceLoader.
815 net::testing::MockFileStream
* file_stream_
;
816 RedirectToFileResourceHandler
* redirect_to_file_resource_handler_
;
819 // Tests that a RedirectToFileResourceHandler works and forwards everything
821 TEST_F(ResourceLoaderRedirectToFileTest
, Basic
) {
822 // Run it to completion.
823 loader_
->StartRequest();
824 base::RunLoop().RunUntilIdle();
826 // Check that the handler forwarded all information to the downstream handler.
827 EXPECT_EQ(temp_path(),
828 raw_ptr_resource_handler_
->response()->head
.download_file_path
);
829 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
830 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
831 EXPECT_EQ(net::URLRequestStatus::SUCCESS
,
832 raw_ptr_resource_handler_
->status().status());
833 EXPECT_EQ(test_data().size(), static_cast<size_t>(
834 raw_ptr_resource_handler_
->total_bytes_downloaded()));
836 // Check that the data was written to the file.
837 std::string contents
;
838 ASSERT_TRUE(base::ReadFileToString(temp_path(), &contents
));
839 EXPECT_EQ(test_data(), contents
);
841 // Release the loader and the saved reference to file. The file should be gone
844 base::RunLoop().RunUntilIdle();
845 EXPECT_FALSE(base::PathExists(temp_path()));
848 // Tests that RedirectToFileResourceHandler handles errors in creating the
850 TEST_F(ResourceLoaderRedirectToFileTest
, CreateTemporaryError
) {
851 // Swap out the create temporary function.
852 redirect_to_file_resource_handler()->
853 SetCreateTemporaryFileStreamFunctionForTesting(
854 base::Bind(&CreateTemporaryError
, base::File::FILE_ERROR_FAILED
));
856 // Run it to completion.
857 loader_
->StartRequest();
858 base::RunLoop().RunUntilIdle();
860 // To downstream, the request was canceled.
861 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
862 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
863 raw_ptr_resource_handler_
->status().status());
864 EXPECT_EQ(0, raw_ptr_resource_handler_
->total_bytes_downloaded());
867 // Tests that RedirectToFileResourceHandler handles synchronous write errors.
868 TEST_F(ResourceLoaderRedirectToFileTest
, WriteError
) {
869 file_stream()->set_forced_error(net::ERR_FAILED
);
871 // Run it to completion.
872 loader_
->StartRequest();
873 base::RunLoop().RunUntilIdle();
875 // To downstream, the request was canceled sometime after it started, but
876 // before any data was written.
877 EXPECT_EQ(temp_path(),
878 raw_ptr_resource_handler_
->response()->head
.download_file_path
);
879 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
880 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
881 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
882 raw_ptr_resource_handler_
->status().status());
883 EXPECT_EQ(0, raw_ptr_resource_handler_
->total_bytes_downloaded());
885 // Release the loader. The file should be gone now.
887 base::RunLoop().RunUntilIdle();
888 EXPECT_FALSE(base::PathExists(temp_path()));
891 // Tests that RedirectToFileResourceHandler handles asynchronous write errors.
892 TEST_F(ResourceLoaderRedirectToFileTest
, WriteErrorAsync
) {
893 file_stream()->set_forced_error_async(net::ERR_FAILED
);
895 // Run it to completion.
896 loader_
->StartRequest();
897 base::RunLoop().RunUntilIdle();
899 // To downstream, the request was canceled sometime after it started, but
900 // before any data was written.
901 EXPECT_EQ(temp_path(),
902 raw_ptr_resource_handler_
->response()->head
.download_file_path
);
903 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
904 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
905 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
906 raw_ptr_resource_handler_
->status().status());
907 EXPECT_EQ(0, raw_ptr_resource_handler_
->total_bytes_downloaded());
909 // Release the loader. The file should be gone now.
911 base::RunLoop().RunUntilIdle();
912 EXPECT_FALSE(base::PathExists(temp_path()));
915 // Tests that RedirectToFileHandler defers completion if there are outstanding
916 // writes and accounts for errors which occur in that time.
917 TEST_F(ResourceLoaderRedirectToFileTest
, DeferCompletion
) {
918 // Program the MockFileStream to error asynchronously, but throttle the
920 file_stream()->set_forced_error_async(net::ERR_FAILED
);
921 file_stream()->ThrottleCallbacks();
923 // Run it as far as it will go.
924 loader_
->StartRequest();
925 base::RunLoop().RunUntilIdle();
927 // At this point, the request should have completed.
928 EXPECT_EQ(net::URLRequestStatus::SUCCESS
,
929 raw_ptr_to_request_
->status().status());
931 // However, the resource loader stack is stuck somewhere after receiving the
933 EXPECT_EQ(temp_path(),
934 raw_ptr_resource_handler_
->response()->head
.download_file_path
);
935 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
936 EXPECT_FALSE(raw_ptr_resource_handler_
->received_response_completed());
937 EXPECT_EQ(0, raw_ptr_resource_handler_
->total_bytes_downloaded());
939 // Now, release the floodgates.
940 file_stream()->ReleaseCallbacks();
941 base::RunLoop().RunUntilIdle();
943 // Although the URLRequest was successful, the leaf handler sees a failure
944 // because the write never completed.
945 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
946 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
947 raw_ptr_resource_handler_
->status().status());
949 // Release the loader. The file should be gone now.
951 base::RunLoop().RunUntilIdle();
952 EXPECT_FALSE(base::PathExists(temp_path()));
955 // Tests that a RedirectToFileResourceHandler behaves properly when the
956 // downstream handler defers OnWillStart.
957 TEST_F(ResourceLoaderRedirectToFileTest
, DownstreamDeferStart
) {
958 // Defer OnWillStart.
959 raw_ptr_resource_handler_
->set_defer_request_on_will_start(true);
961 // Run as far as we'll go.
962 loader_
->StartRequest();
963 base::RunLoop().RunUntilIdle();
965 // The request should have stopped at OnWillStart.
966 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
967 EXPECT_FALSE(raw_ptr_resource_handler_
->response());
968 EXPECT_FALSE(raw_ptr_resource_handler_
->received_response_completed());
969 EXPECT_EQ(0, raw_ptr_resource_handler_
->total_bytes_downloaded());
971 // Now resume the request. Now we complete.
972 raw_ptr_resource_handler_
->Resume();
973 base::RunLoop().RunUntilIdle();
975 // Check that the handler forwarded all information to the downstream handler.
976 EXPECT_EQ(temp_path(),
977 raw_ptr_resource_handler_
->response()->head
.download_file_path
);
978 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
979 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
980 EXPECT_EQ(net::URLRequestStatus::SUCCESS
,
981 raw_ptr_resource_handler_
->status().status());
982 EXPECT_EQ(test_data().size(), static_cast<size_t>(
983 raw_ptr_resource_handler_
->total_bytes_downloaded()));
985 // Check that the data was written to the file.
986 std::string contents
;
987 ASSERT_TRUE(base::ReadFileToString(temp_path(), &contents
));
988 EXPECT_EQ(test_data(), contents
);
990 // Release the loader. The file should be gone now.
992 base::RunLoop().RunUntilIdle();
993 EXPECT_FALSE(base::PathExists(temp_path()));
996 } // namespace content