Home | History | Annotate | Download | only in loader
      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