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
ThrottlingResourceHandler(scoped_ptr<ResourceHandler> next_handler,net::URLRequest * request,ScopedVector<ResourceThrottle> throttles)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
~ThrottlingResourceHandler()31 ThrottlingResourceHandler::~ThrottlingResourceHandler() {
32 }
33
OnRequestRedirected(const net::RedirectInfo & redirect_info,ResourceResponse * response,bool * defer)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
OnWillStart(const GURL & url,bool * defer)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
OnBeforeNetworkStart(const GURL & url,bool * defer)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
OnResponseStarted(ResourceResponse * response,bool * defer)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
Cancel()131 void ThrottlingResourceHandler::Cancel() {
132 cancelled_by_resource_throttle_ = true;
133 controller()->Cancel();
134 }
135
CancelAndIgnore()136 void ThrottlingResourceHandler::CancelAndIgnore() {
137 cancelled_by_resource_throttle_ = true;
138 controller()->CancelAndIgnore();
139 }
140
CancelWithError(int error_code)141 void ThrottlingResourceHandler::CancelWithError(int error_code) {
142 cancelled_by_resource_throttle_ = true;
143 controller()->CancelWithError(error_code);
144 }
145
Resume()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
ResumeStart()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
ResumeNetworkStart()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
ResumeRedirect()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
ResumeResponse()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
OnRequestDefered(int throttle_index)230 void ThrottlingResourceHandler::OnRequestDefered(int throttle_index) {
231 request()->LogBlockedBy(throttles_[throttle_index]->GetNameForLogging());
232 }
233
234 } // namespace content
235