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/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" 32 33 using webkit_blob::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 GURL& url, 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_); 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 new net::URLRequest(test_url(), 317 net::DEFAULT_PRIORITY, 318 NULL, 319 resource_context_.GetRequestContext())); 320 raw_ptr_to_request_ = request.get(); 321 ResourceRequestInfo::AllocateForTesting(request.get(), 322 ResourceType::MAIN_FRAME, 323 &resource_context_, 324 kRenderProcessId, 325 kRenderViewId, 326 MSG_ROUTING_NONE, 327 false); 328 scoped_ptr<ResourceHandlerStub> resource_handler( 329 new ResourceHandlerStub(request.get())); 330 raw_ptr_resource_handler_ = resource_handler.get(); 331 loader_.reset(new ResourceLoader( 332 request.Pass(), 333 WrapResourceHandler(resource_handler.Pass(), raw_ptr_to_request_), 334 this)); 335 } 336 337 // ResourceLoaderDelegate: 338 virtual ResourceDispatcherHostLoginDelegate* CreateLoginDelegate( 339 ResourceLoader* loader, 340 net::AuthChallengeInfo* auth_info) OVERRIDE { 341 return NULL; 342 } 343 virtual bool HandleExternalProtocol(ResourceLoader* loader, 344 const GURL& url) OVERRIDE { 345 return false; 346 } 347 virtual void DidStartRequest(ResourceLoader* loader) OVERRIDE {} 348 virtual void DidReceiveRedirect(ResourceLoader* loader, 349 const GURL& new_url) OVERRIDE {} 350 virtual void DidReceiveResponse(ResourceLoader* loader) OVERRIDE {} 351 virtual void DidFinishLoading(ResourceLoader* loader) OVERRIDE {} 352 353 content::TestBrowserThreadBundle thread_bundle_; 354 355 net::URLRequestJobFactoryImpl job_factory_; 356 net::TestURLRequestContext test_url_request_context_; 357 ResourceContextStub resource_context_; 358 359 // The ResourceLoader owns the URLRequest and the ResourceHandler. 360 ResourceHandlerStub* raw_ptr_resource_handler_; 361 net::URLRequest* raw_ptr_to_request_; 362 scoped_ptr<ResourceLoader> loader_; 363 }; 364 365 // Verifies if a call to net::UrlRequest::Delegate::OnCertificateRequested() 366 // causes client cert store to be queried for certificates and if the returned 367 // certificates are correctly passed to the content browser client for 368 // selection. 369 TEST_F(ResourceLoaderTest, ClientCertStoreLookup) { 370 // Set up the test client cert store. 371 net::CertificateList dummy_certs(1, scoped_refptr<net::X509Certificate>( 372 new net::X509Certificate("test", "test", base::Time(), base::Time()))); 373 scoped_ptr<ClientCertStoreStub> test_store( 374 new ClientCertStoreStub(dummy_certs)); 375 EXPECT_EQ(0, test_store->request_count()); 376 377 // Ownership of the |test_store| is about to be turned over to ResourceLoader. 378 // We need to keep raw pointer copies to access these objects later. 379 ClientCertStoreStub* raw_ptr_to_store = test_store.get(); 380 resource_context_.SetClientCertStore( 381 test_store.PassAs<net::ClientCertStore>()); 382 383 // Prepare a dummy certificate request. 384 scoped_refptr<net::SSLCertRequestInfo> cert_request_info( 385 new net::SSLCertRequestInfo()); 386 std::vector<std::string> dummy_authority(1, "dummy"); 387 cert_request_info->cert_authorities = dummy_authority; 388 389 // Plug in test content browser client. 390 SelectCertificateBrowserClient test_client; 391 ContentBrowserClient* old_client = SetBrowserClientForTesting(&test_client); 392 393 // Everything is set up. Trigger the resource loader certificate request event 394 // and run the message loop. 395 loader_->OnCertificateRequested(raw_ptr_to_request_, cert_request_info.get()); 396 base::RunLoop().RunUntilIdle(); 397 398 // Restore the original content browser client. 399 SetBrowserClientForTesting(old_client); 400 401 // Check if the test store was queried against correct |cert_authorities|. 402 EXPECT_EQ(1, raw_ptr_to_store->request_count()); 403 EXPECT_EQ(dummy_authority, raw_ptr_to_store->requested_authorities()); 404 405 // Check if the retrieved certificates were passed to the content browser 406 // client. 407 EXPECT_EQ(1, test_client.call_count()); 408 EXPECT_EQ(dummy_certs, test_client.passed_certs()); 409 } 410 411 // Verifies if a call to net::URLRequest::Delegate::OnCertificateRequested() 412 // on a platform with a NULL client cert store still calls the content browser 413 // client for selection. 414 TEST_F(ResourceLoaderTest, ClientCertStoreNull) { 415 // Prepare a dummy certificate request. 416 scoped_refptr<net::SSLCertRequestInfo> cert_request_info( 417 new net::SSLCertRequestInfo()); 418 std::vector<std::string> dummy_authority(1, "dummy"); 419 cert_request_info->cert_authorities = dummy_authority; 420 421 // Plug in test content browser client. 422 SelectCertificateBrowserClient test_client; 423 ContentBrowserClient* old_client = SetBrowserClientForTesting(&test_client); 424 425 // Everything is set up. Trigger the resource loader certificate request event 426 // and run the message loop. 427 loader_->OnCertificateRequested(raw_ptr_to_request_, cert_request_info.get()); 428 base::RunLoop().RunUntilIdle(); 429 430 // Restore the original content browser client. 431 SetBrowserClientForTesting(old_client); 432 433 // Check if the SelectClientCertificate was called on the content browser 434 // client. 435 EXPECT_EQ(1, test_client.call_count()); 436 EXPECT_EQ(net::CertificateList(), test_client.passed_certs()); 437 } 438 439 TEST_F(ResourceLoaderTest, ResumeCancelledRequest) { 440 raw_ptr_resource_handler_->set_defer_request_on_will_start(true); 441 442 loader_->StartRequest(); 443 loader_->CancelRequest(true); 444 static_cast<ResourceController*>(loader_.get())->Resume(); 445 } 446 447 // Tests that no invariants are broken if a ResourceHandler cancels during 448 // OnReadCompleted. 449 TEST_F(ResourceLoaderTest, CancelOnReadCompleted) { 450 raw_ptr_resource_handler_->set_cancel_on_read_completed(true); 451 452 loader_->StartRequest(); 453 base::RunLoop().RunUntilIdle(); 454 455 EXPECT_EQ(test_url(), raw_ptr_resource_handler_->start_url()); 456 EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed()); 457 EXPECT_EQ(net::URLRequestStatus::CANCELED, 458 raw_ptr_resource_handler_->status().status()); 459 } 460 461 // Tests that no invariants are broken if a ResourceHandler defers EOF. 462 TEST_F(ResourceLoaderTest, DeferEOF) { 463 raw_ptr_resource_handler_->set_defer_eof(true); 464 465 loader_->StartRequest(); 466 base::RunLoop().RunUntilIdle(); 467 468 EXPECT_EQ(test_url(), raw_ptr_resource_handler_->start_url()); 469 EXPECT_FALSE(raw_ptr_resource_handler_->received_response_completed()); 470 471 raw_ptr_resource_handler_->Resume(); 472 base::RunLoop().RunUntilIdle(); 473 474 EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed()); 475 EXPECT_EQ(net::URLRequestStatus::SUCCESS, 476 raw_ptr_resource_handler_->status().status()); 477 } 478 479 class ResourceLoaderRedirectToFileTest : public ResourceLoaderTest { 480 public: 481 ResourceLoaderRedirectToFileTest() 482 : file_stream_(NULL), 483 redirect_to_file_resource_handler_(NULL) { 484 } 485 486 base::FilePath temp_path() const { return temp_path_; } 487 ShareableFileReference* deletable_file() const { 488 return deletable_file_.get(); 489 } 490 net::testing::MockFileStream* file_stream() const { return file_stream_; } 491 RedirectToFileResourceHandler* redirect_to_file_resource_handler() const { 492 return redirect_to_file_resource_handler_; 493 } 494 495 void ReleaseLoader() { 496 file_stream_ = NULL; 497 deletable_file_ = NULL; 498 loader_.reset(); 499 } 500 501 virtual scoped_ptr<ResourceHandler> WrapResourceHandler( 502 scoped_ptr<ResourceHandlerStub> leaf_handler, 503 net::URLRequest* request) OVERRIDE { 504 leaf_handler->set_expect_reads(false); 505 506 // Make a temporary file. 507 CHECK(base::CreateTemporaryFile(&temp_path_)); 508 int flags = base::File::FLAG_WRITE | base::File::FLAG_TEMPORARY | 509 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_ASYNC; 510 base::File file(temp_path_, flags); 511 CHECK(file.IsValid()); 512 513 // Create mock file streams and a ShareableFileReference. 514 scoped_ptr<net::testing::MockFileStream> file_stream( 515 new net::testing::MockFileStream(file.Pass(), 516 base::MessageLoopProxy::current())); 517 file_stream_ = file_stream.get(); 518 deletable_file_ = ShareableFileReference::GetOrCreate( 519 temp_path_, 520 ShareableFileReference::DELETE_ON_FINAL_RELEASE, 521 BrowserThread::GetMessageLoopProxyForThread( 522 BrowserThread::FILE).get()); 523 524 // Inject them into the handler. 525 scoped_ptr<RedirectToFileResourceHandler> handler( 526 new RedirectToFileResourceHandler( 527 leaf_handler.PassAs<ResourceHandler>(), request)); 528 redirect_to_file_resource_handler_ = handler.get(); 529 handler->SetCreateTemporaryFileStreamFunctionForTesting( 530 base::Bind(&ResourceLoaderRedirectToFileTest::PostCallback, 531 base::Unretained(this), 532 base::Passed(file_stream.PassAs<net::FileStream>()))); 533 return handler.PassAs<ResourceHandler>(); 534 } 535 536 private: 537 void PostCallback( 538 scoped_ptr<net::FileStream> file_stream, 539 const CreateTemporaryFileStreamCallback& callback) { 540 base::MessageLoop::current()->PostTask( 541 FROM_HERE, 542 base::Bind(callback, base::File::FILE_OK, 543 base::Passed(&file_stream), deletable_file_)); 544 } 545 546 base::FilePath temp_path_; 547 scoped_refptr<ShareableFileReference> deletable_file_; 548 // These are owned by the ResourceLoader. 549 net::testing::MockFileStream* file_stream_; 550 RedirectToFileResourceHandler* redirect_to_file_resource_handler_; 551 }; 552 553 // Tests that a RedirectToFileResourceHandler works and forwards everything 554 // downstream. 555 TEST_F(ResourceLoaderRedirectToFileTest, Basic) { 556 // Run it to completion. 557 loader_->StartRequest(); 558 base::RunLoop().RunUntilIdle(); 559 560 // Check that the handler forwarded all information to the downstream handler. 561 EXPECT_EQ(temp_path(), 562 raw_ptr_resource_handler_->response()->head.download_file_path); 563 EXPECT_EQ(test_url(), raw_ptr_resource_handler_->start_url()); 564 EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed()); 565 EXPECT_EQ(net::URLRequestStatus::SUCCESS, 566 raw_ptr_resource_handler_->status().status()); 567 EXPECT_EQ(test_data().size(), static_cast<size_t>( 568 raw_ptr_resource_handler_->total_bytes_downloaded())); 569 570 // Check that the data was written to the file. 571 std::string contents; 572 ASSERT_TRUE(base::ReadFileToString(temp_path(), &contents)); 573 EXPECT_EQ(test_data(), contents); 574 575 // Release the loader and the saved reference to file. The file should be gone 576 // now. 577 ReleaseLoader(); 578 base::RunLoop().RunUntilIdle(); 579 EXPECT_FALSE(base::PathExists(temp_path())); 580 } 581 582 // Tests that RedirectToFileResourceHandler handles errors in creating the 583 // temporary file. 584 TEST_F(ResourceLoaderRedirectToFileTest, CreateTemporaryError) { 585 // Swap out the create temporary function. 586 redirect_to_file_resource_handler()-> 587 SetCreateTemporaryFileStreamFunctionForTesting( 588 base::Bind(&CreateTemporaryError, base::File::FILE_ERROR_FAILED)); 589 590 // Run it to completion. 591 loader_->StartRequest(); 592 base::RunLoop().RunUntilIdle(); 593 594 // To downstream, the request was canceled. 595 EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed()); 596 EXPECT_EQ(net::URLRequestStatus::CANCELED, 597 raw_ptr_resource_handler_->status().status()); 598 EXPECT_EQ(0, raw_ptr_resource_handler_->total_bytes_downloaded()); 599 } 600 601 // Tests that RedirectToFileResourceHandler handles synchronous write errors. 602 TEST_F(ResourceLoaderRedirectToFileTest, WriteError) { 603 file_stream()->set_forced_error(net::ERR_FAILED); 604 605 // Run it to completion. 606 loader_->StartRequest(); 607 base::RunLoop().RunUntilIdle(); 608 609 // To downstream, the request was canceled sometime after it started, but 610 // before any data was written. 611 EXPECT_EQ(temp_path(), 612 raw_ptr_resource_handler_->response()->head.download_file_path); 613 EXPECT_EQ(test_url(), raw_ptr_resource_handler_->start_url()); 614 EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed()); 615 EXPECT_EQ(net::URLRequestStatus::CANCELED, 616 raw_ptr_resource_handler_->status().status()); 617 EXPECT_EQ(0, raw_ptr_resource_handler_->total_bytes_downloaded()); 618 619 // Release the loader. The file should be gone now. 620 ReleaseLoader(); 621 base::RunLoop().RunUntilIdle(); 622 EXPECT_FALSE(base::PathExists(temp_path())); 623 } 624 625 // Tests that RedirectToFileResourceHandler handles asynchronous write errors. 626 TEST_F(ResourceLoaderRedirectToFileTest, WriteErrorAsync) { 627 file_stream()->set_forced_error_async(net::ERR_FAILED); 628 629 // Run it to completion. 630 loader_->StartRequest(); 631 base::RunLoop().RunUntilIdle(); 632 633 // To downstream, the request was canceled sometime after it started, but 634 // before any data was written. 635 EXPECT_EQ(temp_path(), 636 raw_ptr_resource_handler_->response()->head.download_file_path); 637 EXPECT_EQ(test_url(), raw_ptr_resource_handler_->start_url()); 638 EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed()); 639 EXPECT_EQ(net::URLRequestStatus::CANCELED, 640 raw_ptr_resource_handler_->status().status()); 641 EXPECT_EQ(0, raw_ptr_resource_handler_->total_bytes_downloaded()); 642 643 // Release the loader. The file should be gone now. 644 ReleaseLoader(); 645 base::RunLoop().RunUntilIdle(); 646 EXPECT_FALSE(base::PathExists(temp_path())); 647 } 648 649 // Tests that RedirectToFileHandler defers completion if there are outstanding 650 // writes and accounts for errors which occur in that time. 651 TEST_F(ResourceLoaderRedirectToFileTest, DeferCompletion) { 652 // Program the MockFileStream to error asynchronously, but throttle the 653 // callback. 654 file_stream()->set_forced_error_async(net::ERR_FAILED); 655 file_stream()->ThrottleCallbacks(); 656 657 // Run it as far as it will go. 658 loader_->StartRequest(); 659 base::RunLoop().RunUntilIdle(); 660 661 // At this point, the request should have completed. 662 EXPECT_EQ(net::URLRequestStatus::SUCCESS, 663 raw_ptr_to_request_->status().status()); 664 665 // However, the resource loader stack is stuck somewhere after receiving the 666 // response. 667 EXPECT_EQ(temp_path(), 668 raw_ptr_resource_handler_->response()->head.download_file_path); 669 EXPECT_EQ(test_url(), raw_ptr_resource_handler_->start_url()); 670 EXPECT_FALSE(raw_ptr_resource_handler_->received_response_completed()); 671 EXPECT_EQ(0, raw_ptr_resource_handler_->total_bytes_downloaded()); 672 673 // Now, release the floodgates. 674 file_stream()->ReleaseCallbacks(); 675 base::RunLoop().RunUntilIdle(); 676 677 // Although the URLRequest was successful, the leaf handler sees a failure 678 // because the write never completed. 679 EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed()); 680 EXPECT_EQ(net::URLRequestStatus::CANCELED, 681 raw_ptr_resource_handler_->status().status()); 682 683 // Release the loader. The file should be gone now. 684 ReleaseLoader(); 685 base::RunLoop().RunUntilIdle(); 686 EXPECT_FALSE(base::PathExists(temp_path())); 687 } 688 689 // Tests that a RedirectToFileResourceHandler behaves properly when the 690 // downstream handler defers OnWillStart. 691 TEST_F(ResourceLoaderRedirectToFileTest, DownstreamDeferStart) { 692 // Defer OnWillStart. 693 raw_ptr_resource_handler_->set_defer_request_on_will_start(true); 694 695 // Run as far as we'll go. 696 loader_->StartRequest(); 697 base::RunLoop().RunUntilIdle(); 698 699 // The request should have stopped at OnWillStart. 700 EXPECT_EQ(test_url(), raw_ptr_resource_handler_->start_url()); 701 EXPECT_FALSE(raw_ptr_resource_handler_->response()); 702 EXPECT_FALSE(raw_ptr_resource_handler_->received_response_completed()); 703 EXPECT_EQ(0, raw_ptr_resource_handler_->total_bytes_downloaded()); 704 705 // Now resume the request. Now we complete. 706 raw_ptr_resource_handler_->Resume(); 707 base::RunLoop().RunUntilIdle(); 708 709 // Check that the handler forwarded all information to the downstream handler. 710 EXPECT_EQ(temp_path(), 711 raw_ptr_resource_handler_->response()->head.download_file_path); 712 EXPECT_EQ(test_url(), raw_ptr_resource_handler_->start_url()); 713 EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed()); 714 EXPECT_EQ(net::URLRequestStatus::SUCCESS, 715 raw_ptr_resource_handler_->status().status()); 716 EXPECT_EQ(test_data().size(), static_cast<size_t>( 717 raw_ptr_resource_handler_->total_bytes_downloaded())); 718 719 // Check that the data was written to the file. 720 std::string contents; 721 ASSERT_TRUE(base::ReadFileToString(temp_path(), &contents)); 722 EXPECT_EQ(test_data(), contents); 723 724 // Release the loader. The file should be gone now. 725 ReleaseLoader(); 726 base::RunLoop().RunUntilIdle(); 727 EXPECT_FALSE(base::PathExists(temp_path())); 728 } 729 730 } // namespace content 731