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/message_loop/message_loop_proxy.h"
10 #include "base/run_loop.h"
11 #include "content/browser/browser_thread_impl.h"
12 #include "content/browser/loader/redirect_to_file_resource_handler.h"
13 #include "content/browser/loader/resource_loader_delegate.h"
14 #include "content/public/browser/resource_request_info.h"
15 #include "content/public/common/resource_response.h"
16 #include "content/public/test/mock_resource_context.h"
17 #include "content/public/test/test_browser_thread_bundle.h"
18 #include "content/test/test_content_browser_client.h"
19 #include "ipc/ipc_message.h"
20 #include "net/base/io_buffer.h"
21 #include "net/base/mock_file_stream.h"
22 #include "net/base/request_priority.h"
23 #include "net/cert/x509_certificate.h"
24 #include "net/ssl/client_cert_store.h"
25 #include "net/ssl/ssl_cert_request_info.h"
26 #include "net/url_request/url_request.h"
27 #include "net/url_request/url_request_job_factory_impl.h"
28 #include "net/url_request/url_request_test_job.h"
29 #include "net/url_request/url_request_test_util.h"
30 #include "storage/browser/blob/shareable_file_reference.h"
31 #include "testing/gtest/include/gtest/gtest.h"
33 using storage::ShareableFileReference
;
38 // Stub client certificate store that returns a preset list of certificates for
39 // each request and records the arguments of the most recent request for later
41 class ClientCertStoreStub
: public net::ClientCertStore
{
43 // Creates a new ClientCertStoreStub that returns |response| on query. It
44 // saves the number of requests and most recently certificate authorities list
45 // in |requested_authorities| and |request_count|, respectively. The caller is
46 // responsible for ensuring those pointers outlive the ClientCertStoreStub.
48 // TODO(ppi): Make the stub independent from the internal representation of
49 // SSLCertRequestInfo. For now it seems that we can neither save the
50 // scoped_refptr<> (since it is never passed to us) nor copy the entire
51 // CertificateRequestInfo (since there is no copy constructor).
52 ClientCertStoreStub(const net::CertificateList
& response
,
54 std::vector
<std::string
>* requested_authorities
)
55 : response_(response
),
57 requested_authorities_(requested_authorities
),
58 request_count_(request_count
) {
59 requested_authorities_
->clear();
63 ~ClientCertStoreStub() override
{}
65 // Configures whether the certificates are returned asynchronously or not.
66 void set_async(bool async
) { async_
= async
; }
68 // net::ClientCertStore:
69 void GetClientCerts(const net::SSLCertRequestInfo
& cert_request_info
,
70 net::CertificateList
* selected_certs
,
71 const base::Closure
& callback
) override
{
72 *requested_authorities_
= cert_request_info
.cert_authorities
;
75 *selected_certs
= response_
;
77 base::MessageLoop::current()->PostTask(FROM_HERE
, callback
);
84 const net::CertificateList response_
;
86 std::vector
<std::string
>* requested_authorities_
;
90 // Arbitrary read buffer size.
91 const int kReadBufSize
= 1024;
93 // Dummy implementation of ResourceHandler, instance of which is needed to
94 // initialize ResourceLoader.
95 class ResourceHandlerStub
: public ResourceHandler
{
97 explicit ResourceHandlerStub(net::URLRequest
* request
)
98 : ResourceHandler(request
),
99 read_buffer_(new net::IOBuffer(kReadBufSize
)),
100 defer_request_on_will_start_(false),
102 cancel_on_read_completed_(false),
104 received_on_will_read_(false),
105 received_eof_(false),
106 received_response_completed_(false),
107 total_bytes_downloaded_(0) {
110 // If true, defers the resource load in OnWillStart.
111 void set_defer_request_on_will_start(bool defer_request_on_will_start
) {
112 defer_request_on_will_start_
= defer_request_on_will_start
;
115 // If true, expect OnWillRead / OnReadCompleted pairs for handling
116 // data. Otherwise, expect OnDataDownloaded.
117 void set_expect_reads(bool expect_reads
) { expect_reads_
= expect_reads
; }
119 // If true, cancel the request in OnReadCompleted by returning false.
120 void set_cancel_on_read_completed(bool cancel_on_read_completed
) {
121 cancel_on_read_completed_
= cancel_on_read_completed
;
124 // If true, cancel the request in OnReadCompleted by returning false.
125 void set_defer_eof(bool defer_eof
) { defer_eof_
= defer_eof
; }
127 const GURL
& start_url() const { return start_url_
; }
128 ResourceResponse
* response() const { return response_
.get(); }
129 bool received_response_completed() const {
130 return received_response_completed_
;
132 const net::URLRequestStatus
& status() const { return status_
; }
133 int total_bytes_downloaded() const { return total_bytes_downloaded_
; }
136 controller()->Resume();
139 // ResourceHandler implementation:
140 bool OnUploadProgress(uint64 position
, uint64 size
) override
{
145 bool OnRequestRedirected(const net::RedirectInfo
& redirect_info
,
146 ResourceResponse
* response
,
147 bool* defer
) override
{
152 bool OnResponseStarted(ResourceResponse
* response
, bool* defer
) override
{
153 EXPECT_FALSE(response_
.get());
154 response_
= response
;
158 bool OnWillStart(const GURL
& url
, bool* defer
) override
{
159 EXPECT_TRUE(start_url_
.is_empty());
161 *defer
= defer_request_on_will_start_
;
165 bool OnBeforeNetworkStart(const GURL
& url
, bool* defer
) override
{
169 bool OnWillRead(scoped_refptr
<net::IOBuffer
>* buf
,
171 int min_size
) override
{
172 EXPECT_TRUE(expect_reads_
);
173 EXPECT_FALSE(received_on_will_read_
);
174 EXPECT_FALSE(received_eof_
);
175 EXPECT_FALSE(received_response_completed_
);
178 *buf_size
= kReadBufSize
;
179 received_on_will_read_
= true;
183 bool OnReadCompleted(int bytes_read
, bool* defer
) override
{
184 EXPECT_TRUE(received_on_will_read_
);
185 EXPECT_TRUE(expect_reads_
);
186 EXPECT_FALSE(received_response_completed_
);
188 if (bytes_read
== 0) {
189 received_eof_
= true;
196 // Need another OnWillRead() call before seeing an OnReadCompleted().
197 received_on_will_read_
= false;
199 return !cancel_on_read_completed_
;
202 void OnResponseCompleted(const net::URLRequestStatus
& status
,
203 const std::string
& security_info
,
204 bool* defer
) override
{
205 EXPECT_FALSE(received_response_completed_
);
206 if (status
.is_success() && expect_reads_
)
207 EXPECT_TRUE(received_eof_
);
209 received_response_completed_
= true;
213 void OnDataDownloaded(int bytes_downloaded
) override
{
214 EXPECT_FALSE(expect_reads_
);
215 total_bytes_downloaded_
+= bytes_downloaded
;
219 scoped_refptr
<net::IOBuffer
> read_buffer_
;
221 bool defer_request_on_will_start_
;
223 bool cancel_on_read_completed_
;
227 scoped_refptr
<ResourceResponse
> response_
;
228 bool received_on_will_read_
;
230 bool received_response_completed_
;
231 net::URLRequestStatus status_
;
232 int total_bytes_downloaded_
;
235 // Test browser client that captures calls to SelectClientCertificates and
236 // records the arguments of the most recent call for later inspection.
237 class SelectCertificateBrowserClient
: public TestContentBrowserClient
{
239 SelectCertificateBrowserClient() : call_count_(0) {}
241 void SelectClientCertificate(
242 int render_process_id
,
244 net::SSLCertRequestInfo
* cert_request_info
,
245 const base::Callback
<void(net::X509Certificate
*)>& callback
) override
{
247 passed_certs_
= cert_request_info
->client_certs
;
254 net::CertificateList
passed_certs() {
255 return passed_certs_
;
259 net::CertificateList passed_certs_
;
263 class ResourceContextStub
: public MockResourceContext
{
265 explicit ResourceContextStub(net::URLRequestContext
* test_request_context
)
266 : MockResourceContext(test_request_context
) {}
268 scoped_ptr
<net::ClientCertStore
> CreateClientCertStore() override
{
269 return dummy_cert_store_
.Pass();
272 void SetClientCertStore(scoped_ptr
<net::ClientCertStore
> store
) {
273 dummy_cert_store_
= store
.Pass();
277 scoped_ptr
<net::ClientCertStore
> dummy_cert_store_
;
280 // Fails to create a temporary file with the given error.
281 void CreateTemporaryError(
282 base::File::Error error
,
283 const CreateTemporaryFileStreamCallback
& callback
) {
284 base::MessageLoop::current()->PostTask(
286 base::Bind(callback
, error
, base::Passed(scoped_ptr
<net::FileStream
>()),
287 scoped_refptr
<ShareableFileReference
>()));
292 class ResourceLoaderTest
: public testing::Test
,
293 public ResourceLoaderDelegate
{
296 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP
),
297 resource_context_(&test_url_request_context_
),
298 raw_ptr_resource_handler_(NULL
),
299 raw_ptr_to_request_(NULL
) {
300 job_factory_
.SetProtocolHandler(
301 "test", net::URLRequestTestJob::CreateProtocolHandler());
302 test_url_request_context_
.set_job_factory(&job_factory_
);
305 GURL
test_url() const {
306 return net::URLRequestTestJob::test_url_1();
309 std::string
test_data() const {
310 return net::URLRequestTestJob::test_data_1();
313 virtual scoped_ptr
<ResourceHandler
> WrapResourceHandler(
314 scoped_ptr
<ResourceHandlerStub
> leaf_handler
,
315 net::URLRequest
* request
) {
316 return leaf_handler
.Pass();
319 void SetUp() override
{
320 const int kRenderProcessId
= 1;
321 const int kRenderViewId
= 2;
323 scoped_ptr
<net::URLRequest
> request(
324 resource_context_
.GetRequestContext()->CreateRequest(
326 net::DEFAULT_PRIORITY
,
328 NULL
/* cookie_store */));
329 raw_ptr_to_request_
= request
.get();
330 ResourceRequestInfo::AllocateForTesting(request
.get(),
331 RESOURCE_TYPE_MAIN_FRAME
,
336 true, // is_main_frame
337 false, // parent_is_main_frame
338 true, // allow_download
340 scoped_ptr
<ResourceHandlerStub
> resource_handler(
341 new ResourceHandlerStub(request
.get()));
342 raw_ptr_resource_handler_
= resource_handler
.get();
343 loader_
.reset(new ResourceLoader(
345 WrapResourceHandler(resource_handler
.Pass(), raw_ptr_to_request_
),
349 // ResourceLoaderDelegate:
350 ResourceDispatcherHostLoginDelegate
* CreateLoginDelegate(
351 ResourceLoader
* loader
,
352 net::AuthChallengeInfo
* auth_info
) override
{
355 bool HandleExternalProtocol(ResourceLoader
* loader
,
356 const GURL
& url
) override
{
359 void DidStartRequest(ResourceLoader
* loader
) override
{}
360 void DidReceiveRedirect(ResourceLoader
* loader
,
361 const GURL
& new_url
) override
{}
362 void DidReceiveResponse(ResourceLoader
* loader
) override
{}
363 void DidFinishLoading(ResourceLoader
* loader
) override
{}
365 content::TestBrowserThreadBundle thread_bundle_
;
367 net::URLRequestJobFactoryImpl job_factory_
;
368 net::TestURLRequestContext test_url_request_context_
;
369 ResourceContextStub resource_context_
;
371 // The ResourceLoader owns the URLRequest and the ResourceHandler.
372 ResourceHandlerStub
* raw_ptr_resource_handler_
;
373 net::URLRequest
* raw_ptr_to_request_
;
374 scoped_ptr
<ResourceLoader
> loader_
;
377 // Verifies if a call to net::UrlRequest::Delegate::OnCertificateRequested()
378 // causes client cert store to be queried for certificates and if the returned
379 // certificates are correctly passed to the content browser client for
381 TEST_F(ResourceLoaderTest
, ClientCertStoreLookup
) {
382 // Set up the test client cert store.
383 int store_request_count
;
384 std::vector
<std::string
> store_requested_authorities
;
385 net::CertificateList
dummy_certs(1, scoped_refptr
<net::X509Certificate
>(
386 new net::X509Certificate("test", "test", base::Time(), base::Time())));
387 scoped_ptr
<ClientCertStoreStub
> test_store(new ClientCertStoreStub(
388 dummy_certs
, &store_request_count
, &store_requested_authorities
));
389 resource_context_
.SetClientCertStore(test_store
.Pass());
391 // Prepare a dummy certificate request.
392 scoped_refptr
<net::SSLCertRequestInfo
> cert_request_info(
393 new net::SSLCertRequestInfo());
394 std::vector
<std::string
> dummy_authority(1, "dummy");
395 cert_request_info
->cert_authorities
= dummy_authority
;
397 // Plug in test content browser client.
398 SelectCertificateBrowserClient test_client
;
399 ContentBrowserClient
* old_client
= SetBrowserClientForTesting(&test_client
);
401 // Everything is set up. Trigger the resource loader certificate request event
402 // and run the message loop.
403 loader_
->OnCertificateRequested(raw_ptr_to_request_
, cert_request_info
.get());
404 base::RunLoop().RunUntilIdle();
406 // Restore the original content browser client.
407 SetBrowserClientForTesting(old_client
);
409 // Check if the test store was queried against correct |cert_authorities|.
410 EXPECT_EQ(1, store_request_count
);
411 EXPECT_EQ(dummy_authority
, store_requested_authorities
);
413 // Check if the retrieved certificates were passed to the content browser
415 EXPECT_EQ(1, test_client
.call_count());
416 EXPECT_EQ(dummy_certs
, test_client
.passed_certs());
419 // Verifies if a call to net::URLRequest::Delegate::OnCertificateRequested()
420 // on a platform with a NULL client cert store still calls the content browser
421 // client for selection.
422 TEST_F(ResourceLoaderTest
, ClientCertStoreNull
) {
423 // Prepare a dummy certificate request.
424 scoped_refptr
<net::SSLCertRequestInfo
> cert_request_info(
425 new net::SSLCertRequestInfo());
426 std::vector
<std::string
> dummy_authority(1, "dummy");
427 cert_request_info
->cert_authorities
= dummy_authority
;
429 // Plug in test content browser client.
430 SelectCertificateBrowserClient test_client
;
431 ContentBrowserClient
* old_client
= SetBrowserClientForTesting(&test_client
);
433 // Everything is set up. Trigger the resource loader certificate request event
434 // and run the message loop.
435 loader_
->OnCertificateRequested(raw_ptr_to_request_
, cert_request_info
.get());
436 base::RunLoop().RunUntilIdle();
438 // Restore the original content browser client.
439 SetBrowserClientForTesting(old_client
);
441 // Check if the SelectClientCertificate was called on the content browser
443 EXPECT_EQ(1, test_client
.call_count());
444 EXPECT_EQ(net::CertificateList(), test_client
.passed_certs());
447 TEST_F(ResourceLoaderTest
, ClientCertStoreAsyncCancel
) {
448 // Set up the test client cert store.
449 int store_request_count
;
450 std::vector
<std::string
> store_requested_authorities
;
451 scoped_ptr
<ClientCertStoreStub
> test_store(
452 new ClientCertStoreStub(net::CertificateList(), &store_request_count
,
453 &store_requested_authorities
));
454 test_store
->set_async(true);
455 EXPECT_EQ(0, store_request_count
);
456 resource_context_
.SetClientCertStore(test_store
.Pass());
458 // Prepare a dummy certificate request.
459 scoped_refptr
<net::SSLCertRequestInfo
> cert_request_info(
460 new net::SSLCertRequestInfo());
461 std::vector
<std::string
> dummy_authority(1, "dummy");
462 cert_request_info
->cert_authorities
= dummy_authority
;
464 // Everything is set up. Trigger the resource loader certificate request
466 loader_
->OnCertificateRequested(raw_ptr_to_request_
, cert_request_info
.get());
468 // Check if the test store was queried against correct |cert_authorities|.
469 EXPECT_EQ(1, store_request_count
);
470 EXPECT_EQ(dummy_authority
, store_requested_authorities
);
472 // Cancel the request before the store calls the callback.
475 // Pump the event loop. There shouldn't be a crash when the callback is run.
476 base::RunLoop().RunUntilIdle();
479 TEST_F(ResourceLoaderTest
, ResumeCancelledRequest
) {
480 raw_ptr_resource_handler_
->set_defer_request_on_will_start(true);
482 loader_
->StartRequest();
483 loader_
->CancelRequest(true);
484 static_cast<ResourceController
*>(loader_
.get())->Resume();
487 // Tests that no invariants are broken if a ResourceHandler cancels during
489 TEST_F(ResourceLoaderTest
, CancelOnReadCompleted
) {
490 raw_ptr_resource_handler_
->set_cancel_on_read_completed(true);
492 loader_
->StartRequest();
493 base::RunLoop().RunUntilIdle();
495 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
496 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
497 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
498 raw_ptr_resource_handler_
->status().status());
501 // Tests that no invariants are broken if a ResourceHandler defers EOF.
502 TEST_F(ResourceLoaderTest
, DeferEOF
) {
503 raw_ptr_resource_handler_
->set_defer_eof(true);
505 loader_
->StartRequest();
506 base::RunLoop().RunUntilIdle();
508 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
509 EXPECT_FALSE(raw_ptr_resource_handler_
->received_response_completed());
511 raw_ptr_resource_handler_
->Resume();
512 base::RunLoop().RunUntilIdle();
514 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
515 EXPECT_EQ(net::URLRequestStatus::SUCCESS
,
516 raw_ptr_resource_handler_
->status().status());
519 class ResourceLoaderRedirectToFileTest
: public ResourceLoaderTest
{
521 ResourceLoaderRedirectToFileTest()
522 : file_stream_(NULL
),
523 redirect_to_file_resource_handler_(NULL
) {
526 base::FilePath
temp_path() const { return temp_path_
; }
527 ShareableFileReference
* deletable_file() const {
528 return deletable_file_
.get();
530 net::testing::MockFileStream
* file_stream() const { return file_stream_
; }
531 RedirectToFileResourceHandler
* redirect_to_file_resource_handler() const {
532 return redirect_to_file_resource_handler_
;
535 void ReleaseLoader() {
537 deletable_file_
= NULL
;
541 scoped_ptr
<ResourceHandler
> WrapResourceHandler(
542 scoped_ptr
<ResourceHandlerStub
> leaf_handler
,
543 net::URLRequest
* request
) override
{
544 leaf_handler
->set_expect_reads(false);
546 // Make a temporary file.
547 CHECK(base::CreateTemporaryFile(&temp_path_
));
548 int flags
= base::File::FLAG_WRITE
| base::File::FLAG_TEMPORARY
|
549 base::File::FLAG_CREATE_ALWAYS
| base::File::FLAG_ASYNC
;
550 base::File
file(temp_path_
, flags
);
551 CHECK(file
.IsValid());
553 // Create mock file streams and a ShareableFileReference.
554 scoped_ptr
<net::testing::MockFileStream
> file_stream(
555 new net::testing::MockFileStream(file
.Pass(),
556 base::MessageLoopProxy::current()));
557 file_stream_
= file_stream
.get();
558 deletable_file_
= ShareableFileReference::GetOrCreate(
560 ShareableFileReference::DELETE_ON_FINAL_RELEASE
,
561 BrowserThread::GetMessageLoopProxyForThread(
562 BrowserThread::FILE).get());
564 // Inject them into the handler.
565 scoped_ptr
<RedirectToFileResourceHandler
> handler(
566 new RedirectToFileResourceHandler(leaf_handler
.Pass(), request
));
567 redirect_to_file_resource_handler_
= handler
.get();
568 handler
->SetCreateTemporaryFileStreamFunctionForTesting(
569 base::Bind(&ResourceLoaderRedirectToFileTest::PostCallback
,
570 base::Unretained(this),
571 base::Passed(&file_stream
)));
572 return handler
.Pass();
577 scoped_ptr
<net::FileStream
> file_stream
,
578 const CreateTemporaryFileStreamCallback
& callback
) {
579 base::MessageLoop::current()->PostTask(
581 base::Bind(callback
, base::File::FILE_OK
,
582 base::Passed(&file_stream
), deletable_file_
));
585 base::FilePath temp_path_
;
586 scoped_refptr
<ShareableFileReference
> deletable_file_
;
587 // These are owned by the ResourceLoader.
588 net::testing::MockFileStream
* file_stream_
;
589 RedirectToFileResourceHandler
* redirect_to_file_resource_handler_
;
592 // Tests that a RedirectToFileResourceHandler works and forwards everything
594 TEST_F(ResourceLoaderRedirectToFileTest
, Basic
) {
595 // Run it to completion.
596 loader_
->StartRequest();
597 base::RunLoop().RunUntilIdle();
599 // Check that the handler forwarded all information to the downstream handler.
600 EXPECT_EQ(temp_path(),
601 raw_ptr_resource_handler_
->response()->head
.download_file_path
);
602 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
603 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
604 EXPECT_EQ(net::URLRequestStatus::SUCCESS
,
605 raw_ptr_resource_handler_
->status().status());
606 EXPECT_EQ(test_data().size(), static_cast<size_t>(
607 raw_ptr_resource_handler_
->total_bytes_downloaded()));
609 // Check that the data was written to the file.
610 std::string contents
;
611 ASSERT_TRUE(base::ReadFileToString(temp_path(), &contents
));
612 EXPECT_EQ(test_data(), contents
);
614 // Release the loader and the saved reference to file. The file should be gone
617 base::RunLoop().RunUntilIdle();
618 EXPECT_FALSE(base::PathExists(temp_path()));
621 // Tests that RedirectToFileResourceHandler handles errors in creating the
623 TEST_F(ResourceLoaderRedirectToFileTest
, CreateTemporaryError
) {
624 // Swap out the create temporary function.
625 redirect_to_file_resource_handler()->
626 SetCreateTemporaryFileStreamFunctionForTesting(
627 base::Bind(&CreateTemporaryError
, base::File::FILE_ERROR_FAILED
));
629 // Run it to completion.
630 loader_
->StartRequest();
631 base::RunLoop().RunUntilIdle();
633 // To downstream, the request was canceled.
634 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
635 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
636 raw_ptr_resource_handler_
->status().status());
637 EXPECT_EQ(0, raw_ptr_resource_handler_
->total_bytes_downloaded());
640 // Tests that RedirectToFileResourceHandler handles synchronous write errors.
641 TEST_F(ResourceLoaderRedirectToFileTest
, WriteError
) {
642 file_stream()->set_forced_error(net::ERR_FAILED
);
644 // Run it to completion.
645 loader_
->StartRequest();
646 base::RunLoop().RunUntilIdle();
648 // To downstream, the request was canceled sometime after it started, but
649 // before any data was written.
650 EXPECT_EQ(temp_path(),
651 raw_ptr_resource_handler_
->response()->head
.download_file_path
);
652 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
653 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
654 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
655 raw_ptr_resource_handler_
->status().status());
656 EXPECT_EQ(0, raw_ptr_resource_handler_
->total_bytes_downloaded());
658 // Release the loader. The file should be gone now.
660 base::RunLoop().RunUntilIdle();
661 EXPECT_FALSE(base::PathExists(temp_path()));
664 // Tests that RedirectToFileResourceHandler handles asynchronous write errors.
665 TEST_F(ResourceLoaderRedirectToFileTest
, WriteErrorAsync
) {
666 file_stream()->set_forced_error_async(net::ERR_FAILED
);
668 // Run it to completion.
669 loader_
->StartRequest();
670 base::RunLoop().RunUntilIdle();
672 // To downstream, the request was canceled sometime after it started, but
673 // before any data was written.
674 EXPECT_EQ(temp_path(),
675 raw_ptr_resource_handler_
->response()->head
.download_file_path
);
676 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
677 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
678 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
679 raw_ptr_resource_handler_
->status().status());
680 EXPECT_EQ(0, raw_ptr_resource_handler_
->total_bytes_downloaded());
682 // Release the loader. The file should be gone now.
684 base::RunLoop().RunUntilIdle();
685 EXPECT_FALSE(base::PathExists(temp_path()));
688 // Tests that RedirectToFileHandler defers completion if there are outstanding
689 // writes and accounts for errors which occur in that time.
690 TEST_F(ResourceLoaderRedirectToFileTest
, DeferCompletion
) {
691 // Program the MockFileStream to error asynchronously, but throttle the
693 file_stream()->set_forced_error_async(net::ERR_FAILED
);
694 file_stream()->ThrottleCallbacks();
696 // Run it as far as it will go.
697 loader_
->StartRequest();
698 base::RunLoop().RunUntilIdle();
700 // At this point, the request should have completed.
701 EXPECT_EQ(net::URLRequestStatus::SUCCESS
,
702 raw_ptr_to_request_
->status().status());
704 // However, the resource loader stack is stuck somewhere after receiving the
706 EXPECT_EQ(temp_path(),
707 raw_ptr_resource_handler_
->response()->head
.download_file_path
);
708 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
709 EXPECT_FALSE(raw_ptr_resource_handler_
->received_response_completed());
710 EXPECT_EQ(0, raw_ptr_resource_handler_
->total_bytes_downloaded());
712 // Now, release the floodgates.
713 file_stream()->ReleaseCallbacks();
714 base::RunLoop().RunUntilIdle();
716 // Although the URLRequest was successful, the leaf handler sees a failure
717 // because the write never completed.
718 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
719 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
720 raw_ptr_resource_handler_
->status().status());
722 // Release the loader. The file should be gone now.
724 base::RunLoop().RunUntilIdle();
725 EXPECT_FALSE(base::PathExists(temp_path()));
728 // Tests that a RedirectToFileResourceHandler behaves properly when the
729 // downstream handler defers OnWillStart.
730 TEST_F(ResourceLoaderRedirectToFileTest
, DownstreamDeferStart
) {
731 // Defer OnWillStart.
732 raw_ptr_resource_handler_
->set_defer_request_on_will_start(true);
734 // Run as far as we'll go.
735 loader_
->StartRequest();
736 base::RunLoop().RunUntilIdle();
738 // The request should have stopped at OnWillStart.
739 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
740 EXPECT_FALSE(raw_ptr_resource_handler_
->response());
741 EXPECT_FALSE(raw_ptr_resource_handler_
->received_response_completed());
742 EXPECT_EQ(0, raw_ptr_resource_handler_
->total_bytes_downloaded());
744 // Now resume the request. Now we complete.
745 raw_ptr_resource_handler_
->Resume();
746 base::RunLoop().RunUntilIdle();
748 // Check that the handler forwarded all information to the downstream handler.
749 EXPECT_EQ(temp_path(),
750 raw_ptr_resource_handler_
->response()->head
.download_file_path
);
751 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
752 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
753 EXPECT_EQ(net::URLRequestStatus::SUCCESS
,
754 raw_ptr_resource_handler_
->status().status());
755 EXPECT_EQ(test_data().size(), static_cast<size_t>(
756 raw_ptr_resource_handler_
->total_bytes_downloaded()));
758 // Check that the data was written to the file.
759 std::string contents
;
760 ASSERT_TRUE(base::ReadFileToString(temp_path(), &contents
));
761 EXPECT_EQ(test_data(), contents
);
763 // Release the loader. The file should be gone now.
765 base::RunLoop().RunUntilIdle();
766 EXPECT_FALSE(base::PathExists(temp_path()));
769 } // namespace content