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_status.h"
     13 
     14 namespace {
     15 // This matches the maximum allocation size of AsyncResourceHandler.
     16 const int kReadBufSize = 32 * 1024;
     17 }
     18 
     19 namespace content {
     20 
     21 DetachableResourceHandler::DetachableResourceHandler(
     22     net::URLRequest* request,
     23     base::TimeDelta cancel_delay,
     24     scoped_ptr<ResourceHandler> next_handler)
     25     : ResourceHandler(request),
     26       next_handler_(next_handler.Pass()),
     27       cancel_delay_(cancel_delay),
     28       is_deferred_(false),
     29       is_finished_(false) {
     30   GetRequestInfo()->set_detachable_handler(this);
     31 }
     32 
     33 DetachableResourceHandler::~DetachableResourceHandler() {
     34   // Cleanup back-pointer stored on the request info.
     35   GetRequestInfo()->set_detachable_handler(NULL);
     36 }
     37 
     38 void DetachableResourceHandler::Detach() {
     39   if (is_detached())
     40     return;
     41 
     42   if (!is_finished_) {
     43     // Simulate a cancel on the next handler before destroying it.
     44     net::URLRequestStatus status(net::URLRequestStatus::CANCELED,
     45                                  net::ERR_ABORTED);
     46     bool defer_ignored = false;
     47     next_handler_->OnResponseCompleted(GetRequestID(), status, std::string(),
     48                                        &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     Resume();
     75 }
     76 
     77 void DetachableResourceHandler::SetController(ResourceController* controller) {
     78   ResourceHandler::SetController(controller);
     79 
     80   // Intercept the ResourceController for downstream handlers to keep track of
     81   // whether the request is deferred.
     82   if (next_handler_)
     83     next_handler_->SetController(this);
     84 }
     85 
     86 bool DetachableResourceHandler::OnUploadProgress(int request_id,
     87                                                  uint64 position,
     88                                                  uint64 size) {
     89   if (!next_handler_)
     90     return true;
     91 
     92   return next_handler_->OnUploadProgress(request_id, position, size);
     93 }
     94 
     95 bool DetachableResourceHandler::OnRequestRedirected(int request_id,
     96                                                     const GURL& url,
     97                                                     ResourceResponse* response,
     98                                                     bool* defer) {
     99   DCHECK(!is_deferred_);
    100 
    101   if (!next_handler_)
    102     return true;
    103 
    104   bool ret = next_handler_->OnRequestRedirected(request_id, url, response,
    105                                                 &is_deferred_);
    106   *defer = is_deferred_;
    107   return ret;
    108 }
    109 
    110 bool DetachableResourceHandler::OnResponseStarted(int request_id,
    111                                                   ResourceResponse* response,
    112                                                   bool* defer) {
    113   DCHECK(!is_deferred_);
    114 
    115   if (!next_handler_)
    116     return true;
    117 
    118   bool ret =
    119       next_handler_->OnResponseStarted(request_id, response, &is_deferred_);
    120   *defer = is_deferred_;
    121   return ret;
    122 }
    123 
    124 bool DetachableResourceHandler::OnWillStart(int request_id, const GURL& url,
    125                                             bool* defer) {
    126   DCHECK(!is_deferred_);
    127 
    128   if (!next_handler_)
    129     return true;
    130 
    131   bool ret = next_handler_->OnWillStart(request_id, url, &is_deferred_);
    132   *defer = is_deferred_;
    133   return ret;
    134 }
    135 
    136 bool DetachableResourceHandler::OnWillRead(int request_id,
    137                                            scoped_refptr<net::IOBuffer>* buf,
    138                                            int* buf_size,
    139                                            int min_size) {
    140   if (!next_handler_) {
    141     DCHECK_EQ(-1, min_size);
    142     if (!read_buffer_)
    143       read_buffer_ = new net::IOBuffer(kReadBufSize);
    144     *buf = read_buffer_;
    145     *buf_size = kReadBufSize;
    146     return true;
    147   }
    148 
    149   return next_handler_->OnWillRead(request_id, buf, buf_size, min_size);
    150 }
    151 
    152 bool DetachableResourceHandler::OnReadCompleted(int request_id, int bytes_read,
    153                                                 bool* defer) {
    154   DCHECK(!is_deferred_);
    155 
    156   if (!next_handler_)
    157     return true;
    158 
    159   bool ret =
    160       next_handler_->OnReadCompleted(request_id, bytes_read, &is_deferred_);
    161   *defer = is_deferred_;
    162   return ret;
    163 }
    164 
    165 void DetachableResourceHandler::OnResponseCompleted(
    166     int request_id,
    167     const net::URLRequestStatus& status,
    168     const std::string& security_info,
    169     bool* defer) {
    170   // No DCHECK(!is_deferred_) as the request may have been cancelled while
    171   // deferred.
    172 
    173   if (!next_handler_)
    174     return;
    175 
    176   is_finished_ = true;
    177 
    178   next_handler_->OnResponseCompleted(request_id, status, security_info,
    179                                      &is_deferred_);
    180   *defer = is_deferred_;
    181 }
    182 
    183 void DetachableResourceHandler::OnDataDownloaded(int request_id,
    184                                                  int bytes_downloaded) {
    185   if (!next_handler_)
    186     return;
    187 
    188   next_handler_->OnDataDownloaded(request_id, bytes_downloaded);
    189 }
    190 
    191 void DetachableResourceHandler::Resume() {
    192   DCHECK(is_deferred_);
    193   is_deferred_ = false;
    194   controller()->Resume();
    195 }
    196 
    197 void DetachableResourceHandler::Cancel() {
    198   controller()->Cancel();
    199 }
    200 
    201 void DetachableResourceHandler::CancelAndIgnore() {
    202   controller()->CancelAndIgnore();
    203 }
    204 
    205 void DetachableResourceHandler::CancelWithError(int error_code) {
    206   controller()->CancelWithError(error_code);
    207 }
    208 
    209 }  // namespace content
    210