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