OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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" |
| 11 #include "base/metrics/histogram.h" |
10 #include "base/rand_util.h" | 12 #include "base/rand_util.h" |
11 #include "base/string_number_conversions.h" | 13 #include "base/string_number_conversions.h" |
| 14 #include "base/values.h" |
| 15 #include "net/base/net_log.h" |
12 #include "net/url_request/url_request_throttler_header_interface.h" | 16 #include "net/url_request/url_request_throttler_header_interface.h" |
13 #include "net/url_request/url_request_throttler_manager.h" | 17 #include "net/url_request/url_request_throttler_manager.h" |
14 | 18 |
15 namespace net { | 19 namespace net { |
16 | 20 |
17 const int URLRequestThrottlerEntry::kDefaultSlidingWindowPeriodMs = 2000; | 21 const int URLRequestThrottlerEntry::kDefaultSlidingWindowPeriodMs = 2000; |
18 const int URLRequestThrottlerEntry::kDefaultMaxSendThreshold = 20; | 22 const int URLRequestThrottlerEntry::kDefaultMaxSendThreshold = 20; |
19 | 23 |
20 // This set of back-off parameters will (at maximum values, i.e. without | 24 // This set of back-off parameters will (at maximum values, i.e. without |
21 // the reduction caused by jitter) add 0-41% (distributed uniformly | 25 // the reduction caused by jitter) add 0-41% (distributed uniformly |
22 // in that range) to the "perceived downtime" of the remote server, once | 26 // in that range) to the "perceived downtime" of the remote server, once |
23 // exponential back-off kicks in and is throttling requests for more than | 27 // exponential back-off kicks in and is throttling requests for more than |
24 // about a second at a time. Once the maximum back-off is reached, the added | 28 // about a second at a time. Once the maximum back-off is reached, the added |
25 // perceived downtime decreases rapidly, percentage-wise. | 29 // perceived downtime decreases rapidly, percentage-wise. |
26 // | 30 // |
27 // Another way to put it is that the maximum additional perceived downtime | 31 // Another way to put it is that the maximum additional perceived downtime |
28 // with these numbers is a couple of seconds shy of 15 minutes, and such | 32 // with these numbers is a couple of seconds shy of 15 minutes, and such |
29 // a delay would not occur until the remote server has been actually | 33 // a delay would not occur until the remote server has been actually |
30 // unavailable at the end of each back-off period for a total of about | 34 // unavailable at the end of each back-off period for a total of about |
31 // 48 minutes. | 35 // 48 minutes. |
32 // | 36 // |
33 // Ignoring the first 4 errors helps avoid back-off from kicking in on | 37 // Ignoring the first couple of errors is just a conservative measure to |
34 // flaky connections. | 38 // avoid false positives. It should help avoid back-off from kicking in e.g. |
35 const int URLRequestThrottlerEntry::kDefaultNumErrorsToIgnore = 4; | 39 // on flaky connections. |
| 40 const int URLRequestThrottlerEntry::kDefaultNumErrorsToIgnore = 2; |
36 const int URLRequestThrottlerEntry::kDefaultInitialBackoffMs = 700; | 41 const int URLRequestThrottlerEntry::kDefaultInitialBackoffMs = 700; |
37 const double URLRequestThrottlerEntry::kDefaultMultiplyFactor = 1.4; | 42 const double URLRequestThrottlerEntry::kDefaultMultiplyFactor = 1.4; |
38 const double URLRequestThrottlerEntry::kDefaultJitterFactor = 0.4; | 43 const double URLRequestThrottlerEntry::kDefaultJitterFactor = 0.4; |
39 const int URLRequestThrottlerEntry::kDefaultMaximumBackoffMs = 15 * 60 * 1000; | 44 const int URLRequestThrottlerEntry::kDefaultMaximumBackoffMs = 15 * 60 * 1000; |
40 const int URLRequestThrottlerEntry::kDefaultEntryLifetimeMs = 2 * 60 * 1000; | 45 const int URLRequestThrottlerEntry::kDefaultEntryLifetimeMs = 2 * 60 * 1000; |
41 const char URLRequestThrottlerEntry::kRetryHeaderName[] = "X-Retry-After"; | 46 const char URLRequestThrottlerEntry::kRetryHeaderName[] = "X-Retry-After"; |
42 const char URLRequestThrottlerEntry::kExponentialThrottlingHeader[] = | 47 const char URLRequestThrottlerEntry::kExponentialThrottlingHeader[] = |
43 "X-Chrome-Exponential-Throttling"; | 48 "X-Chrome-Exponential-Throttling"; |
44 const char URLRequestThrottlerEntry::kExponentialThrottlingDisableValue[] = | 49 const char URLRequestThrottlerEntry::kExponentialThrottlingDisableValue[] = |
45 "disable"; | 50 "disable"; |
46 | 51 |
| 52 // NetLog parameters when a request is rejected by throttling. |
| 53 class RejectedRequestParameters : public NetLog::EventParameters { |
| 54 public: |
| 55 RejectedRequestParameters(const std::string& url_id, |
| 56 int num_failures, |
| 57 int release_after_ms) |
| 58 : url_id_(url_id), |
| 59 num_failures_(num_failures), |
| 60 release_after_ms_(release_after_ms) { |
| 61 } |
| 62 |
| 63 virtual Value* ToValue() const { |
| 64 DictionaryValue* dict = new DictionaryValue(); |
| 65 dict->SetString("url", url_id_); |
| 66 dict->SetInteger("num_failures", num_failures_); |
| 67 dict->SetInteger("release_after_ms", release_after_ms_); |
| 68 return dict; |
| 69 } |
| 70 |
| 71 private: |
| 72 std::string url_id_; |
| 73 int num_failures_; |
| 74 int release_after_ms_; |
| 75 }; |
| 76 |
| 77 // NetLog parameters when a response contains an X-Retry-After header. |
| 78 class RetryAfterParameters : public NetLog::EventParameters { |
| 79 public: |
| 80 RetryAfterParameters(const std::string& url_id, |
| 81 int retry_after_ms) |
| 82 : url_id_(url_id), |
| 83 retry_after_ms_(retry_after_ms) { |
| 84 } |
| 85 |
| 86 virtual Value* ToValue() const { |
| 87 DictionaryValue* dict = new DictionaryValue(); |
| 88 dict->SetString("url", url_id_); |
| 89 dict->SetInteger("retry_after_ms", retry_after_ms_); |
| 90 return dict; |
| 91 } |
| 92 |
| 93 private: |
| 94 std::string url_id_; |
| 95 int retry_after_ms_; |
| 96 }; |
| 97 |
47 URLRequestThrottlerEntry::URLRequestThrottlerEntry( | 98 URLRequestThrottlerEntry::URLRequestThrottlerEntry( |
48 URLRequestThrottlerManager* manager) | 99 URLRequestThrottlerManager* manager, |
| 100 const std::string& url_id) |
49 : sliding_window_period_( | 101 : sliding_window_period_( |
50 base::TimeDelta::FromMilliseconds(kDefaultSlidingWindowPeriodMs)), | 102 base::TimeDelta::FromMilliseconds(kDefaultSlidingWindowPeriodMs)), |
51 max_send_threshold_(kDefaultMaxSendThreshold), | 103 max_send_threshold_(kDefaultMaxSendThreshold), |
52 is_backoff_disabled_(false), | 104 is_backoff_disabled_(false), |
53 backoff_entry_(&backoff_policy_), | 105 backoff_entry_(&backoff_policy_), |
54 manager_(manager) { | 106 manager_(manager), |
| 107 url_id_(url_id), |
| 108 net_log_(BoundNetLog::Make( |
| 109 manager->net_log(), NetLog::SOURCE_EXPONENTIAL_BACKOFF_THROTTLING)) { |
55 DCHECK(manager_); | 110 DCHECK(manager_); |
56 Initialize(); | 111 Initialize(); |
57 } | 112 } |
58 | 113 |
59 URLRequestThrottlerEntry::URLRequestThrottlerEntry( | 114 URLRequestThrottlerEntry::URLRequestThrottlerEntry( |
60 URLRequestThrottlerManager* manager, | 115 URLRequestThrottlerManager* manager, |
| 116 const std::string& url_id, |
61 int sliding_window_period_ms, | 117 int sliding_window_period_ms, |
62 int max_send_threshold, | 118 int max_send_threshold, |
63 int initial_backoff_ms, | 119 int initial_backoff_ms, |
64 double multiply_factor, | 120 double multiply_factor, |
65 double jitter_factor, | 121 double jitter_factor, |
66 int maximum_backoff_ms) | 122 int maximum_backoff_ms) |
67 : sliding_window_period_( | 123 : sliding_window_period_( |
68 base::TimeDelta::FromMilliseconds(sliding_window_period_ms)), | 124 base::TimeDelta::FromMilliseconds(sliding_window_period_ms)), |
69 max_send_threshold_(max_send_threshold), | 125 max_send_threshold_(max_send_threshold), |
70 is_backoff_disabled_(false), | 126 is_backoff_disabled_(false), |
71 backoff_entry_(&backoff_policy_), | 127 backoff_entry_(&backoff_policy_), |
72 manager_(manager) { | 128 manager_(manager), |
| 129 url_id_(url_id) { |
73 DCHECK_GT(sliding_window_period_ms, 0); | 130 DCHECK_GT(sliding_window_period_ms, 0); |
74 DCHECK_GT(max_send_threshold_, 0); | 131 DCHECK_GT(max_send_threshold_, 0); |
75 DCHECK_GE(initial_backoff_ms, 0); | 132 DCHECK_GE(initial_backoff_ms, 0); |
76 DCHECK_GT(multiply_factor, 0); | 133 DCHECK_GT(multiply_factor, 0); |
77 DCHECK_GE(jitter_factor, 0.0); | 134 DCHECK_GE(jitter_factor, 0.0); |
78 DCHECK_LT(jitter_factor, 1.0); | 135 DCHECK_LT(jitter_factor, 1.0); |
79 DCHECK_GE(maximum_backoff_ms, 0); | 136 DCHECK_GE(maximum_backoff_ms, 0); |
80 DCHECK(manager_); | 137 DCHECK(manager_); |
81 | 138 |
82 Initialize(); | 139 Initialize(); |
(...skipping 16 matching lines...) Expand all Loading... |
99 // it should not be considered outdated. | 156 // it should not be considered outdated. |
100 // | 157 // |
101 // TODO(joi): Once the manager is not a Singleton, revisit whether | 158 // TODO(joi): Once the manager is not a Singleton, revisit whether |
102 // refcounting is needed at all. | 159 // refcounting is needed at all. |
103 if (!HasOneRef()) | 160 if (!HasOneRef()) |
104 return false; | 161 return false; |
105 | 162 |
106 // If there are send events in the sliding window period, we still need this | 163 // If there are send events in the sliding window period, we still need this |
107 // entry. | 164 // entry. |
108 if (!send_log_.empty() && | 165 if (!send_log_.empty() && |
109 send_log_.back() + sliding_window_period_ > GetTimeNow()) { | 166 send_log_.back() + sliding_window_period_ > ImplGetTimeNow()) { |
110 return false; | 167 return false; |
111 } | 168 } |
112 | 169 |
113 return GetBackoffEntry()->CanDiscard(); | 170 return GetBackoffEntry()->CanDiscard(); |
114 } | 171 } |
115 | 172 |
116 void URLRequestThrottlerEntry::DisableBackoffThrottling() { | 173 void URLRequestThrottlerEntry::DisableBackoffThrottling() { |
117 is_backoff_disabled_ = true; | 174 is_backoff_disabled_ = true; |
118 } | 175 } |
119 | 176 |
120 void URLRequestThrottlerEntry::DetachManager() { | 177 void URLRequestThrottlerEntry::DetachManager() { |
121 manager_ = NULL; | 178 manager_ = NULL; |
122 } | 179 } |
123 | 180 |
124 bool URLRequestThrottlerEntry::IsDuringExponentialBackoff() const { | 181 bool URLRequestThrottlerEntry::IsDuringExponentialBackoff() const { |
125 if (is_backoff_disabled_) | 182 bool reject_request = false; |
126 return false; | 183 if (!is_backoff_disabled_ && GetBackoffEntry()->ShouldRejectRequest()) { |
| 184 int num_failures = GetBackoffEntry()->failure_count(); |
| 185 int release_after_ms = |
| 186 (GetBackoffEntry()->GetReleaseTime() - base::TimeTicks::Now()) |
| 187 .InMilliseconds(); |
127 | 188 |
128 return GetBackoffEntry()->ShouldRejectRequest(); | 189 net_log_.AddEvent( |
| 190 NetLog::TYPE_THROTTLING_REJECTED_REQUEST, |
| 191 make_scoped_refptr( |
| 192 new RejectedRequestParameters(url_id_, |
| 193 num_failures, |
| 194 release_after_ms))); |
| 195 |
| 196 reject_request = true; |
| 197 } |
| 198 |
| 199 int reject_count = reject_request ? 1 : 0; |
| 200 UMA_HISTOGRAM_ENUMERATION( |
| 201 "Throttling.RequestThrottled", reject_count, 2); |
| 202 if (base::FieldTrialList::TrialExists("ThrottlingEnabled")) { |
| 203 UMA_HISTOGRAM_ENUMERATION(base::FieldTrial::MakeName( |
| 204 "Throttling.RequestThrottled", "ThrottlingEnabled"), reject_count, 2); |
| 205 } |
| 206 |
| 207 return reject_request; |
129 } | 208 } |
130 | 209 |
131 int64 URLRequestThrottlerEntry::ReserveSendingTimeForNextRequest( | 210 int64 URLRequestThrottlerEntry::ReserveSendingTimeForNextRequest( |
132 const base::TimeTicks& earliest_time) { | 211 const base::TimeTicks& earliest_time) { |
133 base::TimeTicks now = GetTimeNow(); | 212 base::TimeTicks now = ImplGetTimeNow(); |
134 | 213 |
135 // If a lot of requests were successfully made recently, | 214 // If a lot of requests were successfully made recently, |
136 // sliding_window_release_time_ may be greater than | 215 // sliding_window_release_time_ may be greater than |
137 // exponential_backoff_release_time_. | 216 // exponential_backoff_release_time_. |
138 base::TimeTicks recommended_sending_time = | 217 base::TimeTicks recommended_sending_time = |
139 std::max(std::max(now, earliest_time), | 218 std::max(std::max(now, earliest_time), |
140 std::max(GetBackoffEntry()->GetReleaseTime(), | 219 std::max(GetBackoffEntry()->GetReleaseTime(), |
141 sliding_window_release_time_)); | 220 sliding_window_release_time_)); |
142 | 221 |
143 DCHECK(send_log_.empty() || | 222 DCHECK(send_log_.empty() || |
(...skipping 20 matching lines...) Expand all Loading... |
164 } | 243 } |
165 | 244 |
166 base::TimeTicks | 245 base::TimeTicks |
167 URLRequestThrottlerEntry::GetExponentialBackoffReleaseTime() const { | 246 URLRequestThrottlerEntry::GetExponentialBackoffReleaseTime() const { |
168 // If a site opts out, it's likely because they have problems that trigger | 247 // If a site opts out, it's likely because they have problems that trigger |
169 // the back-off mechanism when it shouldn't be triggered, in which case | 248 // the back-off mechanism when it shouldn't be triggered, in which case |
170 // returning the calculated back-off release time would probably be the | 249 // returning the calculated back-off release time would probably be the |
171 // wrong thing to do (i.e. it would likely be too long). Therefore, we | 250 // wrong thing to do (i.e. it would likely be too long). Therefore, we |
172 // return "now" so that retries are not delayed. | 251 // return "now" so that retries are not delayed. |
173 if (is_backoff_disabled_) | 252 if (is_backoff_disabled_) |
174 return GetTimeNow(); | 253 return ImplGetTimeNow(); |
175 | 254 |
176 return GetBackoffEntry()->GetReleaseTime(); | 255 return GetBackoffEntry()->GetReleaseTime(); |
177 } | 256 } |
178 | 257 |
179 void URLRequestThrottlerEntry::UpdateWithResponse( | 258 void URLRequestThrottlerEntry::UpdateWithResponse( |
180 const std::string& host, | 259 const std::string& host, |
181 const URLRequestThrottlerHeaderInterface* response) { | 260 const URLRequestThrottlerHeaderInterface* response) { |
182 if (response->GetResponseCode() >= 500) { | 261 int response_code = response->GetResponseCode(); |
| 262 HandleMetricsTracking(response_code); |
| 263 |
| 264 if (IsConsideredError(response_code)) { |
183 GetBackoffEntry()->InformOfRequest(false); | 265 GetBackoffEntry()->InformOfRequest(false); |
184 } else { | 266 } else { |
185 GetBackoffEntry()->InformOfRequest(true); | 267 GetBackoffEntry()->InformOfRequest(true); |
186 | 268 |
187 std::string retry_header = response->GetNormalizedValue(kRetryHeaderName); | 269 std::string retry_header = response->GetNormalizedValue(kRetryHeaderName); |
188 if (!retry_header.empty()) | 270 if (!retry_header.empty()) |
189 HandleCustomRetryAfter(retry_header); | 271 HandleCustomRetryAfter(retry_header); |
190 | 272 |
191 std::string throttling_header = response->GetNormalizedValue( | 273 std::string throttling_header = response->GetNormalizedValue( |
192 kExponentialThrottlingHeader); | 274 kExponentialThrottlingHeader); |
193 if (!throttling_header.empty()) | 275 if (!throttling_header.empty()) |
194 HandleThrottlingHeader(throttling_header, host); | 276 HandleThrottlingHeader(throttling_header, host); |
195 } | 277 } |
196 } | 278 } |
197 | 279 |
198 void URLRequestThrottlerEntry::ReceivedContentWasMalformed() { | 280 void URLRequestThrottlerEntry::ReceivedContentWasMalformed(int response_code) { |
199 // A malformed body can only occur when the request to fetch a resource | 281 // A malformed body can only occur when the request to fetch a resource |
200 // was successful. Therefore, in such a situation, we will receive one | 282 // was successful. Therefore, in such a situation, we will receive one |
201 // call to ReceivedContentWasMalformed() and one call to UpdateWithResponse() | 283 // call to ReceivedContentWasMalformed() and one call to |
202 // with a response categorized as "good". To end up counting one failure, | 284 // UpdateWithResponse() with a response categorized as "good". To end |
203 // we need to count two failures here against the one success in | 285 // up counting one failure, we need to count two failures here against |
204 // UpdateWithResponse(). | 286 // the one success in UpdateWithResponse(). |
205 GetBackoffEntry()->InformOfRequest(false); | 287 // |
206 GetBackoffEntry()->InformOfRequest(false); | 288 // We do nothing for a response that is already being considered an error |
| 289 // based on its status code (otherwise we would count 3 errors instead of 1). |
| 290 if (!IsConsideredError(response_code)) { |
| 291 GetBackoffEntry()->InformOfRequest(false); |
| 292 GetBackoffEntry()->InformOfRequest(false); |
| 293 } |
207 } | 294 } |
208 | 295 |
209 URLRequestThrottlerEntry::~URLRequestThrottlerEntry() { | 296 URLRequestThrottlerEntry::~URLRequestThrottlerEntry() { |
210 } | 297 } |
211 | 298 |
212 void URLRequestThrottlerEntry::Initialize() { | 299 void URLRequestThrottlerEntry::Initialize() { |
213 sliding_window_release_time_ = base::TimeTicks::Now(); | 300 sliding_window_release_time_ = base::TimeTicks::Now(); |
214 backoff_policy_.num_errors_to_ignore = kDefaultNumErrorsToIgnore; | 301 backoff_policy_.num_errors_to_ignore = kDefaultNumErrorsToIgnore; |
215 backoff_policy_.initial_backoff_ms = kDefaultInitialBackoffMs; | 302 backoff_policy_.initial_backoff_ms = kDefaultInitialBackoffMs; |
216 backoff_policy_.multiply_factor = kDefaultMultiplyFactor; | 303 backoff_policy_.multiply_factor = kDefaultMultiplyFactor; |
217 backoff_policy_.jitter_factor = kDefaultJitterFactor; | 304 backoff_policy_.jitter_factor = kDefaultJitterFactor; |
218 backoff_policy_.maximum_backoff_ms = kDefaultMaximumBackoffMs; | 305 backoff_policy_.maximum_backoff_ms = kDefaultMaximumBackoffMs; |
219 backoff_policy_.entry_lifetime_ms = kDefaultEntryLifetimeMs; | 306 backoff_policy_.entry_lifetime_ms = kDefaultEntryLifetimeMs; |
| 307 |
| 308 // We pretend we just had a successful response so that we have a |
| 309 // starting point to our tracking. This is called from the |
| 310 // constructor so we do not use the virtual ImplGetTimeNow(). |
| 311 last_successful_response_time_ = base::TimeTicks::Now(); |
| 312 last_response_was_success_ = true; |
220 } | 313 } |
221 | 314 |
222 base::TimeTicks URLRequestThrottlerEntry::GetTimeNow() const { | 315 bool URLRequestThrottlerEntry::IsConsideredError(int response_code) { |
| 316 // We throttle only for the status codes most likely to indicate the server |
| 317 // is failing because it is too busy or otherwise are likely to be |
| 318 // because of DDoS. |
| 319 // |
| 320 // 500 is the generic error when no better message is suitable, and |
| 321 // as such does not necessarily indicate a temporary state, but |
| 322 // other status codes cover most of the permanent error states. |
| 323 // 503 is explicitly documented as a temporary state where the server |
| 324 // is either overloaded or down for maintenance. |
| 325 // 509 is the (non-standard but widely implemented) Bandwidth Limit Exceeded |
| 326 // status code, which might indicate DDoS. |
| 327 // |
| 328 // We do not back off on 502 or 504, which are reported by gateways |
| 329 // (proxies) on timeouts or failures, because in many cases these requests |
| 330 // have not made it to the destination server and so we do not actually |
| 331 // know that it is down or busy. One degenerate case could be a proxy on |
| 332 // localhost, where you are not actually connected to the network. |
| 333 return (response_code == 500 || |
| 334 response_code == 503 || |
| 335 response_code == 509); |
| 336 } |
| 337 |
| 338 base::TimeTicks URLRequestThrottlerEntry::ImplGetTimeNow() const { |
223 return base::TimeTicks::Now(); | 339 return base::TimeTicks::Now(); |
224 } | 340 } |
225 | 341 |
226 void URLRequestThrottlerEntry::HandleCustomRetryAfter( | 342 void URLRequestThrottlerEntry::HandleCustomRetryAfter( |
227 const std::string& header_value) { | 343 const std::string& header_value) { |
228 // Input parameter is the number of seconds to wait in a floating point value. | 344 // Input parameter is the number of seconds to wait in a floating point value. |
229 double time_in_sec = 0; | 345 double time_in_sec = 0; |
230 bool conversion_is_ok = base::StringToDouble(header_value, &time_in_sec); | 346 bool conversion_is_ok = base::StringToDouble(header_value, &time_in_sec); |
231 | 347 |
232 // Conversion of custom retry-after header value failed. | 348 // Conversion of custom retry-after header value failed. |
233 if (!conversion_is_ok) | 349 if (!conversion_is_ok) |
234 return; | 350 return; |
235 | 351 |
236 // We must use an int value later so we transform this in milliseconds. | 352 // We must use an int value later so we transform this in milliseconds. |
237 int64 value_ms = static_cast<int64>(0.5 + time_in_sec * 1000); | 353 int64 value_ms = static_cast<int64>(0.5 + time_in_sec * 1000); |
238 | 354 |
239 // We do not check for an upper bound; the server can set any Retry-After it | 355 // We do not check for an upper bound; the server can set any Retry-After it |
240 // desires. Recovery from error would involve restarting the browser. | 356 // desires. Recovery from error would involve restarting the browser. |
241 if (value_ms < 0) | 357 if (value_ms < 0) |
242 return; | 358 return; |
243 | 359 |
244 GetBackoffEntry()->SetCustomReleaseTime( | 360 net_log_.AddEvent( |
245 GetTimeNow() + base::TimeDelta::FromMilliseconds(value_ms)); | 361 NetLog::TYPE_THROTTLING_GOT_CUSTOM_RETRY_AFTER, |
| 362 make_scoped_refptr(new RetryAfterParameters(url_id_, value_ms))); |
| 363 |
| 364 base::TimeDelta value = base::TimeDelta::FromMilliseconds(value_ms); |
| 365 GetBackoffEntry()->SetCustomReleaseTime(ImplGetTimeNow() + value); |
| 366 |
| 367 UMA_HISTOGRAM_CUSTOM_TIMES( |
| 368 "Throttling.CustomRetryAfterMs", value, |
| 369 base::TimeDelta::FromSeconds(1), base::TimeDelta::FromHours(12), 50); |
| 370 if (base::FieldTrialList::TrialExists("ThrottlingEnabled")) { |
| 371 UMA_HISTOGRAM_CUSTOM_TIMES( |
| 372 base::FieldTrial::MakeName("Throttling.CustomRetryAfterMs", |
| 373 "ThrottlingEnabled"), value, |
| 374 base::TimeDelta::FromSeconds(1), base::TimeDelta::FromHours(12), 50); |
| 375 } |
246 } | 376 } |
247 | 377 |
248 void URLRequestThrottlerEntry::HandleThrottlingHeader( | 378 void URLRequestThrottlerEntry::HandleThrottlingHeader( |
249 const std::string& header_value, | 379 const std::string& header_value, |
250 const std::string& host) { | 380 const std::string& host) { |
251 if (header_value == kExponentialThrottlingDisableValue) { | 381 if (header_value == kExponentialThrottlingDisableValue) { |
252 DisableBackoffThrottling(); | 382 DisableBackoffThrottling(); |
253 if (manager_) | 383 if (manager_) |
254 manager_->AddToOptOutList(host); | 384 manager_->AddToOptOutList(host); |
255 } else { | 385 } else { |
256 // TODO(joi): Log this. | 386 // TODO(joi): Log this. |
257 } | 387 } |
258 } | 388 } |
259 | 389 |
| 390 void URLRequestThrottlerEntry::HandleMetricsTracking(int response_code) { |
| 391 // This is essentially the same as the "Net.HttpResponseCode" UMA stat |
| 392 // but we are tracking it separately here for the throttling experiment |
| 393 // to make sure we count only the responses seen by throttling. |
| 394 // TODO(joi): Remove after experiment. |
| 395 UMA_HISTOGRAM_ENUMERATION("Throttling.HttpResponseCode", response_code, 600); |
| 396 if (base::FieldTrialList::TrialExists("ThrottlingEnabled")) { |
| 397 UMA_HISTOGRAM_ENUMERATION( |
| 398 base::FieldTrial::MakeName("Throttling.HttpResponseCode", |
| 399 "ThrottlingEnabled"), |
| 400 response_code, 600); |
| 401 } |
| 402 |
| 403 // Note that we are not interested in whether the code is considered |
| 404 // an error for the backoff logic, but whether it is a 5xx error in |
| 405 // general. This is because here, we are tracking the apparent total |
| 406 // downtime of a server. |
| 407 if (response_code >= 500) { |
| 408 last_response_was_success_ = false; |
| 409 } else { |
| 410 base::TimeTicks now = ImplGetTimeNow(); |
| 411 if (!last_response_was_success_) { |
| 412 // We are transitioning from failure to success, so generate our stats. |
| 413 base::TimeDelta down_time = now - last_successful_response_time_; |
| 414 int failure_count = GetBackoffEntry()->failure_count(); |
| 415 |
| 416 UMA_HISTOGRAM_COUNTS("Throttling.FailureCountAtSuccess", failure_count); |
| 417 UMA_HISTOGRAM_CUSTOM_TIMES( |
| 418 "Throttling.PerceivedDowntime", down_time, |
| 419 base::TimeDelta::FromMilliseconds(10), |
| 420 base::TimeDelta::FromHours(6), 50); |
| 421 |
| 422 if (base::FieldTrialList::TrialExists("ThrottlingEnabled")) { |
| 423 UMA_HISTOGRAM_COUNTS(base::FieldTrial::MakeName( |
| 424 "Throttling.FailureCountAtSuccess", "ThrottlingEnabled"), |
| 425 failure_count); |
| 426 UMA_HISTOGRAM_CUSTOM_TIMES(base::FieldTrial::MakeName( |
| 427 "Throttling.PerceivedDowntime", "ThrottlingEnabled"), down_time, |
| 428 base::TimeDelta::FromMilliseconds(10), |
| 429 base::TimeDelta::FromHours(6), 50); |
| 430 } |
| 431 } |
| 432 |
| 433 last_successful_response_time_ = now; |
| 434 last_response_was_success_ = true; |
| 435 } |
| 436 } |
| 437 |
260 const BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() const { | 438 const BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() const { |
261 return &backoff_entry_; | 439 return &backoff_entry_; |
262 } | 440 } |
263 | 441 |
264 BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() { | 442 BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() { |
265 return &backoff_entry_; | 443 return &backoff_entry_; |
266 } | 444 } |
267 | 445 |
268 } // namespace net | 446 } // namespace net |
OLD | NEW |