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" |
11 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
12 #include "base/rand_util.h" | 12 #include "base/rand_util.h" |
13 #include "base/string_number_conversions.h" | 13 #include "base/string_number_conversions.h" |
14 #include "base/values.h" | 14 #include "base/values.h" |
15 #include "net/base/load_flags.h" | 15 #include "net/base/load_flags.h" |
16 #include "net/base/net_log.h" | 16 #include "net/base/net_log.h" |
17 #include "net/url_request/url_request.h" | |
17 #include "net/url_request/url_request_throttler_header_interface.h" | 18 #include "net/url_request/url_request_throttler_header_interface.h" |
18 #include "net/url_request/url_request_throttler_manager.h" | 19 #include "net/url_request/url_request_throttler_manager.h" |
19 | 20 |
20 namespace net { | 21 namespace net { |
21 | 22 |
22 const int URLRequestThrottlerEntry::kDefaultSlidingWindowPeriodMs = 2000; | 23 const int URLRequestThrottlerEntry::kDefaultSlidingWindowPeriodMs = 2000; |
23 const int URLRequestThrottlerEntry::kDefaultMaxSendThreshold = 20; | 24 const int URLRequestThrottlerEntry::kDefaultMaxSendThreshold = 20; |
24 | 25 |
25 // This set of back-off parameters will (at maximum values, i.e. without | 26 // This set of back-off parameters will (at maximum values, i.e. without |
26 // the reduction caused by jitter) add 0-41% (distributed uniformly | 27 // the reduction caused by jitter) add 0-41% (distributed uniformly |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
131 bool URLRequestThrottlerEntry::IsEntryOutdated() const { | 132 bool URLRequestThrottlerEntry::IsEntryOutdated() const { |
132 // This function is called by the URLRequestThrottlerManager to determine | 133 // This function is called by the URLRequestThrottlerManager to determine |
133 // whether entries should be discarded from its url_entries_ map. We | 134 // whether entries should be discarded from its url_entries_ map. We |
134 // want to ensure that it does not remove entries from the map while there | 135 // want to ensure that it does not remove entries from the map while there |
135 // are clients (objects other than the manager) holding references to | 136 // are clients (objects other than the manager) holding references to |
136 // the entry, otherwise separate clients could end up holding separate | 137 // the entry, otherwise separate clients could end up holding separate |
137 // entries for a request to the same URL, which is undesirable. Therefore, | 138 // entries for a request to the same URL, which is undesirable. Therefore, |
138 // if an entry has more than one reference (the map will always hold one), | 139 // if an entry has more than one reference (the map will always hold one), |
139 // it should not be considered outdated. | 140 // it should not be considered outdated. |
140 // | 141 // |
141 // TODO(joi): Once the manager is not a Singleton, revisit whether | 142 // We considered whether to make URLRequestThrottlerEntry objects |
142 // refcounting is needed at all. | 143 // non-refcounted, but since any means of knowing whether they are |
144 // currently in use by others than the manager would be more or less | |
145 // equivalent to a refcount, we kept them refcounted. | |
143 if (!HasOneRef()) | 146 if (!HasOneRef()) |
144 return false; | 147 return false; |
145 | 148 |
146 // If there are send events in the sliding window period, we still need this | 149 // If there are send events in the sliding window period, we still need this |
147 // entry. | 150 // entry. |
148 if (!send_log_.empty() && | 151 if (!send_log_.empty() && |
149 send_log_.back() + sliding_window_period_ > ImplGetTimeNow()) { | 152 send_log_.back() + sliding_window_period_ > ImplGetTimeNow()) { |
150 return false; | 153 return false; |
151 } | 154 } |
152 | 155 |
153 return GetBackoffEntry()->CanDiscard(); | 156 return GetBackoffEntry()->CanDiscard(); |
154 } | 157 } |
155 | 158 |
156 void URLRequestThrottlerEntry::DisableBackoffThrottling() { | 159 void URLRequestThrottlerEntry::DisableBackoffThrottling() { |
157 is_backoff_disabled_ = true; | 160 is_backoff_disabled_ = true; |
eroman
2012/06/06 04:52:11
Is this still used?
Jói
2012/06/06 13:38:55
Yes, this is separate from the global flag; it's a
| |
158 } | 161 } |
159 | 162 |
160 void URLRequestThrottlerEntry::DetachManager() { | 163 void URLRequestThrottlerEntry::DetachManager() { |
161 manager_ = NULL; | 164 manager_ = NULL; |
162 } | 165 } |
163 | 166 |
164 bool URLRequestThrottlerEntry::ShouldRejectRequest(int load_flags) const { | 167 bool URLRequestThrottlerEntry::ShouldRejectRequest(const URLRequest* request, |
168 int load_flags) const { | |
165 bool reject_request = false; | 169 bool reject_request = false; |
166 if (!is_backoff_disabled_ && !ExplicitUserRequest(load_flags) && | 170 if (!is_backoff_disabled_ && !ExplicitUserRequest(load_flags) && |
171 (!request || !request->context() || | |
172 request->context()->network_delegate()->CanRejectRequest(*request)) && | |
eroman
2012/06/06 04:52:11
Is it possible for network_delegate() to be NULL (
Jói
2012/06/06 13:38:55
So say the trybots :) Added that to the check.
| |
167 GetBackoffEntry()->ShouldRejectRequest()) { | 173 GetBackoffEntry()->ShouldRejectRequest()) { |
168 int num_failures = GetBackoffEntry()->failure_count(); | 174 int num_failures = GetBackoffEntry()->failure_count(); |
169 int release_after_ms = | 175 int release_after_ms = |
170 GetBackoffEntry()->GetTimeUntilRelease().InMilliseconds(); | 176 GetBackoffEntry()->GetTimeUntilRelease().InMilliseconds(); |
171 | 177 |
172 net_log_.AddEvent( | 178 net_log_.AddEvent( |
173 NetLog::TYPE_THROTTLING_REJECTED_REQUEST, | 179 NetLog::TYPE_THROTTLING_REJECTED_REQUEST, |
174 make_scoped_refptr( | 180 make_scoped_refptr( |
175 new RejectedRequestParameters(url_id_, | 181 new RejectedRequestParameters(url_id_, |
176 num_failures, | 182 num_failures, |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
230 // return "now" so that retries are not delayed. | 236 // return "now" so that retries are not delayed. |
231 if (is_backoff_disabled_) | 237 if (is_backoff_disabled_) |
232 return ImplGetTimeNow(); | 238 return ImplGetTimeNow(); |
233 | 239 |
234 return GetBackoffEntry()->GetReleaseTime(); | 240 return GetBackoffEntry()->GetReleaseTime(); |
235 } | 241 } |
236 | 242 |
237 void URLRequestThrottlerEntry::UpdateWithResponse( | 243 void URLRequestThrottlerEntry::UpdateWithResponse( |
238 const std::string& host, | 244 const std::string& host, |
239 const URLRequestThrottlerHeaderInterface* response) { | 245 const URLRequestThrottlerHeaderInterface* response) { |
240 int response_code = response->GetResponseCode(); | 246 if (IsConsideredError(response->GetResponseCode())) { |
241 HandleMetricsTracking(response_code); | |
242 | |
243 if (IsConsideredError(response_code)) { | |
244 GetBackoffEntry()->InformOfRequest(false); | 247 GetBackoffEntry()->InformOfRequest(false); |
245 } else { | 248 } else { |
246 GetBackoffEntry()->InformOfRequest(true); | 249 GetBackoffEntry()->InformOfRequest(true); |
247 | 250 |
248 std::string throttling_header = response->GetNormalizedValue( | 251 std::string throttling_header = response->GetNormalizedValue( |
249 kExponentialThrottlingHeader); | 252 kExponentialThrottlingHeader); |
250 if (!throttling_header.empty()) | 253 if (!throttling_header.empty()) |
251 HandleThrottlingHeader(throttling_header, host); | 254 HandleThrottlingHeader(throttling_header, host); |
252 } | 255 } |
253 } | 256 } |
(...skipping 19 matching lines...) Expand all Loading... | |
273 | 276 |
274 void URLRequestThrottlerEntry::Initialize() { | 277 void URLRequestThrottlerEntry::Initialize() { |
275 sliding_window_release_time_ = base::TimeTicks::Now(); | 278 sliding_window_release_time_ = base::TimeTicks::Now(); |
276 backoff_policy_.num_errors_to_ignore = kDefaultNumErrorsToIgnore; | 279 backoff_policy_.num_errors_to_ignore = kDefaultNumErrorsToIgnore; |
277 backoff_policy_.initial_delay_ms = kDefaultInitialDelayMs; | 280 backoff_policy_.initial_delay_ms = kDefaultInitialDelayMs; |
278 backoff_policy_.multiply_factor = kDefaultMultiplyFactor; | 281 backoff_policy_.multiply_factor = kDefaultMultiplyFactor; |
279 backoff_policy_.jitter_factor = kDefaultJitterFactor; | 282 backoff_policy_.jitter_factor = kDefaultJitterFactor; |
280 backoff_policy_.maximum_backoff_ms = kDefaultMaximumBackoffMs; | 283 backoff_policy_.maximum_backoff_ms = kDefaultMaximumBackoffMs; |
281 backoff_policy_.entry_lifetime_ms = kDefaultEntryLifetimeMs; | 284 backoff_policy_.entry_lifetime_ms = kDefaultEntryLifetimeMs; |
282 backoff_policy_.always_use_initial_delay = false; | 285 backoff_policy_.always_use_initial_delay = false; |
283 | |
284 // We pretend we just had a successful response so that we have a | |
285 // starting point to our tracking. This is called from the | |
286 // constructor so we do not use the virtual ImplGetTimeNow(). | |
287 last_successful_response_time_ = base::TimeTicks::Now(); | |
288 last_response_was_success_ = true; | |
289 } | 286 } |
290 | 287 |
291 bool URLRequestThrottlerEntry::IsConsideredError(int response_code) { | 288 bool URLRequestThrottlerEntry::IsConsideredError(int response_code) { |
292 // We throttle only for the status codes most likely to indicate the server | 289 // We throttle only for the status codes most likely to indicate the server |
293 // is failing because it is too busy or otherwise are likely to be | 290 // is failing because it is too busy or otherwise are likely to be |
294 // because of DDoS. | 291 // because of DDoS. |
295 // | 292 // |
296 // 500 is the generic error when no better message is suitable, and | 293 // 500 is the generic error when no better message is suitable, and |
297 // as such does not necessarily indicate a temporary state, but | 294 // as such does not necessarily indicate a temporary state, but |
298 // other status codes cover most of the permanent error states. | 295 // other status codes cover most of the permanent error states. |
(...skipping 16 matching lines...) Expand all Loading... | |
315 return base::TimeTicks::Now(); | 312 return base::TimeTicks::Now(); |
316 } | 313 } |
317 | 314 |
318 void URLRequestThrottlerEntry::HandleThrottlingHeader( | 315 void URLRequestThrottlerEntry::HandleThrottlingHeader( |
319 const std::string& header_value, | 316 const std::string& header_value, |
320 const std::string& host) { | 317 const std::string& host) { |
321 if (header_value == kExponentialThrottlingDisableValue) { | 318 if (header_value == kExponentialThrottlingDisableValue) { |
322 DisableBackoffThrottling(); | 319 DisableBackoffThrottling(); |
323 if (manager_) | 320 if (manager_) |
324 manager_->AddToOptOutList(host); | 321 manager_->AddToOptOutList(host); |
325 } else { | |
326 // TODO(joi): Log this. | |
327 } | 322 } |
328 } | 323 } |
329 | 324 |
330 void URLRequestThrottlerEntry::HandleMetricsTracking(int response_code) { | |
331 // Note that we are not interested in whether the code is considered | |
332 // an error for the backoff logic, but whether it is a 5xx error in | |
333 // general. This is because here, we are tracking the apparent total | |
334 // downtime of a server. | |
335 if (response_code >= 500) { | |
336 last_response_was_success_ = false; | |
337 } else { | |
338 base::TimeTicks now = ImplGetTimeNow(); | |
339 if (!last_response_was_success_) { | |
340 // We are transitioning from failure to success, so generate our stats. | |
341 base::TimeDelta down_time = now - last_successful_response_time_; | |
342 int failure_count = GetBackoffEntry()->failure_count(); | |
343 | |
344 UMA_HISTOGRAM_COUNTS("Throttling.FailureCountAtSuccess", failure_count); | |
345 UMA_HISTOGRAM_CUSTOM_TIMES( | |
346 "Throttling.PerceivedDowntime", down_time, | |
347 base::TimeDelta::FromMilliseconds(10), | |
348 base::TimeDelta::FromHours(6), 50); | |
349 } | |
350 | |
351 last_successful_response_time_ = now; | |
352 last_response_was_success_ = true; | |
353 } | |
354 } | |
355 | |
356 const BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() const { | 325 const BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() const { |
357 return &backoff_entry_; | 326 return &backoff_entry_; |
358 } | 327 } |
359 | 328 |
360 BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() { | 329 BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() { |
361 return &backoff_entry_; | 330 return &backoff_entry_; |
362 } | 331 } |
363 | 332 |
364 // static | 333 // static |
365 bool URLRequestThrottlerEntry::ExplicitUserRequest(const int load_flags) { | 334 bool URLRequestThrottlerEntry::ExplicitUserRequest(const int load_flags) { |
366 return (load_flags & LOAD_MAYBE_USER_GESTURE) != 0; | 335 return (load_flags & LOAD_MAYBE_USER_GESTURE) != 0; |
367 } | 336 } |
368 | 337 |
369 } // namespace net | 338 } // namespace net |
OLD | NEW |