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 12namespace content { 13 14ThrottlingResourceHandler::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 31ThrottlingResourceHandler::~ThrottlingResourceHandler() { 32} 33 34bool 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 61bool 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 84bool 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 108bool 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 131void ThrottlingResourceHandler::Cancel() { 132 cancelled_by_resource_throttle_ = true; 133 controller()->Cancel(); 134} 135 136void ThrottlingResourceHandler::CancelAndIgnore() { 137 cancelled_by_resource_throttle_ = true; 138 controller()->CancelAndIgnore(); 139} 140 141void ThrottlingResourceHandler::CancelWithError(int error_code) { 142 cancelled_by_resource_throttle_ = true; 143 controller()->CancelWithError(error_code); 144} 145 146void 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 172void 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 186void 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 200void 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 216void 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 230void ThrottlingResourceHandler::OnRequestDefered(int throttle_index) { 231 request()->LogBlockedBy(throttles_[throttle_index]->GetNameForLogging()); 232} 233 234} // namespace content 235