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.
4
5 #include "content/browser/loader/resource_loader.h"
6
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/common/blob/shareable_file_reference.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32
33 using storage::ShareableFileReference;
34
35 namespace content {
36 namespace {
37
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
40 // inspection.
41 class ClientCertStoreStub : public net::ClientCertStore {
42 public:
ClientCertStoreStub(const net::CertificateList & certs)43 ClientCertStoreStub(const net::CertificateList& certs)
44 : response_(certs),
45 request_count_(0) {}
46
~ClientCertStoreStub()47 virtual ~ClientCertStoreStub() {}
48
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).
requested_authorities()55 std::vector<std::string> requested_authorities() {
56 return requested_authorities_;
57 }
58
59 // Returns the number of calls to GetClientCerts().
request_count()60 int request_count() {
61 return request_count_;
62 }
63
64 // net::ClientCertStore:
GetClientCerts(const net::SSLCertRequestInfo & cert_request_info,net::CertificateList * selected_certs,const base::Closure & callback)65 virtual void GetClientCerts(const net::SSLCertRequestInfo& cert_request_info,
66 net::CertificateList* selected_certs,
67 const base::Closure& callback) OVERRIDE {
68 ++request_count_;
69 requested_authorities_ = cert_request_info.cert_authorities;
70 *selected_certs = response_;
71 callback.Run();
72 }
73
74 private:
75 const net::CertificateList response_;
76 int request_count_;
77 std::vector<std::string> requested_authorities_;
78 };
79
80 // Arbitrary read buffer size.
81 const int kReadBufSize = 1024;
82
83 // Dummy implementation of ResourceHandler, instance of which is needed to
84 // initialize ResourceLoader.
85 class ResourceHandlerStub : public ResourceHandler {
86 public:
ResourceHandlerStub(net::URLRequest * request)87 explicit ResourceHandlerStub(net::URLRequest* request)
88 : ResourceHandler(request),
89 read_buffer_(new net::IOBuffer(kReadBufSize)),
90 defer_request_on_will_start_(false),
91 expect_reads_(true),
92 cancel_on_read_completed_(false),
93 defer_eof_(false),
94 received_on_will_read_(false),
95 received_eof_(false),
96 received_response_completed_(false),
97 total_bytes_downloaded_(0) {
98 }
99
100 // If true, defers the resource load in OnWillStart.
set_defer_request_on_will_start(bool defer_request_on_will_start)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;
103 }
104
105 // If true, expect OnWillRead / OnReadCompleted pairs for handling
106 // data. Otherwise, expect OnDataDownloaded.
set_expect_reads(bool expect_reads)107 void set_expect_reads(bool expect_reads) { expect_reads_ = expect_reads; }
108
109 // If true, cancel the request in OnReadCompleted by returning false.
set_cancel_on_read_completed(bool cancel_on_read_completed)110 void set_cancel_on_read_completed(bool cancel_on_read_completed) {
111 cancel_on_read_completed_ = cancel_on_read_completed;
112 }
113
114 // If true, cancel the request in OnReadCompleted by returning false.
set_defer_eof(bool defer_eof)115 void set_defer_eof(bool defer_eof) { defer_eof_ = defer_eof; }
116
start_url() const117 const GURL& start_url() const { return start_url_; }
response() const118 ResourceResponse* response() const { return response_.get(); }
received_response_completed() const119 bool received_response_completed() const {
120 return received_response_completed_;
121 }
status() const122 const net::URLRequestStatus& status() const { return status_; }
total_bytes_downloaded() const123 int total_bytes_downloaded() const { return total_bytes_downloaded_; }
124
Resume()125 void Resume() {
126 controller()->Resume();
127 }
128
129 // ResourceHandler implementation:
OnUploadProgress(uint64 position,uint64 size)130 virtual bool OnUploadProgress(uint64 position, uint64 size) OVERRIDE {
131 NOTREACHED();
132 return true;
133 }
134
OnRequestRedirected(const net::RedirectInfo & redirect_info,ResourceResponse * response,bool * defer)135 virtual bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
136 ResourceResponse* response,
137 bool* defer) OVERRIDE {
138 NOTREACHED();
139 return true;
140 }
141
OnResponseStarted(ResourceResponse * response,bool * defer)142 virtual bool OnResponseStarted(ResourceResponse* response,
143 bool* defer) OVERRIDE {
144 EXPECT_FALSE(response_.get());
145 response_ = response;
146 return true;
147 }
148
OnWillStart(const GURL & url,bool * defer)149 virtual bool OnWillStart(const GURL& url, bool* defer) OVERRIDE {
150 EXPECT_TRUE(start_url_.is_empty());
151 start_url_ = url;
152 *defer = defer_request_on_will_start_;
153 return true;
154 }
155
OnBeforeNetworkStart(const GURL & url,bool * defer)156 virtual bool OnBeforeNetworkStart(const GURL& url, bool* defer) OVERRIDE {
157 return true;
158 }
159
OnWillRead(scoped_refptr<net::IOBuffer> * buf,int * buf_size,int min_size)160 virtual bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
161 int* buf_size,
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_);
167
168 *buf = read_buffer_;
169 *buf_size = kReadBufSize;
170 received_on_will_read_ = true;
171 return true;
172 }
173
OnReadCompleted(int bytes_read,bool * defer)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_);
178
179 if (bytes_read == 0) {
180 received_eof_ = true;
181 if (defer_eof_) {
182 defer_eof_ = false;
183 *defer = true;
184 }
185 }
186
187 // Need another OnWillRead() call before seeing an OnReadCompleted().
188 received_on_will_read_ = false;
189
190 return !cancel_on_read_completed_;
191 }
192
OnResponseCompleted(const net::URLRequestStatus & status,const std::string & security_info,bool * defer)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_);
199
200 received_response_completed_ = true;
201 status_ = status;
202 }
203
OnDataDownloaded(int bytes_downloaded)204 virtual void OnDataDownloaded(int bytes_downloaded) OVERRIDE {
205 EXPECT_FALSE(expect_reads_);
206 total_bytes_downloaded_ += bytes_downloaded;
207 }
208
209 private:
210 scoped_refptr<net::IOBuffer> read_buffer_;
211
212 bool defer_request_on_will_start_;
213 bool expect_reads_;
214 bool cancel_on_read_completed_;
215 bool defer_eof_;
216
217 GURL start_url_;
218 scoped_refptr<ResourceResponse> response_;
219 bool received_on_will_read_;
220 bool received_eof_;
221 bool received_response_completed_;
222 net::URLRequestStatus status_;
223 int total_bytes_downloaded_;
224 };
225
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 {
229 public:
SelectCertificateBrowserClient()230 SelectCertificateBrowserClient() : call_count_(0) {}
231
SelectClientCertificate(int render_process_id,int render_view_id,const net::HttpNetworkSession * network_session,net::SSLCertRequestInfo * cert_request_info,const base::Callback<void (net::X509Certificate *)> & callback)232 virtual void SelectClientCertificate(
233 int render_process_id,
234 int render_view_id,
235 const net::HttpNetworkSession* network_session,
236 net::SSLCertRequestInfo* cert_request_info,
237 const base::Callback<void(net::X509Certificate*)>& callback) OVERRIDE {
238 ++call_count_;
239 passed_certs_ = cert_request_info->client_certs;
240 }
241
call_count()242 int call_count() {
243 return call_count_;
244 }
245
passed_certs()246 net::CertificateList passed_certs() {
247 return passed_certs_;
248 }
249
250 private:
251 net::CertificateList passed_certs_;
252 int call_count_;
253 };
254
255 class ResourceContextStub : public MockResourceContext {
256 public:
ResourceContextStub(net::URLRequestContext * test_request_context)257 explicit ResourceContextStub(net::URLRequestContext* test_request_context)
258 : MockResourceContext(test_request_context) {}
259
CreateClientCertStore()260 virtual scoped_ptr<net::ClientCertStore> CreateClientCertStore() OVERRIDE {
261 return dummy_cert_store_.Pass();
262 }
263
SetClientCertStore(scoped_ptr<net::ClientCertStore> store)264 void SetClientCertStore(scoped_ptr<net::ClientCertStore> store) {
265 dummy_cert_store_ = store.Pass();
266 }
267
268 private:
269 scoped_ptr<net::ClientCertStore> dummy_cert_store_;
270 };
271
272 // Fails to create a temporary file with the given error.
CreateTemporaryError(base::File::Error error,const CreateTemporaryFileStreamCallback & callback)273 void CreateTemporaryError(
274 base::File::Error error,
275 const CreateTemporaryFileStreamCallback& callback) {
276 base::MessageLoop::current()->PostTask(
277 FROM_HERE,
278 base::Bind(callback, error, base::Passed(scoped_ptr<net::FileStream>()),
279 scoped_refptr<ShareableFileReference>()));
280 }
281
282 } // namespace
283
284 class ResourceLoaderTest : public testing::Test,
285 public ResourceLoaderDelegate {
286 protected:
ResourceLoaderTest()287 ResourceLoaderTest()
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_);
295 }
296
test_url() const297 GURL test_url() const {
298 return net::URLRequestTestJob::test_url_1();
299 }
300
test_data() const301 std::string test_data() const {
302 return net::URLRequestTestJob::test_data_1();
303 }
304
WrapResourceHandler(scoped_ptr<ResourceHandlerStub> leaf_handler,net::URLRequest * request)305 virtual scoped_ptr<ResourceHandler> WrapResourceHandler(
306 scoped_ptr<ResourceHandlerStub> leaf_handler,
307 net::URLRequest* request) {
308 return leaf_handler.PassAs<ResourceHandler>();
309 }
310
SetUp()311 virtual void SetUp() OVERRIDE {
312 const int kRenderProcessId = 1;
313 const int kRenderViewId = 2;
314
315 scoped_ptr<net::URLRequest> request(
316 resource_context_.GetRequestContext()->CreateRequest(
317 test_url(),
318 net::DEFAULT_PRIORITY,
319 NULL /* delegate */,
320 NULL /* cookie_store */));
321 raw_ptr_to_request_ = request.get();
322 ResourceRequestInfo::AllocateForTesting(request.get(),
323 RESOURCE_TYPE_MAIN_FRAME,
324 &resource_context_,
325 kRenderProcessId,
326 kRenderViewId,
327 MSG_ROUTING_NONE,
328 false);
329 scoped_ptr<ResourceHandlerStub> resource_handler(
330 new ResourceHandlerStub(request.get()));
331 raw_ptr_resource_handler_ = resource_handler.get();
332 loader_.reset(new ResourceLoader(
333 request.Pass(),
334 WrapResourceHandler(resource_handler.Pass(), raw_ptr_to_request_),
335 this));
336 }
337
338 // ResourceLoaderDelegate:
CreateLoginDelegate(ResourceLoader * loader,net::AuthChallengeInfo * auth_info)339 virtual ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
340 ResourceLoader* loader,
341 net::AuthChallengeInfo* auth_info) OVERRIDE {
342 return NULL;
343 }
HandleExternalProtocol(ResourceLoader * loader,const GURL & url)344 virtual bool HandleExternalProtocol(ResourceLoader* loader,
345 const GURL& url) OVERRIDE {
346 return false;
347 }
DidStartRequest(ResourceLoader * loader)348 virtual void DidStartRequest(ResourceLoader* loader) OVERRIDE {}
DidReceiveRedirect(ResourceLoader * loader,const GURL & new_url)349 virtual void DidReceiveRedirect(ResourceLoader* loader,
350 const GURL& new_url) OVERRIDE {}
DidReceiveResponse(ResourceLoader * loader)351 virtual void DidReceiveResponse(ResourceLoader* loader) OVERRIDE {}
DidFinishLoading(ResourceLoader * loader)352 virtual void DidFinishLoading(ResourceLoader* loader) OVERRIDE {}
353
354 content::TestBrowserThreadBundle thread_bundle_;
355
356 net::URLRequestJobFactoryImpl job_factory_;
357 net::TestURLRequestContext test_url_request_context_;
358 ResourceContextStub resource_context_;
359
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_;
364 };
365
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
369 // selection.
TEST_F(ResourceLoaderTest,ClientCertStoreLookup)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());
377
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>());
383
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;
389
390 // Plug in test content browser client.
391 SelectCertificateBrowserClient test_client;
392 ContentBrowserClient* old_client = SetBrowserClientForTesting(&test_client);
393
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();
398
399 // Restore the original content browser client.
400 SetBrowserClientForTesting(old_client);
401
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());
405
406 // Check if the retrieved certificates were passed to the content browser
407 // client.
408 EXPECT_EQ(1, test_client.call_count());
409 EXPECT_EQ(dummy_certs, test_client.passed_certs());
410 }
411
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.
TEST_F(ResourceLoaderTest,ClientCertStoreNull)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;
421
422 // Plug in test content browser client.
423 SelectCertificateBrowserClient test_client;
424 ContentBrowserClient* old_client = SetBrowserClientForTesting(&test_client);
425
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();
430
431 // Restore the original content browser client.
432 SetBrowserClientForTesting(old_client);
433
434 // Check if the SelectClientCertificate was called on the content browser
435 // client.
436 EXPECT_EQ(1, test_client.call_count());
437 EXPECT_EQ(net::CertificateList(), test_client.passed_certs());
438 }
439
TEST_F(ResourceLoaderTest,ResumeCancelledRequest)440 TEST_F(ResourceLoaderTest, ResumeCancelledRequest) {
441 raw_ptr_resource_handler_->set_defer_request_on_will_start(true);
442
443 loader_->StartRequest();
444 loader_->CancelRequest(true);
445 static_cast<ResourceController*>(loader_.get())->Resume();
446 }
447
448 // Tests that no invariants are broken if a ResourceHandler cancels during
449 // OnReadCompleted.
TEST_F(ResourceLoaderTest,CancelOnReadCompleted)450 TEST_F(ResourceLoaderTest, CancelOnReadCompleted) {
451 raw_ptr_resource_handler_->set_cancel_on_read_completed(true);
452
453 loader_->StartRequest();
454 base::RunLoop().RunUntilIdle();
455
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());
460 }
461
462 // Tests that no invariants are broken if a ResourceHandler defers EOF.
TEST_F(ResourceLoaderTest,DeferEOF)463 TEST_F(ResourceLoaderTest, DeferEOF) {
464 raw_ptr_resource_handler_->set_defer_eof(true);
465
466 loader_->StartRequest();
467 base::RunLoop().RunUntilIdle();
468
469 EXPECT_EQ(test_url(), raw_ptr_resource_handler_->start_url());
470 EXPECT_FALSE(raw_ptr_resource_handler_->received_response_completed());
471
472 raw_ptr_resource_handler_->Resume();
473 base::RunLoop().RunUntilIdle();
474
475 EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed());
476 EXPECT_EQ(net::URLRequestStatus::SUCCESS,
477 raw_ptr_resource_handler_->status().status());
478 }
479
480 class ResourceLoaderRedirectToFileTest : public ResourceLoaderTest {
481 public:
ResourceLoaderRedirectToFileTest()482 ResourceLoaderRedirectToFileTest()
483 : file_stream_(NULL),
484 redirect_to_file_resource_handler_(NULL) {
485 }
486
temp_path() const487 base::FilePath temp_path() const { return temp_path_; }
deletable_file() const488 ShareableFileReference* deletable_file() const {
489 return deletable_file_.get();
490 }
file_stream() const491 net::testing::MockFileStream* file_stream() const { return file_stream_; }
redirect_to_file_resource_handler() const492 RedirectToFileResourceHandler* redirect_to_file_resource_handler() const {
493 return redirect_to_file_resource_handler_;
494 }
495
ReleaseLoader()496 void ReleaseLoader() {
497 file_stream_ = NULL;
498 deletable_file_ = NULL;
499 loader_.reset();
500 }
501
WrapResourceHandler(scoped_ptr<ResourceHandlerStub> leaf_handler,net::URLRequest * request)502 virtual scoped_ptr<ResourceHandler> WrapResourceHandler(
503 scoped_ptr<ResourceHandlerStub> leaf_handler,
504 net::URLRequest* request) OVERRIDE {
505 leaf_handler->set_expect_reads(false);
506
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());
513
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(
520 temp_path_,
521 ShareableFileReference::DELETE_ON_FINAL_RELEASE,
522 BrowserThread::GetMessageLoopProxyForThread(
523 BrowserThread::FILE).get());
524
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>();
535 }
536
537 private:
PostCallback(scoped_ptr<net::FileStream> file_stream,const CreateTemporaryFileStreamCallback & callback)538 void PostCallback(
539 scoped_ptr<net::FileStream> file_stream,
540 const CreateTemporaryFileStreamCallback& callback) {
541 base::MessageLoop::current()->PostTask(
542 FROM_HERE,
543 base::Bind(callback, base::File::FILE_OK,
544 base::Passed(&file_stream), deletable_file_));
545 }
546
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_;
552 };
553
554 // Tests that a RedirectToFileResourceHandler works and forwards everything
555 // downstream.
TEST_F(ResourceLoaderRedirectToFileTest,Basic)556 TEST_F(ResourceLoaderRedirectToFileTest, Basic) {
557 // Run it to completion.
558 loader_->StartRequest();
559 base::RunLoop().RunUntilIdle();
560
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()));
570
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);
575
576 // Release the loader and the saved reference to file. The file should be gone
577 // now.
578 ReleaseLoader();
579 base::RunLoop().RunUntilIdle();
580 EXPECT_FALSE(base::PathExists(temp_path()));
581 }
582
583 // Tests that RedirectToFileResourceHandler handles errors in creating the
584 // temporary file.
TEST_F(ResourceLoaderRedirectToFileTest,CreateTemporaryError)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));
590
591 // Run it to completion.
592 loader_->StartRequest();
593 base::RunLoop().RunUntilIdle();
594
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());
600 }
601
602 // Tests that RedirectToFileResourceHandler handles synchronous write errors.
TEST_F(ResourceLoaderRedirectToFileTest,WriteError)603 TEST_F(ResourceLoaderRedirectToFileTest, WriteError) {
604 file_stream()->set_forced_error(net::ERR_FAILED);
605
606 // Run it to completion.
607 loader_->StartRequest();
608 base::RunLoop().RunUntilIdle();
609
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());
619
620 // Release the loader. The file should be gone now.
621 ReleaseLoader();
622 base::RunLoop().RunUntilIdle();
623 EXPECT_FALSE(base::PathExists(temp_path()));
624 }
625
626 // Tests that RedirectToFileResourceHandler handles asynchronous write errors.
TEST_F(ResourceLoaderRedirectToFileTest,WriteErrorAsync)627 TEST_F(ResourceLoaderRedirectToFileTest, WriteErrorAsync) {
628 file_stream()->set_forced_error_async(net::ERR_FAILED);
629
630 // Run it to completion.
631 loader_->StartRequest();
632 base::RunLoop().RunUntilIdle();
633
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());
643
644 // Release the loader. The file should be gone now.
645 ReleaseLoader();
646 base::RunLoop().RunUntilIdle();
647 EXPECT_FALSE(base::PathExists(temp_path()));
648 }
649
650 // Tests that RedirectToFileHandler defers completion if there are outstanding
651 // writes and accounts for errors which occur in that time.
TEST_F(ResourceLoaderRedirectToFileTest,DeferCompletion)652 TEST_F(ResourceLoaderRedirectToFileTest, DeferCompletion) {
653 // Program the MockFileStream to error asynchronously, but throttle the
654 // callback.
655 file_stream()->set_forced_error_async(net::ERR_FAILED);
656 file_stream()->ThrottleCallbacks();
657
658 // Run it as far as it will go.
659 loader_->StartRequest();
660 base::RunLoop().RunUntilIdle();
661
662 // At this point, the request should have completed.
663 EXPECT_EQ(net::URLRequestStatus::SUCCESS,
664 raw_ptr_to_request_->status().status());
665
666 // However, the resource loader stack is stuck somewhere after receiving the
667 // response.
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());
673
674 // Now, release the floodgates.
675 file_stream()->ReleaseCallbacks();
676 base::RunLoop().RunUntilIdle();
677
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());
683
684 // Release the loader. The file should be gone now.
685 ReleaseLoader();
686 base::RunLoop().RunUntilIdle();
687 EXPECT_FALSE(base::PathExists(temp_path()));
688 }
689
690 // Tests that a RedirectToFileResourceHandler behaves properly when the
691 // downstream handler defers OnWillStart.
TEST_F(ResourceLoaderRedirectToFileTest,DownstreamDeferStart)692 TEST_F(ResourceLoaderRedirectToFileTest, DownstreamDeferStart) {
693 // Defer OnWillStart.
694 raw_ptr_resource_handler_->set_defer_request_on_will_start(true);
695
696 // Run as far as we'll go.
697 loader_->StartRequest();
698 base::RunLoop().RunUntilIdle();
699
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());
705
706 // Now resume the request. Now we complete.
707 raw_ptr_resource_handler_->Resume();
708 base::RunLoop().RunUntilIdle();
709
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()));
719
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);
724
725 // Release the loader. The file should be gone now.
726 ReleaseLoader();
727 base::RunLoop().RunUntilIdle();
728 EXPECT_FALSE(base::PathExists(temp_path()));
729 }
730
731 } // namespace content
732