OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/loader/throttling_resource_handler.h" | 5 #include "content/browser/loader/throttling_resource_handler.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/debug/alias.h" | |
10 #include "base/strings/string_util.h" | |
11 #include "content/browser/loader/resource_request_info_impl.h" | 9 #include "content/browser/loader/resource_request_info_impl.h" |
12 #include "content/public/browser/resource_throttle.h" | 10 #include "content/public/browser/resource_throttle.h" |
13 #include "content/public/common/resource_response.h" | 11 #include "content/public/common/resource_response.h" |
14 #include "net/url_request/url_request.h" | 12 #include "net/url_request/url_request.h" |
15 | 13 |
16 namespace content { | 14 namespace content { |
17 | 15 |
18 ThrottlingResourceHandler::ThrottlingResourceHandler( | 16 ThrottlingResourceHandler::ThrottlingResourceHandler( |
19 std::unique_ptr<ResourceHandler> next_handler, | 17 std::unique_ptr<ResourceHandler> next_handler, |
20 net::URLRequest* request, | 18 net::URLRequest* request, |
21 ScopedVector<ResourceThrottle> throttles) | 19 ScopedVector<ResourceThrottle> throttles) |
22 : LayeredResourceHandler(request, std::move(next_handler)), | 20 : LayeredResourceHandler(request, std::move(next_handler)), |
23 deferred_stage_(DEFERRED_NONE), | 21 deferred_stage_(DEFERRED_NONE), |
24 throttles_(std::move(throttles)), | 22 throttles_(std::move(throttles)), |
25 next_index_(0), | 23 next_index_(0), |
26 cancelled_by_resource_throttle_(false), | 24 cancelled_by_resource_throttle_(false) { |
27 currently_calling_throttle_(false) { | |
28 for (size_t i = 0; i < throttles_.size(); ++i) { | 25 for (size_t i = 0; i < throttles_.size(); ++i) { |
29 throttles_[i]->set_controller(this); | 26 throttles_[i]->set_controller(this); |
30 // Throttles must have a name, as otherwise, bugs where a throttle fails | 27 // Throttles must have a name, as otherwise, bugs where a throttle fails |
31 // to resume a request can be very difficult to debug. | 28 // to resume a request can be very difficult to debug. |
32 DCHECK(throttles_[i]->GetNameForLogging()); | 29 DCHECK(throttles_[i]->GetNameForLogging()); |
33 } | 30 } |
34 } | 31 } |
35 | 32 |
36 ThrottlingResourceHandler::~ThrottlingResourceHandler() { | 33 ThrottlingResourceHandler::~ThrottlingResourceHandler() { |
37 // Check if |this| is being destroyed in a reentrant call from a throttle. | |
38 if (currently_calling_throttle_) { | |
39 CHECK_LE(1u, next_index_); | |
40 CHECK_LE(next_index_, throttles_.size()); | |
41 | |
42 // Stick some information on the stack that may be useful in debugging. | |
43 char bad_throttle_name[100]; | |
44 base::strlcpy(bad_throttle_name, | |
45 throttles_[next_index_ - 1]->GetNameForLogging(), | |
46 arraysize(bad_throttle_name)); | |
47 DeferredStage deferred_stage = deferred_stage_; | |
48 char url[128]; | |
49 // The request should still be valid at this point... | |
50 base::strlcpy(url, request()->url().spec().c_str(), arraysize(url)); | |
51 base::debug::Alias(bad_throttle_name); | |
52 base::debug::Alias(&deferred_stage); | |
53 base::debug::Alias(url); | |
54 | |
55 CHECK(false); | |
56 } | |
57 } | 34 } |
58 | 35 |
59 bool ThrottlingResourceHandler::OnRequestRedirected( | 36 bool ThrottlingResourceHandler::OnRequestRedirected( |
60 const net::RedirectInfo& redirect_info, | 37 const net::RedirectInfo& redirect_info, |
61 ResourceResponse* response, | 38 ResourceResponse* response, |
62 bool* defer) { | 39 bool* defer) { |
63 CHECK(!currently_calling_throttle_); | |
64 DCHECK(!cancelled_by_resource_throttle_); | 40 DCHECK(!cancelled_by_resource_throttle_); |
65 | 41 |
66 *defer = false; | 42 *defer = false; |
67 while (next_index_ < throttles_.size()) { | 43 while (next_index_ < throttles_.size()) { |
68 int index = next_index_; | 44 int index = next_index_; |
69 currently_calling_throttle_ = true; | |
70 throttles_[index]->WillRedirectRequest(redirect_info, defer); | 45 throttles_[index]->WillRedirectRequest(redirect_info, defer); |
71 currently_calling_throttle_ = false; | |
72 next_index_++; | 46 next_index_++; |
73 if (cancelled_by_resource_throttle_) | 47 if (cancelled_by_resource_throttle_) |
74 return false; | 48 return false; |
75 if (*defer) { | 49 if (*defer) { |
76 OnRequestDefered(index); | 50 OnRequestDefered(index); |
77 deferred_stage_ = DEFERRED_REDIRECT; | 51 deferred_stage_ = DEFERRED_REDIRECT; |
78 deferred_redirect_ = redirect_info; | 52 deferred_redirect_ = redirect_info; |
79 deferred_response_ = response; | 53 deferred_response_ = response; |
80 return true; // Do not cancel. | 54 return true; // Do not cancel. |
81 } | 55 } |
82 } | 56 } |
83 | 57 |
84 next_index_ = 0; // Reset for next time. | 58 next_index_ = 0; // Reset for next time. |
85 | 59 |
86 return next_handler_->OnRequestRedirected(redirect_info, response, defer); | 60 return next_handler_->OnRequestRedirected(redirect_info, response, defer); |
87 } | 61 } |
88 | 62 |
89 bool ThrottlingResourceHandler::OnWillStart(const GURL& url, bool* defer) { | 63 bool ThrottlingResourceHandler::OnWillStart(const GURL& url, bool* defer) { |
90 CHECK(!currently_calling_throttle_); | |
91 DCHECK(!cancelled_by_resource_throttle_); | 64 DCHECK(!cancelled_by_resource_throttle_); |
92 | 65 |
93 *defer = false; | 66 *defer = false; |
94 while (next_index_ < throttles_.size()) { | 67 while (next_index_ < throttles_.size()) { |
95 int index = next_index_; | 68 int index = next_index_; |
96 currently_calling_throttle_ = true; | |
97 throttles_[index]->WillStartRequest(defer); | 69 throttles_[index]->WillStartRequest(defer); |
98 currently_calling_throttle_ = false; | |
99 next_index_++; | 70 next_index_++; |
100 if (cancelled_by_resource_throttle_) | 71 if (cancelled_by_resource_throttle_) |
101 return false; | 72 return false; |
102 if (*defer) { | 73 if (*defer) { |
103 OnRequestDefered(index); | 74 OnRequestDefered(index); |
104 deferred_stage_ = DEFERRED_START; | 75 deferred_stage_ = DEFERRED_START; |
105 deferred_url_ = url; | 76 deferred_url_ = url; |
106 return true; // Do not cancel. | 77 return true; // Do not cancel. |
107 } | 78 } |
108 } | 79 } |
109 | 80 |
110 next_index_ = 0; // Reset for next time. | 81 next_index_ = 0; // Reset for next time. |
111 | 82 |
112 return next_handler_->OnWillStart(url, defer); | 83 return next_handler_->OnWillStart(url, defer); |
113 } | 84 } |
114 | 85 |
115 bool ThrottlingResourceHandler::OnResponseStarted(ResourceResponse* response, | 86 bool ThrottlingResourceHandler::OnResponseStarted(ResourceResponse* response, |
116 bool* defer) { | 87 bool* defer) { |
117 CHECK(!currently_calling_throttle_); | |
118 DCHECK(!cancelled_by_resource_throttle_); | 88 DCHECK(!cancelled_by_resource_throttle_); |
119 | 89 |
120 while (next_index_ < throttles_.size()) { | 90 while (next_index_ < throttles_.size()) { |
121 int index = next_index_; | 91 int index = next_index_; |
122 currently_calling_throttle_ = true; | |
123 throttles_[index]->WillProcessResponse(defer); | 92 throttles_[index]->WillProcessResponse(defer); |
124 currently_calling_throttle_ = false; | |
125 next_index_++; | 93 next_index_++; |
126 if (cancelled_by_resource_throttle_) | 94 if (cancelled_by_resource_throttle_) |
127 return false; | 95 return false; |
128 if (*defer) { | 96 if (*defer) { |
129 OnRequestDefered(index); | 97 OnRequestDefered(index); |
130 deferred_stage_ = DEFERRED_RESPONSE; | 98 deferred_stage_ = DEFERRED_RESPONSE; |
131 deferred_response_ = response; | 99 deferred_response_ = response; |
132 return true; // Do not cancel. | 100 return true; // Do not cancel. |
133 } | 101 } |
134 } | 102 } |
(...skipping 12 matching lines...) Expand all Loading... |
147 cancelled_by_resource_throttle_ = true; | 115 cancelled_by_resource_throttle_ = true; |
148 controller()->CancelAndIgnore(); | 116 controller()->CancelAndIgnore(); |
149 } | 117 } |
150 | 118 |
151 void ThrottlingResourceHandler::CancelWithError(int error_code) { | 119 void ThrottlingResourceHandler::CancelWithError(int error_code) { |
152 cancelled_by_resource_throttle_ = true; | 120 cancelled_by_resource_throttle_ = true; |
153 controller()->CancelWithError(error_code); | 121 controller()->CancelWithError(error_code); |
154 } | 122 } |
155 | 123 |
156 void ThrottlingResourceHandler::Resume() { | 124 void ThrottlingResourceHandler::Resume() { |
157 CHECK(!currently_calling_throttle_); | |
158 DCHECK(!cancelled_by_resource_throttle_); | 125 DCHECK(!cancelled_by_resource_throttle_); |
159 // TODO(mmenke): Remove CHECK once https://crbug.com/640545 is resolved, as | |
160 // it's redundant with the NOTREACHED() below. | |
161 CHECK_NE(DEFERRED_NONE, deferred_stage_); | |
162 | 126 |
163 DeferredStage last_deferred_stage = deferred_stage_; | 127 DeferredStage last_deferred_stage = deferred_stage_; |
164 deferred_stage_ = DEFERRED_NONE; | 128 deferred_stage_ = DEFERRED_NONE; |
165 // Clear information about the throttle that delayed the request. | 129 // Clear information about the throttle that delayed the request. |
166 request()->LogUnblocked(); | 130 request()->LogUnblocked(); |
167 switch (last_deferred_stage) { | 131 switch (last_deferred_stage) { |
168 case DEFERRED_NONE: | 132 case DEFERRED_NONE: |
169 NOTREACHED(); | 133 NOTREACHED(); |
170 break; | 134 break; |
171 case DEFERRED_START: | 135 case DEFERRED_START: |
172 ResumeStart(); | 136 ResumeStart(); |
173 break; | 137 break; |
174 case DEFERRED_REDIRECT: | 138 case DEFERRED_REDIRECT: |
175 ResumeRedirect(); | 139 ResumeRedirect(); |
176 break; | 140 break; |
177 case DEFERRED_RESPONSE: | 141 case DEFERRED_RESPONSE: |
178 ResumeResponse(); | 142 ResumeResponse(); |
179 break; | 143 break; |
180 } | 144 } |
181 } | 145 } |
182 | 146 |
183 void ThrottlingResourceHandler::ResumeStart() { | 147 void ThrottlingResourceHandler::ResumeStart() { |
184 CHECK(!currently_calling_throttle_); | |
185 DCHECK(!cancelled_by_resource_throttle_); | 148 DCHECK(!cancelled_by_resource_throttle_); |
186 | 149 |
187 GURL url = deferred_url_; | 150 GURL url = deferred_url_; |
188 deferred_url_ = GURL(); | 151 deferred_url_ = GURL(); |
189 | 152 |
190 bool defer = false; | 153 bool defer = false; |
191 if (!OnWillStart(url, &defer)) { | 154 if (!OnWillStart(url, &defer)) { |
192 controller()->Cancel(); | 155 controller()->Cancel(); |
193 } else if (!defer) { | 156 } else if (!defer) { |
194 controller()->Resume(); | 157 controller()->Resume(); |
195 } | 158 } |
196 } | 159 } |
197 | 160 |
198 void ThrottlingResourceHandler::ResumeRedirect() { | 161 void ThrottlingResourceHandler::ResumeRedirect() { |
199 CHECK(!currently_calling_throttle_); | |
200 DCHECK(!cancelled_by_resource_throttle_); | 162 DCHECK(!cancelled_by_resource_throttle_); |
201 | 163 |
202 net::RedirectInfo redirect_info = deferred_redirect_; | 164 net::RedirectInfo redirect_info = deferred_redirect_; |
203 deferred_redirect_ = net::RedirectInfo(); | 165 deferred_redirect_ = net::RedirectInfo(); |
204 scoped_refptr<ResourceResponse> response; | 166 scoped_refptr<ResourceResponse> response; |
205 deferred_response_.swap(response); | 167 deferred_response_.swap(response); |
206 | 168 |
207 bool defer = false; | 169 bool defer = false; |
208 if (!OnRequestRedirected(redirect_info, response.get(), &defer)) { | 170 if (!OnRequestRedirected(redirect_info, response.get(), &defer)) { |
209 controller()->Cancel(); | 171 controller()->Cancel(); |
210 } else if (!defer) { | 172 } else if (!defer) { |
211 controller()->Resume(); | 173 controller()->Resume(); |
212 } | 174 } |
213 } | 175 } |
214 | 176 |
215 void ThrottlingResourceHandler::ResumeResponse() { | 177 void ThrottlingResourceHandler::ResumeResponse() { |
216 CHECK(!currently_calling_throttle_); | |
217 DCHECK(!cancelled_by_resource_throttle_); | 178 DCHECK(!cancelled_by_resource_throttle_); |
218 | 179 |
219 scoped_refptr<ResourceResponse> response; | 180 scoped_refptr<ResourceResponse> response; |
220 deferred_response_.swap(response); | 181 deferred_response_.swap(response); |
221 | 182 |
222 bool defer = false; | 183 bool defer = false; |
223 if (!OnResponseStarted(response.get(), &defer)) { | 184 if (!OnResponseStarted(response.get(), &defer)) { |
224 controller()->Cancel(); | 185 controller()->Cancel(); |
225 } else if (!defer) { | 186 } else if (!defer) { |
226 controller()->Resume(); | 187 controller()->Resume(); |
227 } | 188 } |
228 } | 189 } |
229 | 190 |
230 void ThrottlingResourceHandler::OnRequestDefered(int throttle_index) { | 191 void ThrottlingResourceHandler::OnRequestDefered(int throttle_index) { |
231 request()->LogBlockedBy(throttles_[throttle_index]->GetNameForLogging()); | 192 request()->LogBlockedBy(throttles_[throttle_index]->GetNameForLogging()); |
232 } | 193 } |
233 | 194 |
234 } // namespace content | 195 } // namespace content |
OLD | NEW |