Home | History | Annotate | Download | only in loader
      1 // Copyright 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/detachable_resource_handler.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/time/time.h"
      9 #include "content/browser/loader/resource_request_info_impl.h"
     10 #include "net/base/io_buffer.h"
     11 #include "net/base/net_errors.h"
     12 #include "net/url_request/url_request.h"
     13 #include "net/url_request/url_request_status.h"
     14 
     15 namespace {
     16 // This matches the maximum allocation size of AsyncResourceHandler.
     17 const int kReadBufSize = 32 * 1024;
     18 }
     19 
     20 namespace content {
     21 
     22 DetachableResourceHandler::DetachableResourceHandler(
     23     net::URLRequest* request,
     24     base::TimeDelta cancel_delay,
     25     scoped_ptr<ResourceHandler> next_handler)
     26     : ResourceHandler(request),
     27       next_handler_(next_handler.Pass()),
     28       cancel_delay_(cancel_delay),
     29       is_deferred_(false),
     30       is_finished_(false) {
     31   GetRequestInfo()->set_detachable_handler(this);
     32 }
     33 
     34 DetachableResourceHandler::~DetachableResourceHandler() {
     35   // Cleanup back-pointer stored on the request info.
     36   GetRequestInfo()->set_detachable_handler(NULL);
     37 }
     38 
     39 void DetachableResourceHandler::Detach() {
     40   if (is_detached())
     41     return;
     42 
     43   if (!is_finished_) {
     44     // Simulate a cancel on the next handler before destroying it.
     45     net::URLRequestStatus status(net::URLRequestStatus::CANCELED,
     46                                  net::ERR_ABORTED);
     47     bool defer_ignored = false;
     48     next_handler_->OnResponseCompleted(status, std::string(), &defer_ignored);
     49     DCHECK(!defer_ignored);
     50     // If |next_handler_| were to defer its shutdown in OnResponseCompleted,
     51     // this would destroy it anyway. Fortunately, AsyncResourceHandler never
     52     // does this anyway, so DCHECK it. BufferedResourceHandler and RVH shutdown
     53     // already ignore deferred ResourceHandler shutdown, but
     54     // DetachableResourceHandler and the detach-on-renderer-cancel logic
     55     // introduces a case where this occurs when the renderer cancels a resource.
     56   }
     57   // A OnWillRead / OnReadCompleted pair may still be in progress, but
     58   // OnWillRead passes back a scoped_refptr, so downstream handler's buffer will
     59   // survive long enough to complete that read. From there, future reads will
     60   // drain into |read_buffer_|. (If |next_handler_| is an AsyncResourceHandler,
     61   // the net::IOBuffer takes a reference to the ResourceBuffer which owns the
     62   // shared memory.)
     63   next_handler_.reset();
     64 
     65   // Time the request out if it takes too long.
     66   detached_timer_.reset(new base::OneShotTimer<DetachableResourceHandler>());
     67   detached_timer_->Start(
     68       FROM_HERE, cancel_delay_, this, &DetachableResourceHandler::Cancel);
     69 
     70   // Resume if necessary. The request may have been deferred, say, waiting on a
     71   // full buffer in AsyncResourceHandler. Now that it has been detached, resume
     72   // and drain it.
     73   if (is_deferred_) {
     74     // The nested ResourceHandler may have logged that it's blocking the
     75     // request.  Log it as no longer doing so, to avoid a DCHECK on resume.
     76     request()->LogUnblocked();
     77     Resume();
     78   }
     79 }
     80 
     81 void DetachableResourceHandler::SetController(ResourceController* controller) {
     82   ResourceHandler::SetController(controller);
     83 
     84   // Intercept the ResourceController for downstream handlers to keep track of
     85   // whether the request is deferred.
     86   if (next_handler_)
     87     next_handler_->SetController(this);
     88 }
     89 
     90 bool DetachableResourceHandler::OnUploadProgress(uint64 position, uint64 size) {
     91   if (!next_handler_)
     92     return true;
     93 
     94   return next_handler_->OnUploadProgress(position, size);
     95 }
     96 
     97 bool DetachableResourceHandler::OnRequestRedirected(
     98     const net::RedirectInfo& redirect_info,
     99     ResourceResponse* response,
    100     bool* defer) {
    101   DCHECK(!is_deferred_);
    102 
    103   if (!next_handler_)
    104     return true;
    105 
    106   bool ret = next_handler_->OnRequestRedirected(
    107       redirect_info, response, &is_deferred_);
    108   *defer = is_deferred_;
    109   return ret;
    110 }
    111 
    112 bool DetachableResourceHandler::OnResponseStarted(ResourceResponse* response,
    113                                                   bool* defer) {
    114   DCHECK(!is_deferred_);
    115 
    116   if (!next_handler_)
    117     return true;
    118 
    119   bool ret =
    120       next_handler_->OnResponseStarted(response, &is_deferred_);
    121   *defer = is_deferred_;
    122   return ret;
    123 }
    124 
    125 bool DetachableResourceHandler::OnWillStart(const GURL& url, bool* defer) {
    126   DCHECK(!is_deferred_);
    127 
    128   if (!next_handler_)
    129     return true;
    130 
    131   bool ret = next_handler_->OnWillStart(url, &is_deferred_);
    132   *defer = is_deferred_;
    133   return ret;
    134 }
    135 
    136 bool DetachableResourceHandler::OnBeforeNetworkStart(const GURL& url,
    137                                                      bool* defer) {
    138   DCHECK(!is_deferred_);
    139 
    140   if (!next_handler_)
    141     return true;
    142 
    143   bool ret =
    144       next_handler_->OnBeforeNetworkStart(url, &is_deferred_);
    145   *defer = is_deferred_;
    146   return ret;
    147 }
    148 
    149 bool DetachableResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf,
    150                                            int* buf_size,
    151                                            int min_size) {
    152   if (!next_handler_) {
    153     DCHECK_EQ(-1, min_size);
    154     if (!read_buffer_.get())
    155       read_buffer_ = new net::IOBuffer(kReadBufSize);
    156     *buf = read_buffer_;
    157     *buf_size = kReadBufSize;
    158     return true;
    159   }
    160 
    161   return next_handler_->OnWillRead(buf, buf_size, min_size);
    162 }
    163 
    164 bool DetachableResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
    165   DCHECK(!is_deferred_);
    166 
    167   if (!next_handler_)
    168     return true;
    169 
    170   bool ret =
    171       next_handler_->OnReadCompleted(bytes_read, &is_deferred_);
    172   *defer = is_deferred_;
    173   return ret;
    174 }
    175 
    176 void DetachableResourceHandler::OnResponseCompleted(
    177     const net::URLRequestStatus& status,
    178     const std::string& security_info,
    179     bool* defer) {
    180   // No DCHECK(!is_deferred_) as the request may have been cancelled while
    181   // deferred.
    182 
    183   if (!next_handler_)
    184     return;
    185 
    186   is_finished_ = true;
    187 
    188   next_handler_->OnResponseCompleted(status, security_info, &is_deferred_);
    189   *defer = is_deferred_;
    190 }
    191 
    192 void DetachableResourceHandler::OnDataDownloaded(int bytes_downloaded) {
    193   if (!next_handler_)
    194     return;
    195 
    196   next_handler_->OnDataDownloaded(bytes_downloaded);
    197 }
    198 
    199 void DetachableResourceHandler::Resume() {
    200   DCHECK(is_deferred_);
    201   is_deferred_ = false;
    202   controller()->Resume();
    203 }
    204 
    205 void DetachableResourceHandler::Cancel() {
    206   controller()->Cancel();
    207 }
    208 
    209 void DetachableResourceHandler::CancelAndIgnore() {
    210   controller()->CancelAndIgnore();
    211 }
    212 
    213 void DetachableResourceHandler::CancelWithError(int error_code) {
    214   controller()->CancelWithError(error_code);
    215 }
    216 
    217 }  // namespace content
    218