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(
     35     const net::RedirectInfo& redirect_info,
     36     ResourceResponse* response,
     37     bool* defer) {
     38   DCHECK(!cancelled_by_resource_throttle_);
     39 
     40   *defer = false;
     41   while (next_index_ < throttles_.size()) {
     42     int index = next_index_;
     43     throttles_[index]->WillRedirectRequest(redirect_info.new_url, defer);
     44     next_index_++;
     45     if (cancelled_by_resource_throttle_)
     46       return false;
     47     if (*defer) {
     48       OnRequestDefered(index);
     49       deferred_stage_ = DEFERRED_REDIRECT;
     50       deferred_redirect_ = redirect_info;
     51       deferred_response_ = response;
     52       return true;  // Do not cancel.
     53     }
     54   }
     55 
     56   next_index_ = 0;  // Reset for next time.
     57 
     58   return next_handler_->OnRequestRedirected(redirect_info, response, defer);
     59 }
     60 
     61 bool ThrottlingResourceHandler::OnWillStart(const GURL& url, bool* defer) {
     62   DCHECK(!cancelled_by_resource_throttle_);
     63 
     64   *defer = false;
     65   while (next_index_ < throttles_.size()) {
     66     int index = next_index_;
     67     throttles_[index]->WillStartRequest(defer);
     68     next_index_++;
     69     if (cancelled_by_resource_throttle_)
     70       return false;
     71     if (*defer) {
     72       OnRequestDefered(index);
     73       deferred_stage_ = DEFERRED_START;
     74       deferred_url_ = url;
     75       return true;  // Do not cancel.
     76     }
     77   }
     78 
     79   next_index_ = 0;  // Reset for next time.
     80 
     81   return next_handler_->OnWillStart(url, defer);
     82 }
     83 
     84 bool ThrottlingResourceHandler::OnBeforeNetworkStart(const GURL& url,
     85                                                      bool* defer) {
     86   DCHECK(!cancelled_by_resource_throttle_);
     87 
     88   *defer = false;
     89   while (next_index_ < throttles_.size()) {
     90     int index = next_index_;
     91     throttles_[index]->WillStartUsingNetwork(defer);
     92     next_index_++;
     93     if (cancelled_by_resource_throttle_)
     94       return false;
     95     if (*defer) {
     96       OnRequestDefered(index);
     97       deferred_stage_ = DEFERRED_NETWORK_START;
     98       deferred_url_ = url;
     99       return true;  // Do not cancel.
    100     }
    101   }
    102 
    103   next_index_ = 0;  // Reset for next time.
    104 
    105   return next_handler_->OnBeforeNetworkStart(url, defer);
    106 }
    107 
    108 bool ThrottlingResourceHandler::OnResponseStarted(ResourceResponse* response,
    109                                                   bool* defer) {
    110   DCHECK(!cancelled_by_resource_throttle_);
    111 
    112   while (next_index_ < throttles_.size()) {
    113     int index = next_index_;
    114     throttles_[index]->WillProcessResponse(defer);
    115     next_index_++;
    116     if (cancelled_by_resource_throttle_)
    117       return false;
    118     if (*defer) {
    119       OnRequestDefered(index);
    120       deferred_stage_ = DEFERRED_RESPONSE;
    121       deferred_response_ = response;
    122       return true;  // Do not cancel.
    123     }
    124   }
    125 
    126   next_index_ = 0;  // Reset for next time.
    127 
    128   return next_handler_->OnResponseStarted(response, defer);
    129 }
    130 
    131 void ThrottlingResourceHandler::Cancel() {
    132   cancelled_by_resource_throttle_ = true;
    133   controller()->Cancel();
    134 }
    135 
    136 void ThrottlingResourceHandler::CancelAndIgnore() {
    137   cancelled_by_resource_throttle_ = true;
    138   controller()->CancelAndIgnore();
    139 }
    140 
    141 void ThrottlingResourceHandler::CancelWithError(int error_code) {
    142   cancelled_by_resource_throttle_ = true;
    143   controller()->CancelWithError(error_code);
    144 }
    145 
    146 void ThrottlingResourceHandler::Resume() {
    147   DCHECK(!cancelled_by_resource_throttle_);
    148 
    149   DeferredStage last_deferred_stage = deferred_stage_;
    150   deferred_stage_ = DEFERRED_NONE;
    151   // Clear information about the throttle that delayed the request.
    152   request()->LogUnblocked();
    153   switch (last_deferred_stage) {
    154     case DEFERRED_NONE:
    155       NOTREACHED();
    156       break;
    157     case DEFERRED_START:
    158       ResumeStart();
    159       break;
    160     case DEFERRED_NETWORK_START:
    161       ResumeNetworkStart();
    162       break;
    163     case DEFERRED_REDIRECT:
    164       ResumeRedirect();
    165       break;
    166     case DEFERRED_RESPONSE:
    167       ResumeResponse();
    168       break;
    169   }
    170 }
    171 
    172 void ThrottlingResourceHandler::ResumeStart() {
    173   DCHECK(!cancelled_by_resource_throttle_);
    174 
    175   GURL url = deferred_url_;
    176   deferred_url_ = GURL();
    177 
    178   bool defer = false;
    179   if (!OnWillStart(url, &defer)) {
    180     controller()->Cancel();
    181   } else if (!defer) {
    182     controller()->Resume();
    183   }
    184 }
    185 
    186 void ThrottlingResourceHandler::ResumeNetworkStart() {
    187   DCHECK(!cancelled_by_resource_throttle_);
    188 
    189   GURL url = deferred_url_;
    190   deferred_url_ = GURL();
    191 
    192   bool defer = false;
    193   if (!OnBeforeNetworkStart(url, &defer)) {
    194     controller()->Cancel();
    195   } else if (!defer) {
    196     controller()->Resume();
    197   }
    198 }
    199 
    200 void ThrottlingResourceHandler::ResumeRedirect() {
    201   DCHECK(!cancelled_by_resource_throttle_);
    202 
    203   net::RedirectInfo redirect_info = deferred_redirect_;
    204   deferred_redirect_ = net::RedirectInfo();
    205   scoped_refptr<ResourceResponse> response;
    206   deferred_response_.swap(response);
    207 
    208   bool defer = false;
    209   if (!OnRequestRedirected(redirect_info, response.get(), &defer)) {
    210     controller()->Cancel();
    211   } else if (!defer) {
    212     controller()->Resume();
    213   }
    214 }
    215 
    216 void ThrottlingResourceHandler::ResumeResponse() {
    217   DCHECK(!cancelled_by_resource_throttle_);
    218 
    219   scoped_refptr<ResourceResponse> response;
    220   deferred_response_.swap(response);
    221 
    222   bool defer = false;
    223   if (!OnResponseStarted(response.get(), &defer)) {
    224     controller()->Cancel();
    225   } else if (!defer) {
    226     controller()->Resume();
    227   }
    228 }
    229 
    230 void ThrottlingResourceHandler::OnRequestDefered(int throttle_index) {
    231   request()->LogBlockedBy(throttles_[throttle_index]->GetNameForLogging());
    232 }
    233 
    234 }  // namespace content
    235