• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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