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/file_util.h"
8 #include "base/files/file.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 "testing/gtest/include/gtest/gtest.h"
31 #include "webkit/common/blob/shareable_file_reference.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 ClientCertStoreStub(const net::CertificateList
& certs
)
47 virtual ~ClientCertStoreStub() {}
49 // Returns |cert_authorities| field of the certificate request passed in the
50 // most recent call to GetClientCerts().
51 // TODO(ppi): Make the stub independent from the internal representation of
52 // SSLCertRequestInfo. For now it seems that we cannot neither save the
53 // scoped_refptr<> (since it is never passed to us) nor copy the entire
54 // CertificateRequestInfo (since there is no copy constructor).
55 std::vector
<std::string
> requested_authorities() {
56 return requested_authorities_
;
59 // Returns the number of calls to GetClientCerts().
61 return request_count_
;
64 // net::ClientCertStore:
65 virtual void GetClientCerts(const net::SSLCertRequestInfo
& cert_request_info
,
66 net::CertificateList
* selected_certs
,
67 const base::Closure
& callback
) OVERRIDE
{
69 requested_authorities_
= cert_request_info
.cert_authorities
;
70 *selected_certs
= response_
;
75 const net::CertificateList response_
;
77 std::vector
<std::string
> requested_authorities_
;
80 // Arbitrary read buffer size.
81 const int kReadBufSize
= 1024;
83 // Dummy implementation of ResourceHandler, instance of which is needed to
84 // initialize ResourceLoader.
85 class ResourceHandlerStub
: public ResourceHandler
{
87 explicit ResourceHandlerStub(net::URLRequest
* request
)
88 : ResourceHandler(request
),
89 read_buffer_(new net::IOBuffer(kReadBufSize
)),
90 defer_request_on_will_start_(false),
92 cancel_on_read_completed_(false),
94 received_on_will_read_(false),
96 received_response_completed_(false),
97 total_bytes_downloaded_(0) {
100 // If true, defers the resource load in OnWillStart.
101 void set_defer_request_on_will_start(bool defer_request_on_will_start
) {
102 defer_request_on_will_start_
= defer_request_on_will_start
;
105 // If true, expect OnWillRead / OnReadCompleted pairs for handling
106 // data. Otherwise, expect OnDataDownloaded.
107 void set_expect_reads(bool expect_reads
) { expect_reads_
= expect_reads
; }
109 // If true, cancel the request in OnReadCompleted by returning false.
110 void set_cancel_on_read_completed(bool cancel_on_read_completed
) {
111 cancel_on_read_completed_
= cancel_on_read_completed
;
114 // If true, cancel the request in OnReadCompleted by returning false.
115 void set_defer_eof(bool defer_eof
) { defer_eof_
= defer_eof
; }
117 const GURL
& start_url() const { return start_url_
; }
118 ResourceResponse
* response() const { return response_
.get(); }
119 bool received_response_completed() const {
120 return received_response_completed_
;
122 const net::URLRequestStatus
& status() const { return status_
; }
123 int total_bytes_downloaded() const { return total_bytes_downloaded_
; }
126 controller()->Resume();
129 // ResourceHandler implementation:
130 virtual bool OnUploadProgress(uint64 position
, uint64 size
) OVERRIDE
{
135 virtual bool OnRequestRedirected(const net::RedirectInfo
& redirect_info
,
136 ResourceResponse
* response
,
137 bool* defer
) OVERRIDE
{
142 virtual bool OnResponseStarted(ResourceResponse
* response
,
143 bool* defer
) OVERRIDE
{
144 EXPECT_FALSE(response_
.get());
145 response_
= response
;
149 virtual bool OnWillStart(const GURL
& url
, bool* defer
) OVERRIDE
{
150 EXPECT_TRUE(start_url_
.is_empty());
152 *defer
= defer_request_on_will_start_
;
156 virtual bool OnBeforeNetworkStart(const GURL
& url
, bool* defer
) OVERRIDE
{
160 virtual bool OnWillRead(scoped_refptr
<net::IOBuffer
>* buf
,
162 int min_size
) OVERRIDE
{
163 EXPECT_TRUE(expect_reads_
);
164 EXPECT_FALSE(received_on_will_read_
);
165 EXPECT_FALSE(received_eof_
);
166 EXPECT_FALSE(received_response_completed_
);
169 *buf_size
= kReadBufSize
;
170 received_on_will_read_
= true;
174 virtual bool OnReadCompleted(int bytes_read
, bool* defer
) OVERRIDE
{
175 EXPECT_TRUE(received_on_will_read_
);
176 EXPECT_TRUE(expect_reads_
);
177 EXPECT_FALSE(received_response_completed_
);
179 if (bytes_read
== 0) {
180 received_eof_
= true;
187 // Need another OnWillRead() call before seeing an OnReadCompleted().
188 received_on_will_read_
= false;
190 return !cancel_on_read_completed_
;
193 virtual void OnResponseCompleted(const net::URLRequestStatus
& status
,
194 const std::string
& security_info
,
195 bool* defer
) OVERRIDE
{
196 EXPECT_FALSE(received_response_completed_
);
197 if (status
.is_success() && expect_reads_
)
198 EXPECT_TRUE(received_eof_
);
200 received_response_completed_
= true;
204 virtual void OnDataDownloaded(int bytes_downloaded
) OVERRIDE
{
205 EXPECT_FALSE(expect_reads_
);
206 total_bytes_downloaded_
+= bytes_downloaded
;
210 scoped_refptr
<net::IOBuffer
> read_buffer_
;
212 bool defer_request_on_will_start_
;
214 bool cancel_on_read_completed_
;
218 scoped_refptr
<ResourceResponse
> response_
;
219 bool received_on_will_read_
;
221 bool received_response_completed_
;
222 net::URLRequestStatus status_
;
223 int total_bytes_downloaded_
;
226 // Test browser client that captures calls to SelectClientCertificates and
227 // records the arguments of the most recent call for later inspection.
228 class SelectCertificateBrowserClient
: public TestContentBrowserClient
{
230 SelectCertificateBrowserClient() : call_count_(0) {}
232 virtual void SelectClientCertificate(
233 int render_process_id
,
235 const net::HttpNetworkSession
* network_session
,
236 net::SSLCertRequestInfo
* cert_request_info
,
237 const base::Callback
<void(net::X509Certificate
*)>& callback
) OVERRIDE
{
239 passed_certs_
= cert_request_info
->client_certs
;
246 net::CertificateList
passed_certs() {
247 return passed_certs_
;
251 net::CertificateList passed_certs_
;
255 class ResourceContextStub
: public MockResourceContext
{
257 explicit ResourceContextStub(net::URLRequestContext
* test_request_context
)
258 : MockResourceContext(test_request_context
) {}
260 virtual scoped_ptr
<net::ClientCertStore
> CreateClientCertStore() OVERRIDE
{
261 return dummy_cert_store_
.Pass();
264 void SetClientCertStore(scoped_ptr
<net::ClientCertStore
> store
) {
265 dummy_cert_store_
= store
.Pass();
269 scoped_ptr
<net::ClientCertStore
> dummy_cert_store_
;
272 // Fails to create a temporary file with the given error.
273 void CreateTemporaryError(
274 base::File::Error error
,
275 const CreateTemporaryFileStreamCallback
& callback
) {
276 base::MessageLoop::current()->PostTask(
278 base::Bind(callback
, error
, base::Passed(scoped_ptr
<net::FileStream
>()),
279 scoped_refptr
<ShareableFileReference
>()));
284 class ResourceLoaderTest
: public testing::Test
,
285 public ResourceLoaderDelegate
{
288 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP
),
289 resource_context_(&test_url_request_context_
),
290 raw_ptr_resource_handler_(NULL
),
291 raw_ptr_to_request_(NULL
) {
292 job_factory_
.SetProtocolHandler(
293 "test", net::URLRequestTestJob::CreateProtocolHandler());
294 test_url_request_context_
.set_job_factory(&job_factory_
);
297 GURL
test_url() const {
298 return net::URLRequestTestJob::test_url_1();
301 std::string
test_data() const {
302 return net::URLRequestTestJob::test_data_1();
305 virtual scoped_ptr
<ResourceHandler
> WrapResourceHandler(
306 scoped_ptr
<ResourceHandlerStub
> leaf_handler
,
307 net::URLRequest
* request
) {
308 return leaf_handler
.PassAs
<ResourceHandler
>();
311 virtual void SetUp() OVERRIDE
{
312 const int kRenderProcessId
= 1;
313 const int kRenderViewId
= 2;
315 scoped_ptr
<net::URLRequest
> request(
316 resource_context_
.GetRequestContext()->CreateRequest(
318 net::DEFAULT_PRIORITY
,
320 NULL
/* cookie_store */));
321 raw_ptr_to_request_
= request
.get();
322 ResourceRequestInfo::AllocateForTesting(request
.get(),
323 RESOURCE_TYPE_MAIN_FRAME
,
329 scoped_ptr
<ResourceHandlerStub
> resource_handler(
330 new ResourceHandlerStub(request
.get()));
331 raw_ptr_resource_handler_
= resource_handler
.get();
332 loader_
.reset(new ResourceLoader(
334 WrapResourceHandler(resource_handler
.Pass(), raw_ptr_to_request_
),
338 // ResourceLoaderDelegate:
339 virtual ResourceDispatcherHostLoginDelegate
* CreateLoginDelegate(
340 ResourceLoader
* loader
,
341 net::AuthChallengeInfo
* auth_info
) OVERRIDE
{
344 virtual bool HandleExternalProtocol(ResourceLoader
* loader
,
345 const GURL
& url
) OVERRIDE
{
348 virtual void DidStartRequest(ResourceLoader
* loader
) OVERRIDE
{}
349 virtual void DidReceiveRedirect(ResourceLoader
* loader
,
350 const GURL
& new_url
) OVERRIDE
{}
351 virtual void DidReceiveResponse(ResourceLoader
* loader
) OVERRIDE
{}
352 virtual void DidFinishLoading(ResourceLoader
* loader
) OVERRIDE
{}
354 content::TestBrowserThreadBundle thread_bundle_
;
356 net::URLRequestJobFactoryImpl job_factory_
;
357 net::TestURLRequestContext test_url_request_context_
;
358 ResourceContextStub resource_context_
;
360 // The ResourceLoader owns the URLRequest and the ResourceHandler.
361 ResourceHandlerStub
* raw_ptr_resource_handler_
;
362 net::URLRequest
* raw_ptr_to_request_
;
363 scoped_ptr
<ResourceLoader
> loader_
;
366 // Verifies if a call to net::UrlRequest::Delegate::OnCertificateRequested()
367 // causes client cert store to be queried for certificates and if the returned
368 // certificates are correctly passed to the content browser client for
370 TEST_F(ResourceLoaderTest
, ClientCertStoreLookup
) {
371 // Set up the test client cert store.
372 net::CertificateList
dummy_certs(1, scoped_refptr
<net::X509Certificate
>(
373 new net::X509Certificate("test", "test", base::Time(), base::Time())));
374 scoped_ptr
<ClientCertStoreStub
> test_store(
375 new ClientCertStoreStub(dummy_certs
));
376 EXPECT_EQ(0, test_store
->request_count());
378 // Ownership of the |test_store| is about to be turned over to ResourceLoader.
379 // We need to keep raw pointer copies to access these objects later.
380 ClientCertStoreStub
* raw_ptr_to_store
= test_store
.get();
381 resource_context_
.SetClientCertStore(
382 test_store
.PassAs
<net::ClientCertStore
>());
384 // Prepare a dummy certificate request.
385 scoped_refptr
<net::SSLCertRequestInfo
> cert_request_info(
386 new net::SSLCertRequestInfo());
387 std::vector
<std::string
> dummy_authority(1, "dummy");
388 cert_request_info
->cert_authorities
= dummy_authority
;
390 // Plug in test content browser client.
391 SelectCertificateBrowserClient test_client
;
392 ContentBrowserClient
* old_client
= SetBrowserClientForTesting(&test_client
);
394 // Everything is set up. Trigger the resource loader certificate request event
395 // and run the message loop.
396 loader_
->OnCertificateRequested(raw_ptr_to_request_
, cert_request_info
.get());
397 base::RunLoop().RunUntilIdle();
399 // Restore the original content browser client.
400 SetBrowserClientForTesting(old_client
);
402 // Check if the test store was queried against correct |cert_authorities|.
403 EXPECT_EQ(1, raw_ptr_to_store
->request_count());
404 EXPECT_EQ(dummy_authority
, raw_ptr_to_store
->requested_authorities());
406 // Check if the retrieved certificates were passed to the content browser
408 EXPECT_EQ(1, test_client
.call_count());
409 EXPECT_EQ(dummy_certs
, test_client
.passed_certs());
412 // Verifies if a call to net::URLRequest::Delegate::OnCertificateRequested()
413 // on a platform with a NULL client cert store still calls the content browser
414 // client for selection.
415 TEST_F(ResourceLoaderTest
, ClientCertStoreNull
) {
416 // Prepare a dummy certificate request.
417 scoped_refptr
<net::SSLCertRequestInfo
> cert_request_info(
418 new net::SSLCertRequestInfo());
419 std::vector
<std::string
> dummy_authority(1, "dummy");
420 cert_request_info
->cert_authorities
= dummy_authority
;
422 // Plug in test content browser client.
423 SelectCertificateBrowserClient test_client
;
424 ContentBrowserClient
* old_client
= SetBrowserClientForTesting(&test_client
);
426 // Everything is set up. Trigger the resource loader certificate request event
427 // and run the message loop.
428 loader_
->OnCertificateRequested(raw_ptr_to_request_
, cert_request_info
.get());
429 base::RunLoop().RunUntilIdle();
431 // Restore the original content browser client.
432 SetBrowserClientForTesting(old_client
);
434 // Check if the SelectClientCertificate was called on the content browser
436 EXPECT_EQ(1, test_client
.call_count());
437 EXPECT_EQ(net::CertificateList(), test_client
.passed_certs());
440 TEST_F(ResourceLoaderTest
, ResumeCancelledRequest
) {
441 raw_ptr_resource_handler_
->set_defer_request_on_will_start(true);
443 loader_
->StartRequest();
444 loader_
->CancelRequest(true);
445 static_cast<ResourceController
*>(loader_
.get())->Resume();
448 // Tests that no invariants are broken if a ResourceHandler cancels during
450 TEST_F(ResourceLoaderTest
, CancelOnReadCompleted
) {
451 raw_ptr_resource_handler_
->set_cancel_on_read_completed(true);
453 loader_
->StartRequest();
454 base::RunLoop().RunUntilIdle();
456 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
457 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
458 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
459 raw_ptr_resource_handler_
->status().status());
462 // Tests that no invariants are broken if a ResourceHandler defers EOF.
463 TEST_F(ResourceLoaderTest
, DeferEOF
) {
464 raw_ptr_resource_handler_
->set_defer_eof(true);
466 loader_
->StartRequest();
467 base::RunLoop().RunUntilIdle();
469 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
470 EXPECT_FALSE(raw_ptr_resource_handler_
->received_response_completed());
472 raw_ptr_resource_handler_
->Resume();
473 base::RunLoop().RunUntilIdle();
475 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
476 EXPECT_EQ(net::URLRequestStatus::SUCCESS
,
477 raw_ptr_resource_handler_
->status().status());
480 class ResourceLoaderRedirectToFileTest
: public ResourceLoaderTest
{
482 ResourceLoaderRedirectToFileTest()
483 : file_stream_(NULL
),
484 redirect_to_file_resource_handler_(NULL
) {
487 base::FilePath
temp_path() const { return temp_path_
; }
488 ShareableFileReference
* deletable_file() const {
489 return deletable_file_
.get();
491 net::testing::MockFileStream
* file_stream() const { return file_stream_
; }
492 RedirectToFileResourceHandler
* redirect_to_file_resource_handler() const {
493 return redirect_to_file_resource_handler_
;
496 void ReleaseLoader() {
498 deletable_file_
= NULL
;
502 virtual scoped_ptr
<ResourceHandler
> WrapResourceHandler(
503 scoped_ptr
<ResourceHandlerStub
> leaf_handler
,
504 net::URLRequest
* request
) OVERRIDE
{
505 leaf_handler
->set_expect_reads(false);
507 // Make a temporary file.
508 CHECK(base::CreateTemporaryFile(&temp_path_
));
509 int flags
= base::File::FLAG_WRITE
| base::File::FLAG_TEMPORARY
|
510 base::File::FLAG_CREATE_ALWAYS
| base::File::FLAG_ASYNC
;
511 base::File
file(temp_path_
, flags
);
512 CHECK(file
.IsValid());
514 // Create mock file streams and a ShareableFileReference.
515 scoped_ptr
<net::testing::MockFileStream
> file_stream(
516 new net::testing::MockFileStream(file
.Pass(),
517 base::MessageLoopProxy::current()));
518 file_stream_
= file_stream
.get();
519 deletable_file_
= ShareableFileReference::GetOrCreate(
521 ShareableFileReference::DELETE_ON_FINAL_RELEASE
,
522 BrowserThread::GetMessageLoopProxyForThread(
523 BrowserThread::FILE).get());
525 // Inject them into the handler.
526 scoped_ptr
<RedirectToFileResourceHandler
> handler(
527 new RedirectToFileResourceHandler(
528 leaf_handler
.PassAs
<ResourceHandler
>(), request
));
529 redirect_to_file_resource_handler_
= handler
.get();
530 handler
->SetCreateTemporaryFileStreamFunctionForTesting(
531 base::Bind(&ResourceLoaderRedirectToFileTest::PostCallback
,
532 base::Unretained(this),
533 base::Passed(file_stream
.PassAs
<net::FileStream
>())));
534 return handler
.PassAs
<ResourceHandler
>();
539 scoped_ptr
<net::FileStream
> file_stream
,
540 const CreateTemporaryFileStreamCallback
& callback
) {
541 base::MessageLoop::current()->PostTask(
543 base::Bind(callback
, base::File::FILE_OK
,
544 base::Passed(&file_stream
), deletable_file_
));
547 base::FilePath temp_path_
;
548 scoped_refptr
<ShareableFileReference
> deletable_file_
;
549 // These are owned by the ResourceLoader.
550 net::testing::MockFileStream
* file_stream_
;
551 RedirectToFileResourceHandler
* redirect_to_file_resource_handler_
;
554 // Tests that a RedirectToFileResourceHandler works and forwards everything
556 TEST_F(ResourceLoaderRedirectToFileTest
, Basic
) {
557 // Run it to completion.
558 loader_
->StartRequest();
559 base::RunLoop().RunUntilIdle();
561 // Check that the handler forwarded all information to the downstream handler.
562 EXPECT_EQ(temp_path(),
563 raw_ptr_resource_handler_
->response()->head
.download_file_path
);
564 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
565 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
566 EXPECT_EQ(net::URLRequestStatus::SUCCESS
,
567 raw_ptr_resource_handler_
->status().status());
568 EXPECT_EQ(test_data().size(), static_cast<size_t>(
569 raw_ptr_resource_handler_
->total_bytes_downloaded()));
571 // Check that the data was written to the file.
572 std::string contents
;
573 ASSERT_TRUE(base::ReadFileToString(temp_path(), &contents
));
574 EXPECT_EQ(test_data(), contents
);
576 // Release the loader and the saved reference to file. The file should be gone
579 base::RunLoop().RunUntilIdle();
580 EXPECT_FALSE(base::PathExists(temp_path()));
583 // Tests that RedirectToFileResourceHandler handles errors in creating the
585 TEST_F(ResourceLoaderRedirectToFileTest
, CreateTemporaryError
) {
586 // Swap out the create temporary function.
587 redirect_to_file_resource_handler()->
588 SetCreateTemporaryFileStreamFunctionForTesting(
589 base::Bind(&CreateTemporaryError
, base::File::FILE_ERROR_FAILED
));
591 // Run it to completion.
592 loader_
->StartRequest();
593 base::RunLoop().RunUntilIdle();
595 // To downstream, the request was canceled.
596 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
597 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
598 raw_ptr_resource_handler_
->status().status());
599 EXPECT_EQ(0, raw_ptr_resource_handler_
->total_bytes_downloaded());
602 // Tests that RedirectToFileResourceHandler handles synchronous write errors.
603 TEST_F(ResourceLoaderRedirectToFileTest
, WriteError
) {
604 file_stream()->set_forced_error(net::ERR_FAILED
);
606 // Run it to completion.
607 loader_
->StartRequest();
608 base::RunLoop().RunUntilIdle();
610 // To downstream, the request was canceled sometime after it started, but
611 // before any data was written.
612 EXPECT_EQ(temp_path(),
613 raw_ptr_resource_handler_
->response()->head
.download_file_path
);
614 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
615 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
616 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
617 raw_ptr_resource_handler_
->status().status());
618 EXPECT_EQ(0, raw_ptr_resource_handler_
->total_bytes_downloaded());
620 // Release the loader. The file should be gone now.
622 base::RunLoop().RunUntilIdle();
623 EXPECT_FALSE(base::PathExists(temp_path()));
626 // Tests that RedirectToFileResourceHandler handles asynchronous write errors.
627 TEST_F(ResourceLoaderRedirectToFileTest
, WriteErrorAsync
) {
628 file_stream()->set_forced_error_async(net::ERR_FAILED
);
630 // Run it to completion.
631 loader_
->StartRequest();
632 base::RunLoop().RunUntilIdle();
634 // To downstream, the request was canceled sometime after it started, but
635 // before any data was written.
636 EXPECT_EQ(temp_path(),
637 raw_ptr_resource_handler_
->response()->head
.download_file_path
);
638 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
639 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
640 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
641 raw_ptr_resource_handler_
->status().status());
642 EXPECT_EQ(0, raw_ptr_resource_handler_
->total_bytes_downloaded());
644 // Release the loader. The file should be gone now.
646 base::RunLoop().RunUntilIdle();
647 EXPECT_FALSE(base::PathExists(temp_path()));
650 // Tests that RedirectToFileHandler defers completion if there are outstanding
651 // writes and accounts for errors which occur in that time.
652 TEST_F(ResourceLoaderRedirectToFileTest
, DeferCompletion
) {
653 // Program the MockFileStream to error asynchronously, but throttle the
655 file_stream()->set_forced_error_async(net::ERR_FAILED
);
656 file_stream()->ThrottleCallbacks();
658 // Run it as far as it will go.
659 loader_
->StartRequest();
660 base::RunLoop().RunUntilIdle();
662 // At this point, the request should have completed.
663 EXPECT_EQ(net::URLRequestStatus::SUCCESS
,
664 raw_ptr_to_request_
->status().status());
666 // However, the resource loader stack is stuck somewhere after receiving the
668 EXPECT_EQ(temp_path(),
669 raw_ptr_resource_handler_
->response()->head
.download_file_path
);
670 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
671 EXPECT_FALSE(raw_ptr_resource_handler_
->received_response_completed());
672 EXPECT_EQ(0, raw_ptr_resource_handler_
->total_bytes_downloaded());
674 // Now, release the floodgates.
675 file_stream()->ReleaseCallbacks();
676 base::RunLoop().RunUntilIdle();
678 // Although the URLRequest was successful, the leaf handler sees a failure
679 // because the write never completed.
680 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
681 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
682 raw_ptr_resource_handler_
->status().status());
684 // Release the loader. The file should be gone now.
686 base::RunLoop().RunUntilIdle();
687 EXPECT_FALSE(base::PathExists(temp_path()));
690 // Tests that a RedirectToFileResourceHandler behaves properly when the
691 // downstream handler defers OnWillStart.
692 TEST_F(ResourceLoaderRedirectToFileTest
, DownstreamDeferStart
) {
693 // Defer OnWillStart.
694 raw_ptr_resource_handler_
->set_defer_request_on_will_start(true);
696 // Run as far as we'll go.
697 loader_
->StartRequest();
698 base::RunLoop().RunUntilIdle();
700 // The request should have stopped at OnWillStart.
701 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
702 EXPECT_FALSE(raw_ptr_resource_handler_
->response());
703 EXPECT_FALSE(raw_ptr_resource_handler_
->received_response_completed());
704 EXPECT_EQ(0, raw_ptr_resource_handler_
->total_bytes_downloaded());
706 // Now resume the request. Now we complete.
707 raw_ptr_resource_handler_
->Resume();
708 base::RunLoop().RunUntilIdle();
710 // Check that the handler forwarded all information to the downstream handler.
711 EXPECT_EQ(temp_path(),
712 raw_ptr_resource_handler_
->response()->head
.download_file_path
);
713 EXPECT_EQ(test_url(), raw_ptr_resource_handler_
->start_url());
714 EXPECT_TRUE(raw_ptr_resource_handler_
->received_response_completed());
715 EXPECT_EQ(net::URLRequestStatus::SUCCESS
,
716 raw_ptr_resource_handler_
->status().status());
717 EXPECT_EQ(test_data().size(), static_cast<size_t>(
718 raw_ptr_resource_handler_
->total_bytes_downloaded()));
720 // Check that the data was written to the file.
721 std::string contents
;
722 ASSERT_TRUE(base::ReadFileToString(temp_path(), &contents
));
723 EXPECT_EQ(test_data(), contents
);
725 // Release the loader. The file should be gone now.
727 base::RunLoop().RunUntilIdle();
728 EXPECT_FALSE(base::PathExists(temp_path()));
731 } // namespace content