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: 43 ClientCertStoreStub(const net::CertificateList& certs) 44 : response_(certs), 45 request_count_(0) {} 46 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). 55 std::vector<std::string> requested_authorities() { 56 return requested_authorities_; 57 } 58 59 // Returns the number of calls to GetClientCerts(). 60 int request_count() { 61 return request_count_; 62 } 63 64 // net::ClientCertStore: 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: 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. 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. 107 void set_expect_reads(bool expect_reads) { expect_reads_ = expect_reads; } 108 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; 112 } 113 114 // If true, cancel the request in OnReadCompleted by returning false. 115 void set_defer_eof(bool defer_eof) { defer_eof_ = defer_eof; } 116 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_; 121 } 122 const net::URLRequestStatus& status() const { return status_; } 123 int total_bytes_downloaded() const { return total_bytes_downloaded_; } 124 125 void Resume() { 126 controller()->Resume(); 127 } 128 129 // ResourceHandler implementation: 130 virtual bool OnUploadProgress(uint64 position, uint64 size) OVERRIDE { 131 NOTREACHED(); 132 return true; 133 } 134 135 virtual bool OnRequestRedirected(const net::RedirectInfo& redirect_info, 136 ResourceResponse* response, 137 bool* defer) OVERRIDE { 138 NOTREACHED(); 139 return true; 140 } 141 142 virtual bool OnResponseStarted(ResourceResponse* response, 143 bool* defer) OVERRIDE { 144 EXPECT_FALSE(response_.get()); 145 response_ = response; 146 return true; 147 } 148 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 156 virtual bool OnBeforeNetworkStart(const GURL& url, bool* defer) OVERRIDE { 157 return true; 158 } 159 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 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 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 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: 230 SelectCertificateBrowserClient() : call_count_(0) {} 231 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 242 int call_count() { 243 return call_count_; 244 } 245 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: 257 explicit ResourceContextStub(net::URLRequestContext* test_request_context) 258 : MockResourceContext(test_request_context) {} 259 260 virtual scoped_ptr<net::ClientCertStore> CreateClientCertStore() OVERRIDE { 261 return dummy_cert_store_.Pass(); 262 } 263 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. 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: 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 297 GURL test_url() const { 298 return net::URLRequestTestJob::test_url_1(); 299 } 300 301 std::string test_data() const { 302 return net::URLRequestTestJob::test_data_1(); 303 } 304 305 virtual scoped_ptr<ResourceHandler> WrapResourceHandler( 306 scoped_ptr<ResourceHandlerStub> leaf_handler, 307 net::URLRequest* request) { 308 return leaf_handler.PassAs<ResourceHandler>(); 309 } 310 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: 339 virtual ResourceDispatcherHostLoginDelegate* CreateLoginDelegate( 340 ResourceLoader* loader, 341 net::AuthChallengeInfo* auth_info) OVERRIDE { 342 return NULL; 343 } 344 virtual bool HandleExternalProtocol(ResourceLoader* loader, 345 const GURL& url) OVERRIDE { 346 return false; 347 } 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 {} 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. 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. 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 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. 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. 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: 482 ResourceLoaderRedirectToFileTest() 483 : file_stream_(NULL), 484 redirect_to_file_resource_handler_(NULL) { 485 } 486 487 base::FilePath temp_path() const { return temp_path_; } 488 ShareableFileReference* deletable_file() const { 489 return deletable_file_.get(); 490 } 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_; 494 } 495 496 void ReleaseLoader() { 497 file_stream_ = NULL; 498 deletable_file_ = NULL; 499 loader_.reset(); 500 } 501 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: 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. 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. 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. 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. 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. 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. 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