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(int request_id,
     35                                                     const GURL& new_url,
     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(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_url_ = new_url;
     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(request_id, new_url, response,
     59                                             defer);
     60 }
     61 
     62 bool ThrottlingResourceHandler::OnWillStart(int request_id,
     63                                             const GURL& url,
     64                                             bool* defer) {
     65   DCHECK(!cancelled_by_resource_throttle_);
     66 
     67   *defer = false;
     68   while (next_index_ < throttles_.size()) {
     69     int index = next_index_;
     70     throttles_[index]->WillStartRequest(defer);
     71     next_index_++;
     72     if (cancelled_by_resource_throttle_)
     73       return false;
     74     if (*defer) {
     75       OnRequestDefered(index);
     76       deferred_stage_ = DEFERRED_START;
     77       deferred_url_ = url;
     78       return true;  // Do not cancel.
     79     }
     80   }
     81 
     82   next_index_ = 0;  // Reset for next time.
     83 
     84   return next_handler_->OnWillStart(request_id, url, defer);
     85 }
     86 
     87 bool ThrottlingResourceHandler::OnResponseStarted(int request_id,
     88                                                   ResourceResponse* response,
     89                                                   bool* defer) {
     90   DCHECK(!cancelled_by_resource_throttle_);
     91 
     92   while (next_index_ < throttles_.size()) {
     93     int index = next_index_;
     94     throttles_[index]->WillProcessResponse(defer);
     95     next_index_++;
     96     if (cancelled_by_resource_throttle_)
     97       return false;
     98     if (*defer) {
     99       OnRequestDefered(index);
    100       deferred_stage_ = DEFERRED_RESPONSE;
    101       deferred_response_ = response;
    102       return true;  // Do not cancel.
    103     }
    104   }
    105 
    106   next_index_ = 0;  // Reset for next time.
    107 
    108   return next_handler_->OnResponseStarted(request_id, response, defer);
    109 }
    110 
    111 void ThrottlingResourceHandler::Cancel() {
    112   cancelled_by_resource_throttle_ = true;
    113   controller()->Cancel();
    114 }
    115 
    116 void ThrottlingResourceHandler::CancelAndIgnore() {
    117   cancelled_by_resource_throttle_ = true;
    118   controller()->CancelAndIgnore();
    119 }
    120 
    121 void ThrottlingResourceHandler::CancelWithError(int error_code) {
    122   cancelled_by_resource_throttle_ = true;
    123   controller()->CancelWithError(error_code);
    124 }
    125 
    126 void ThrottlingResourceHandler::Resume() {
    127   DCHECK(!cancelled_by_resource_throttle_);
    128 
    129   DeferredStage last_deferred_stage = deferred_stage_;
    130   deferred_stage_ = DEFERRED_NONE;
    131   // Clear information about the throttle that delayed the request.
    132   request()->LogUnblocked();
    133   switch (last_deferred_stage) {
    134     case DEFERRED_NONE:
    135       NOTREACHED();
    136       break;
    137     case DEFERRED_START:
    138       ResumeStart();
    139       break;
    140     case DEFERRED_REDIRECT:
    141       ResumeRedirect();
    142       break;
    143     case DEFERRED_RESPONSE:
    144       ResumeResponse();
    145       break;
    146   }
    147 }
    148 
    149 void ThrottlingResourceHandler::ResumeStart() {
    150   DCHECK(!cancelled_by_resource_throttle_);
    151 
    152   GURL url = deferred_url_;
    153   deferred_url_ = GURL();
    154 
    155   bool defer = false;
    156   if (!OnWillStart(GetRequestID(), url, &defer)) {
    157     controller()->Cancel();
    158   } else if (!defer) {
    159     controller()->Resume();
    160   }
    161 }
    162 
    163 void ThrottlingResourceHandler::ResumeRedirect() {
    164   DCHECK(!cancelled_by_resource_throttle_);
    165 
    166   GURL new_url = deferred_url_;
    167   deferred_url_ = GURL();
    168   scoped_refptr<ResourceResponse> response;
    169   deferred_response_.swap(response);
    170 
    171   bool defer = false;
    172   if (!OnRequestRedirected(GetRequestID(), new_url, response.get(), &defer)) {
    173     controller()->Cancel();
    174   } else if (!defer) {
    175     controller()->Resume();
    176   }
    177 }
    178 
    179 void ThrottlingResourceHandler::ResumeResponse() {
    180   DCHECK(!cancelled_by_resource_throttle_);
    181 
    182   scoped_refptr<ResourceResponse> response;
    183   deferred_response_.swap(response);
    184 
    185   bool defer = false;
    186   if (!OnResponseStarted(GetRequestID(), response.get(), &defer)) {
    187     controller()->Cancel();
    188   } else if (!defer) {
    189     controller()->Resume();
    190   }
    191 }
    192 
    193 void ThrottlingResourceHandler::OnRequestDefered(int throttle_index) {
    194   request()->LogBlockedBy(throttles_[throttle_index]->GetNameForLogging());
    195 }
    196 
    197 }  // namespace content
    198