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