Home | History | Annotate | Download | only in loader
      1 // Copyright (c) 2012 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/throttling_resource_handler.h"
      6 
      7 #include "content/browser/loader/resource_request_info_impl.h"
      8 #include "content/public/browser/resource_throttle.h"
      9 #include "content/public/common/resource_response.h"
     10 #include "net/url_request/url_request.h"
     11 
     12 namespace content {
     13 
     14 ThrottlingResourceHandler::ThrottlingResourceHandler(
     15     scoped_ptr<ResourceHandler> next_handler,
     16     net::URLRequest* request,
     17     ScopedVector<ResourceThrottle> throttles)
     18     : LayeredResourceHandler(request, next_handler.Pass()),
     19       deferred_stage_(DEFERRED_NONE),
     20       throttles_(throttles.Pass()),
     21       next_index_(0),
     22       cancelled_by_resource_throttle_(false) {
     23   for (size_t i = 0; i < throttles_.size(); ++i) {
     24     throttles_[i]->set_controller(this);
     25     // Throttles must have a name, as otherwise, bugs where a throttle fails
     26     // to resume a request can be very difficult to debug.
     27     DCHECK(throttles_[i]->GetNameForLogging());
     28   }
     29 }
     30 
     31 ThrottlingResourceHandler::~ThrottlingResourceHandler() {
     32 }
     33 
     34 bool ThrottlingResourceHandler::OnRequestRedirected(const GURL& new_url,
     35                                                     ResourceResponse* response,
     36                                                     bool* defer) {
     37   DCHECK(!cancelled_by_resource_throttle_);
     38 
     39   *defer = false;
     40   while (next_index_ < throttles_.size()) {
     41     int index = next_index_;
     42     throttles_[index]->WillRedirectRequest(new_url, defer);
     43     next_index_++;
     44     if (cancelled_by_resource_throttle_)
     45       return false;
     46     if (*defer) {
     47       OnRequestDefered(index);
     48       deferred_stage_ = DEFERRED_REDIRECT;
     49       deferred_url_ = new_url;
     50       deferred_response_ = response;
     51       return true;  // Do not cancel.
     52     }
     53   }
     54 
     55   next_index_ = 0;  // Reset for next time.
     56 
     57   return next_handler_->OnRequestRedirected(new_url, response, defer);
     58 }
     59 
     60 bool ThrottlingResourceHandler::OnWillStart(const GURL& url, bool* defer) {
     61   DCHECK(!cancelled_by_resource_throttle_);
     62 
     63   *defer = false;
     64   while (next_index_ < throttles_.size()) {
     65     int index = next_index_;
     66     throttles_[index]->WillStartRequest(defer);
     67     next_index_++;
     68     if (cancelled_by_resource_throttle_)
     69       return false;
     70     if (*defer) {
     71       OnRequestDefered(index);
     72       deferred_stage_ = DEFERRED_START;
     73       deferred_url_ = url;
     74       return true;  // Do not cancel.
     75     }
     76   }
     77 
     78   next_index_ = 0;  // Reset for next time.
     79 
     80   return next_handler_->OnWillStart(url, defer);
     81 }
     82 
     83 bool ThrottlingResourceHandler::OnBeforeNetworkStart(const GURL& url,
     84                                                      bool* defer) {
     85   DCHECK(!cancelled_by_resource_throttle_);
     86 
     87   *defer = false;
     88   while (next_index_ < throttles_.size()) {
     89     int index = next_index_;
     90     throttles_[index]->OnBeforeNetworkStart(defer);
     91     next_index_++;
     92     if (cancelled_by_resource_throttle_)
     93       return false;
     94     if (*defer) {
     95       OnRequestDefered(index);
     96       deferred_stage_ = DEFERRED_NETWORK_START;
     97       deferred_url_ = url;
     98       return true;  // Do not cancel.
     99     }
    100   }
    101 
    102   next_index_ = 0;  // Reset for next time.
    103 
    104   return next_handler_->OnBeforeNetworkStart(url, defer);
    105 }
    106 
    107 bool ThrottlingResourceHandler::OnResponseStarted(ResourceResponse* response,
    108                                                   bool* defer) {
    109   DCHECK(!cancelled_by_resource_throttle_);
    110 
    111   while (next_index_ < throttles_.size()) {
    112     int index = next_index_;
    113     throttles_[index]->WillProcessResponse(defer);
    114     next_index_++;
    115     if (cancelled_by_resource_throttle_)
    116       return false;
    117     if (*defer) {
    118       OnRequestDefered(index);
    119       deferred_stage_ = DEFERRED_RESPONSE;
    120       deferred_response_ = response;
    121       return true;  // Do not cancel.
    122     }
    123   }
    124 
    125   next_index_ = 0;  // Reset for next time.
    126 
    127   return next_handler_->OnResponseStarted(response, defer);
    128 }
    129 
    130 void ThrottlingResourceHandler::Cancel() {
    131   cancelled_by_resource_throttle_ = true;
    132   controller()->Cancel();
    133 }
    134 
    135 void ThrottlingResourceHandler::CancelAndIgnore() {
    136   cancelled_by_resource_throttle_ = true;
    137   controller()->CancelAndIgnore();
    138 }
    139 
    140 void ThrottlingResourceHandler::CancelWithError(int error_code) {
    141   cancelled_by_resource_throttle_ = true;
    142   controller()->CancelWithError(error_code);
    143 }
    144 
    145 void ThrottlingResourceHandler::Resume() {
    146   DCHECK(!cancelled_by_resource_throttle_);
    147 
    148   DeferredStage last_deferred_stage = deferred_stage_;
    149   deferred_stage_ = DEFERRED_NONE;
    150   // Clear information about the throttle that delayed the request.
    151   request()->LogUnblocked();
    152   switch (last_deferred_stage) {
    153     case DEFERRED_NONE:
    154       NOTREACHED();
    155       break;
    156     case DEFERRED_START:
    157       ResumeStart();
    158       break;
    159     case DEFERRED_NETWORK_START:
    160       ResumeNetworkStart();
    161       break;
    162     case DEFERRED_REDIRECT:
    163       ResumeRedirect();
    164       break;
    165     case DEFERRED_RESPONSE:
    166       ResumeResponse();
    167       break;
    168   }
    169 }
    170 
    171 void ThrottlingResourceHandler::ResumeStart() {
    172   DCHECK(!cancelled_by_resource_throttle_);
    173 
    174   GURL url = deferred_url_;
    175   deferred_url_ = GURL();
    176 
    177   bool defer = false;
    178   if (!OnWillStart(url, &defer)) {
    179     controller()->Cancel();
    180   } else if (!defer) {
    181     controller()->Resume();
    182   }
    183 }
    184 
    185 void ThrottlingResourceHandler::ResumeNetworkStart() {
    186   DCHECK(!cancelled_by_resource_throttle_);
    187 
    188   GURL url = deferred_url_;
    189   deferred_url_ = GURL();
    190 
    191   bool defer = false;
    192   if (!OnBeforeNetworkStart(url, &defer)) {
    193     controller()->Cancel();
    194   } else if (!defer) {
    195     controller()->Resume();
    196   }
    197 }
    198 
    199 void ThrottlingResourceHandler::ResumeRedirect() {
    200   DCHECK(!cancelled_by_resource_throttle_);
    201 
    202   GURL new_url = deferred_url_;
    203   deferred_url_ = GURL();
    204   scoped_refptr<ResourceResponse> response;
    205   deferred_response_.swap(response);
    206 
    207   bool defer = false;
    208   if (!OnRequestRedirected(new_url, response.get(), &defer)) {
    209     controller()->Cancel();
    210   } else if (!defer) {
    211     controller()->Resume();
    212   }
    213 }
    214 
    215 void ThrottlingResourceHandler::ResumeResponse() {
    216   DCHECK(!cancelled_by_resource_throttle_);
    217 
    218   scoped_refptr<ResourceResponse> response;
    219   deferred_response_.swap(response);
    220 
    221   bool defer = false;
    222   if (!OnResponseStarted(response.get(), &defer)) {
    223     controller()->Cancel();
    224   } else if (!defer) {
    225     controller()->Resume();
    226   }
    227 }
    228 
    229 void ThrottlingResourceHandler::OnRequestDefered(int throttle_index) {
    230   request()->LogBlockedBy(throttles_[throttle_index]->GetNameForLogging());
    231 }
    232 
    233 }  // namespace content
    234