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