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 "net/url_request/url_request_throttler_entry.h" | 5 #include "net/url_request/url_request_throttler_entry.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/metrics/field_trial.h" | 10 #include "base/metrics/field_trial.h" |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
66 URLRequestThrottlerEntry::URLRequestThrottlerEntry( | 66 URLRequestThrottlerEntry::URLRequestThrottlerEntry( |
67 URLRequestThrottlerManager* manager, | 67 URLRequestThrottlerManager* manager, |
68 const std::string& url_id) | 68 const std::string& url_id) |
69 : sliding_window_period_( | 69 : sliding_window_period_( |
70 base::TimeDelta::FromMilliseconds(kDefaultSlidingWindowPeriodMs)), | 70 base::TimeDelta::FromMilliseconds(kDefaultSlidingWindowPeriodMs)), |
71 max_send_threshold_(kDefaultMaxSendThreshold), | 71 max_send_threshold_(kDefaultMaxSendThreshold), |
72 is_backoff_disabled_(false), | 72 is_backoff_disabled_(false), |
73 backoff_entry_(&backoff_policy_), | 73 backoff_entry_(&backoff_policy_), |
74 manager_(manager), | 74 manager_(manager), |
75 url_id_(url_id), | 75 url_id_(url_id), |
76 net_log_(BoundNetLog::Make( | 76 net_log_( |
77 manager->net_log(), NetLog::SOURCE_EXPONENTIAL_BACKOFF_THROTTLING)) { | 77 BoundNetLog::Make(manager->net_log(), |
| 78 NetLog::SOURCE_EXPONENTIAL_BACKOFF_THROTTLING)) { |
78 DCHECK(manager_); | 79 DCHECK(manager_); |
79 Initialize(); | 80 Initialize(); |
80 } | 81 } |
81 | 82 |
82 URLRequestThrottlerEntry::URLRequestThrottlerEntry( | 83 URLRequestThrottlerEntry::URLRequestThrottlerEntry( |
83 URLRequestThrottlerManager* manager, | 84 URLRequestThrottlerManager* manager, |
84 const std::string& url_id, | 85 const std::string& url_id, |
85 int sliding_window_period_ms, | 86 int sliding_window_period_ms, |
86 int max_send_threshold, | 87 int max_send_threshold, |
87 int initial_backoff_ms, | 88 int initial_backoff_ms, |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
153 const URLRequest& request) const { | 154 const URLRequest& request) const { |
154 bool reject_request = false; | 155 bool reject_request = false; |
155 if (!is_backoff_disabled_ && !ExplicitUserRequest(request.load_flags()) && | 156 if (!is_backoff_disabled_ && !ExplicitUserRequest(request.load_flags()) && |
156 (!request.context()->network_delegate() || | 157 (!request.context()->network_delegate() || |
157 request.context()->network_delegate()->CanThrottleRequest(request)) && | 158 request.context()->network_delegate()->CanThrottleRequest(request)) && |
158 GetBackoffEntry()->ShouldRejectRequest()) { | 159 GetBackoffEntry()->ShouldRejectRequest()) { |
159 int num_failures = GetBackoffEntry()->failure_count(); | 160 int num_failures = GetBackoffEntry()->failure_count(); |
160 int release_after_ms = | 161 int release_after_ms = |
161 GetBackoffEntry()->GetTimeUntilRelease().InMilliseconds(); | 162 GetBackoffEntry()->GetTimeUntilRelease().InMilliseconds(); |
162 | 163 |
163 net_log_.AddEvent( | 164 net_log_.AddEvent(NetLog::TYPE_THROTTLING_REJECTED_REQUEST, |
164 NetLog::TYPE_THROTTLING_REJECTED_REQUEST, | 165 base::Bind(&NetLogRejectedRequestCallback, |
165 base::Bind(&NetLogRejectedRequestCallback, | 166 &url_id_, |
166 &url_id_, num_failures, release_after_ms)); | 167 num_failures, |
| 168 release_after_ms)); |
167 | 169 |
168 reject_request = true; | 170 reject_request = true; |
169 } | 171 } |
170 | 172 |
171 int reject_count = reject_request ? 1 : 0; | 173 int reject_count = reject_request ? 1 : 0; |
172 UMA_HISTOGRAM_ENUMERATION( | 174 UMA_HISTOGRAM_ENUMERATION("Throttling.RequestThrottled", reject_count, 2); |
173 "Throttling.RequestThrottled", reject_count, 2); | |
174 | 175 |
175 return reject_request; | 176 return reject_request; |
176 } | 177 } |
177 | 178 |
178 int64 URLRequestThrottlerEntry::ReserveSendingTimeForNextRequest( | 179 int64 URLRequestThrottlerEntry::ReserveSendingTimeForNextRequest( |
179 const base::TimeTicks& earliest_time) { | 180 const base::TimeTicks& earliest_time) { |
180 base::TimeTicks now = ImplGetTimeNow(); | 181 base::TimeTicks now = ImplGetTimeNow(); |
181 | 182 |
182 // If a lot of requests were successfully made recently, | 183 // If a lot of requests were successfully made recently, |
183 // sliding_window_release_time_ may be greater than | 184 // sliding_window_release_time_ may be greater than |
184 // exponential_backoff_release_time_. | 185 // exponential_backoff_release_time_. |
185 base::TimeTicks recommended_sending_time = | 186 base::TimeTicks recommended_sending_time = |
186 std::max(std::max(now, earliest_time), | 187 std::max(std::max(now, earliest_time), |
187 std::max(GetBackoffEntry()->GetReleaseTime(), | 188 std::max(GetBackoffEntry()->GetReleaseTime(), |
188 sliding_window_release_time_)); | 189 sliding_window_release_time_)); |
189 | 190 |
190 DCHECK(send_log_.empty() || | 191 DCHECK(send_log_.empty() || recommended_sending_time >= send_log_.back()); |
191 recommended_sending_time >= send_log_.back()); | |
192 // Log the new send event. | 192 // Log the new send event. |
193 send_log_.push(recommended_sending_time); | 193 send_log_.push(recommended_sending_time); |
194 | 194 |
195 sliding_window_release_time_ = recommended_sending_time; | 195 sliding_window_release_time_ = recommended_sending_time; |
196 | 196 |
197 // Drop the out-of-date events in the event list. | 197 // Drop the out-of-date events in the event list. |
198 // We don't need to worry that the queue may become empty during this | 198 // We don't need to worry that the queue may become empty during this |
199 // operation, since the last element is sliding_window_release_time_. | 199 // operation, since the last element is sliding_window_release_time_. |
200 while ((send_log_.front() + sliding_window_period_ <= | 200 while ((send_log_.front() + sliding_window_period_ <= |
201 sliding_window_release_time_) || | 201 sliding_window_release_time_) || |
202 send_log_.size() > static_cast<unsigned>(max_send_threshold_)) { | 202 send_log_.size() > static_cast<unsigned>(max_send_threshold_)) { |
203 send_log_.pop(); | 203 send_log_.pop(); |
204 } | 204 } |
205 | 205 |
206 // Check if there are too many send events in recent time. | 206 // Check if there are too many send events in recent time. |
207 if (send_log_.size() == static_cast<unsigned>(max_send_threshold_)) | 207 if (send_log_.size() == static_cast<unsigned>(max_send_threshold_)) |
208 sliding_window_release_time_ = send_log_.front() + sliding_window_period_; | 208 sliding_window_release_time_ = send_log_.front() + sliding_window_period_; |
209 | 209 |
210 return (recommended_sending_time - now).InMillisecondsRoundedUp(); | 210 return (recommended_sending_time - now).InMillisecondsRoundedUp(); |
211 } | 211 } |
212 | 212 |
213 base::TimeTicks | 213 base::TimeTicks URLRequestThrottlerEntry::GetExponentialBackoffReleaseTime() |
214 URLRequestThrottlerEntry::GetExponentialBackoffReleaseTime() const { | 214 const { |
215 // If a site opts out, it's likely because they have problems that trigger | 215 // If a site opts out, it's likely because they have problems that trigger |
216 // the back-off mechanism when it shouldn't be triggered, in which case | 216 // the back-off mechanism when it shouldn't be triggered, in which case |
217 // returning the calculated back-off release time would probably be the | 217 // returning the calculated back-off release time would probably be the |
218 // wrong thing to do (i.e. it would likely be too long). Therefore, we | 218 // wrong thing to do (i.e. it would likely be too long). Therefore, we |
219 // return "now" so that retries are not delayed. | 219 // return "now" so that retries are not delayed. |
220 if (is_backoff_disabled_) | 220 if (is_backoff_disabled_) |
221 return ImplGetTimeNow(); | 221 return ImplGetTimeNow(); |
222 | 222 |
223 return GetBackoffEntry()->GetReleaseTime(); | 223 return GetBackoffEntry()->GetReleaseTime(); |
224 } | 224 } |
225 | 225 |
226 void URLRequestThrottlerEntry::UpdateWithResponse( | 226 void URLRequestThrottlerEntry::UpdateWithResponse( |
227 const std::string& host, | 227 const std::string& host, |
228 const URLRequestThrottlerHeaderInterface* response) { | 228 const URLRequestThrottlerHeaderInterface* response) { |
229 if (IsConsideredError(response->GetResponseCode())) { | 229 if (IsConsideredError(response->GetResponseCode())) { |
230 GetBackoffEntry()->InformOfRequest(false); | 230 GetBackoffEntry()->InformOfRequest(false); |
231 } else { | 231 } else { |
232 GetBackoffEntry()->InformOfRequest(true); | 232 GetBackoffEntry()->InformOfRequest(true); |
233 | 233 |
234 std::string throttling_header = response->GetNormalizedValue( | 234 std::string throttling_header = |
235 kExponentialThrottlingHeader); | 235 response->GetNormalizedValue(kExponentialThrottlingHeader); |
236 if (!throttling_header.empty()) | 236 if (!throttling_header.empty()) |
237 HandleThrottlingHeader(throttling_header, host); | 237 HandleThrottlingHeader(throttling_header, host); |
238 } | 238 } |
239 } | 239 } |
240 | 240 |
241 void URLRequestThrottlerEntry::ReceivedContentWasMalformed(int response_code) { | 241 void URLRequestThrottlerEntry::ReceivedContentWasMalformed(int response_code) { |
242 // A malformed body can only occur when the request to fetch a resource | 242 // A malformed body can only occur when the request to fetch a resource |
243 // was successful. Therefore, in such a situation, we will receive one | 243 // was successful. Therefore, in such a situation, we will receive one |
244 // call to ReceivedContentWasMalformed() and one call to | 244 // call to ReceivedContentWasMalformed() and one call to |
245 // UpdateWithResponse() with a response categorized as "good". To end | 245 // UpdateWithResponse() with a response categorized as "good". To end |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
279 // 503 is explicitly documented as a temporary state where the server | 279 // 503 is explicitly documented as a temporary state where the server |
280 // is either overloaded or down for maintenance. | 280 // is either overloaded or down for maintenance. |
281 // 509 is the (non-standard but widely implemented) Bandwidth Limit Exceeded | 281 // 509 is the (non-standard but widely implemented) Bandwidth Limit Exceeded |
282 // status code, which might indicate DDoS. | 282 // status code, which might indicate DDoS. |
283 // | 283 // |
284 // We do not back off on 502 or 504, which are reported by gateways | 284 // We do not back off on 502 or 504, which are reported by gateways |
285 // (proxies) on timeouts or failures, because in many cases these requests | 285 // (proxies) on timeouts or failures, because in many cases these requests |
286 // have not made it to the destination server and so we do not actually | 286 // have not made it to the destination server and so we do not actually |
287 // know that it is down or busy. One degenerate case could be a proxy on | 287 // know that it is down or busy. One degenerate case could be a proxy on |
288 // localhost, where you are not actually connected to the network. | 288 // localhost, where you are not actually connected to the network. |
289 return (response_code == 500 || | 289 return (response_code == 500 || response_code == 503 || response_code == 509); |
290 response_code == 503 || | |
291 response_code == 509); | |
292 } | 290 } |
293 | 291 |
294 base::TimeTicks URLRequestThrottlerEntry::ImplGetTimeNow() const { | 292 base::TimeTicks URLRequestThrottlerEntry::ImplGetTimeNow() const { |
295 return base::TimeTicks::Now(); | 293 return base::TimeTicks::Now(); |
296 } | 294 } |
297 | 295 |
298 void URLRequestThrottlerEntry::HandleThrottlingHeader( | 296 void URLRequestThrottlerEntry::HandleThrottlingHeader( |
299 const std::string& header_value, | 297 const std::string& header_value, |
300 const std::string& host) { | 298 const std::string& host) { |
301 if (header_value == kExponentialThrottlingDisableValue) { | 299 if (header_value == kExponentialThrottlingDisableValue) { |
(...skipping 10 matching lines...) Expand all Loading... |
312 BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() { | 310 BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() { |
313 return &backoff_entry_; | 311 return &backoff_entry_; |
314 } | 312 } |
315 | 313 |
316 // static | 314 // static |
317 bool URLRequestThrottlerEntry::ExplicitUserRequest(const int load_flags) { | 315 bool URLRequestThrottlerEntry::ExplicitUserRequest(const int load_flags) { |
318 return (load_flags & LOAD_MAYBE_USER_GESTURE) != 0; | 316 return (load_flags & LOAD_MAYBE_USER_GESTURE) != 0; |
319 } | 317 } |
320 | 318 |
321 } // namespace net | 319 } // namespace net |
OLD | NEW |