Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(134)

Side by Side Diff: net/url_request/url_request_throttler_entry.cc

Issue 6966038: Anti-DDoS enhancements: Log to net log, UMA stats, improved policy. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remove NON_EXPORTED_BASE where not needed. Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/time.h"
15 #include "base/values.h"
16 #include "net/base/net_log.h"
12 #include "net/url_request/url_request_throttler_header_interface.h" 17 #include "net/url_request/url_request_throttler_header_interface.h"
13 #include "net/url_request/url_request_throttler_manager.h" 18 #include "net/url_request/url_request_throttler_manager.h"
14 19
15 namespace net { 20 namespace net {
16 21
17 const int URLRequestThrottlerEntry::kDefaultSlidingWindowPeriodMs = 2000; 22 const int URLRequestThrottlerEntry::kDefaultSlidingWindowPeriodMs = 2000;
18 const int URLRequestThrottlerEntry::kDefaultMaxSendThreshold = 20; 23 const int URLRequestThrottlerEntry::kDefaultMaxSendThreshold = 20;
19 24
20 // This set of back-off parameters will (at maximum values, i.e. without 25 // This set of back-off parameters will (at maximum values, i.e. without
21 // the reduction caused by jitter) add 0-41% (distributed uniformly 26 // the reduction caused by jitter) add 0-41% (distributed uniformly
22 // in that range) to the "perceived downtime" of the remote server, once 27 // 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 28 // 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 29 // about a second at a time. Once the maximum back-off is reached, the added
25 // perceived downtime decreases rapidly, percentage-wise. 30 // perceived downtime decreases rapidly, percentage-wise.
26 // 31 //
27 // Another way to put it is that the maximum additional perceived downtime 32 // 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 33 // 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 34 // 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 35 // unavailable at the end of each back-off period for a total of about
31 // 48 minutes. 36 // 48 minutes.
32 // 37 //
33 // Ignoring the first 4 errors helps avoid back-off from kicking in on 38 // Ignoring the first couple of errors is just a conservative measure to
34 // flaky connections. 39 // avoid false positives. It should help avoid back-off from kicking in e.g.
35 const int URLRequestThrottlerEntry::kDefaultNumErrorsToIgnore = 4; 40 // on flaky connections.
41 const int URLRequestThrottlerEntry::kDefaultNumErrorsToIgnore = 2;
36 const int URLRequestThrottlerEntry::kDefaultInitialBackoffMs = 700; 42 const int URLRequestThrottlerEntry::kDefaultInitialBackoffMs = 700;
37 const double URLRequestThrottlerEntry::kDefaultMultiplyFactor = 1.4; 43 const double URLRequestThrottlerEntry::kDefaultMultiplyFactor = 1.4;
38 const double URLRequestThrottlerEntry::kDefaultJitterFactor = 0.4; 44 const double URLRequestThrottlerEntry::kDefaultJitterFactor = 0.4;
39 const int URLRequestThrottlerEntry::kDefaultMaximumBackoffMs = 15 * 60 * 1000; 45 const int URLRequestThrottlerEntry::kDefaultMaximumBackoffMs = 15 * 60 * 1000;
40 const int URLRequestThrottlerEntry::kDefaultEntryLifetimeMs = 2 * 60 * 1000; 46 const int URLRequestThrottlerEntry::kDefaultEntryLifetimeMs = 2 * 60 * 1000;
41 const char URLRequestThrottlerEntry::kRetryHeaderName[] = "X-Retry-After"; 47 const char URLRequestThrottlerEntry::kRetryHeaderName[] = "X-Retry-After";
42 const char URLRequestThrottlerEntry::kExponentialThrottlingHeader[] = 48 const char URLRequestThrottlerEntry::kExponentialThrottlingHeader[] =
43 "X-Chrome-Exponential-Throttling"; 49 "X-Chrome-Exponential-Throttling";
44 const char URLRequestThrottlerEntry::kExponentialThrottlingDisableValue[] = 50 const char URLRequestThrottlerEntry::kExponentialThrottlingDisableValue[] =
45 "disable"; 51 "disable";
46 52
53 // NetLog parameters when a request is rejected by throttling.
54 class RejectedRequestParameters : public NetLog::EventParameters {
55 public:
56 RejectedRequestParameters(const std::string& url_id,
57 int num_failures,
58 int release_after_ms)
59 : url_id_(url_id),
60 num_failures_(num_failures),
61 release_after_ms_(release_after_ms) {
62 }
63
64 virtual Value* ToValue() const {
65 DictionaryValue* dict = new DictionaryValue();
66 dict->SetString("url", url_id_);
67 dict->SetInteger("num_failures", num_failures_);
68 dict->SetInteger("release_after_ms", release_after_ms_);
69 return dict;
70 }
71
72 private:
73 std::string url_id_;
74 int num_failures_;
75 int release_after_ms_;
76 };
77
78 // NetLog parameters when a response contains an X-Retry-After header.
79 class RetryAfterParameters : public NetLog::EventParameters {
80 public:
81 RetryAfterParameters(const std::string& url_id,
82 int retry_after_ms)
yzshen1 2011/05/25 03:49:06 Wrong indent.
Jói 2011/05/25 14:30:35 Done.
83 : url_id_(url_id),
84 retry_after_ms_(retry_after_ms) {
85 }
86
87 virtual Value* ToValue() const {
88 DictionaryValue* dict = new DictionaryValue();
89 dict->SetString("url", url_id_);
90 dict->SetInteger("retry_after_ms", retry_after_ms_);
91 return dict;
92 }
93
94 private:
95 std::string url_id_;
96 int retry_after_ms_;
97 };
98
47 URLRequestThrottlerEntry::URLRequestThrottlerEntry( 99 URLRequestThrottlerEntry::URLRequestThrottlerEntry(
48 URLRequestThrottlerManager* manager) 100 URLRequestThrottlerManager* manager,
101 const std::string& url_id)
49 : sliding_window_period_( 102 : sliding_window_period_(
50 base::TimeDelta::FromMilliseconds(kDefaultSlidingWindowPeriodMs)), 103 base::TimeDelta::FromMilliseconds(kDefaultSlidingWindowPeriodMs)),
51 max_send_threshold_(kDefaultMaxSendThreshold), 104 max_send_threshold_(kDefaultMaxSendThreshold),
52 is_backoff_disabled_(false), 105 is_backoff_disabled_(false),
53 backoff_entry_(&backoff_policy_), 106 backoff_entry_(&backoff_policy_),
54 manager_(manager) { 107 manager_(manager),
108 url_id_(url_id),
109 net_log_(BoundNetLog::Make(
110 manager->net_log(), NetLog::SOURCE_EXPONENTIAL_BACKOFF_THROTTLING)) {
55 DCHECK(manager_); 111 DCHECK(manager_);
56 Initialize(); 112 Initialize();
57 } 113 }
58 114
59 URLRequestThrottlerEntry::URLRequestThrottlerEntry( 115 URLRequestThrottlerEntry::URLRequestThrottlerEntry(
60 URLRequestThrottlerManager* manager, 116 URLRequestThrottlerManager* manager,
117 const std::string& url_id,
61 int sliding_window_period_ms, 118 int sliding_window_period_ms,
62 int max_send_threshold, 119 int max_send_threshold,
63 int initial_backoff_ms, 120 int initial_backoff_ms,
64 double multiply_factor, 121 double multiply_factor,
65 double jitter_factor, 122 double jitter_factor,
66 int maximum_backoff_ms) 123 int maximum_backoff_ms)
67 : sliding_window_period_( 124 : sliding_window_period_(
68 base::TimeDelta::FromMilliseconds(sliding_window_period_ms)), 125 base::TimeDelta::FromMilliseconds(sliding_window_period_ms)),
69 max_send_threshold_(max_send_threshold), 126 max_send_threshold_(max_send_threshold),
70 is_backoff_disabled_(false), 127 is_backoff_disabled_(false),
71 backoff_entry_(&backoff_policy_), 128 backoff_entry_(&backoff_policy_),
72 manager_(manager) { 129 manager_(manager),
130 url_id_(url_id) {
73 DCHECK_GT(sliding_window_period_ms, 0); 131 DCHECK_GT(sliding_window_period_ms, 0);
74 DCHECK_GT(max_send_threshold_, 0); 132 DCHECK_GT(max_send_threshold_, 0);
75 DCHECK_GE(initial_backoff_ms, 0); 133 DCHECK_GE(initial_backoff_ms, 0);
76 DCHECK_GT(multiply_factor, 0); 134 DCHECK_GT(multiply_factor, 0);
77 DCHECK_GE(jitter_factor, 0.0); 135 DCHECK_GE(jitter_factor, 0.0);
78 DCHECK_LT(jitter_factor, 1.0); 136 DCHECK_LT(jitter_factor, 1.0);
79 DCHECK_GE(maximum_backoff_ms, 0); 137 DCHECK_GE(maximum_backoff_ms, 0);
80 DCHECK(manager_); 138 DCHECK(manager_);
81 139
82 Initialize(); 140 Initialize();
(...skipping 16 matching lines...) Expand all
99 // it should not be considered outdated. 157 // it should not be considered outdated.
100 // 158 //
101 // TODO(joi): Once the manager is not a Singleton, revisit whether 159 // TODO(joi): Once the manager is not a Singleton, revisit whether
102 // refcounting is needed at all. 160 // refcounting is needed at all.
103 if (!HasOneRef()) 161 if (!HasOneRef())
104 return false; 162 return false;
105 163
106 // If there are send events in the sliding window period, we still need this 164 // If there are send events in the sliding window period, we still need this
107 // entry. 165 // entry.
108 if (!send_log_.empty() && 166 if (!send_log_.empty() &&
109 send_log_.back() + sliding_window_period_ > GetTimeNow()) { 167 send_log_.back() + sliding_window_period_ > ImplGetTimeNow()) {
110 return false; 168 return false;
111 } 169 }
112 170
113 return GetBackoffEntry()->CanDiscard(); 171 return GetBackoffEntry()->CanDiscard();
114 } 172 }
115 173
116 void URLRequestThrottlerEntry::DisableBackoffThrottling() { 174 void URLRequestThrottlerEntry::DisableBackoffThrottling() {
117 is_backoff_disabled_ = true; 175 is_backoff_disabled_ = true;
118 } 176 }
119 177
120 void URLRequestThrottlerEntry::DetachManager() { 178 void URLRequestThrottlerEntry::DetachManager() {
121 manager_ = NULL; 179 manager_ = NULL;
122 } 180 }
123 181
124 bool URLRequestThrottlerEntry::IsDuringExponentialBackoff() const { 182 bool URLRequestThrottlerEntry::IsDuringExponentialBackoff() const {
125 if (is_backoff_disabled_) 183 bool reject_request = false;
126 return false; 184 if (!is_backoff_disabled_ && GetBackoffEntry()->ShouldRejectRequest()) {
185 int num_failures = GetBackoffEntry()->failure_count();
186 int release_after_ms =
187 (GetBackoffEntry()->GetReleaseTime() - base::TimeTicks::Now())
188 .InMilliseconds();
127 189
128 return GetBackoffEntry()->ShouldRejectRequest(); 190 net_log_.AddEvent(
191 NetLog::TYPE_THROTTLING_REJECTED_REQUEST,
yzshen1 2011/05/25 03:49:06 Wrong indent.
Jói 2011/05/25 14:30:35 Done.
192 make_scoped_refptr(
193 new RejectedRequestParameters(url_id_,
194 num_failures,
195 release_after_ms)));
196
197 reject_request = true;
198 }
199
200 int reject_count = reject_request ? 1 : 0;
201 UMA_HISTOGRAM_ENUMERATION(
202 "Throttling.RequestThrottled", reject_count, 2);
203 if (base::FieldTrialList::TrialExists("ThrottlingEnabled")) {
204 UMA_HISTOGRAM_ENUMERATION(base::FieldTrial::MakeName(
205 "Throttling.RequestThrottled", "ThrottlingEnabled"), reject_count, 2);
206 }
207
208 return reject_request;
129 } 209 }
130 210
131 int64 URLRequestThrottlerEntry::ReserveSendingTimeForNextRequest( 211 int64 URLRequestThrottlerEntry::ReserveSendingTimeForNextRequest(
132 const base::TimeTicks& earliest_time) { 212 const base::TimeTicks& earliest_time) {
133 base::TimeTicks now = GetTimeNow(); 213 base::TimeTicks now = ImplGetTimeNow();
134 214
135 // If a lot of requests were successfully made recently, 215 // If a lot of requests were successfully made recently,
136 // sliding_window_release_time_ may be greater than 216 // sliding_window_release_time_ may be greater than
137 // exponential_backoff_release_time_. 217 // exponential_backoff_release_time_.
138 base::TimeTicks recommended_sending_time = 218 base::TimeTicks recommended_sending_time =
139 std::max(std::max(now, earliest_time), 219 std::max(std::max(now, earliest_time),
140 std::max(GetBackoffEntry()->GetReleaseTime(), 220 std::max(GetBackoffEntry()->GetReleaseTime(),
141 sliding_window_release_time_)); 221 sliding_window_release_time_));
142 222
143 DCHECK(send_log_.empty() || 223 DCHECK(send_log_.empty() ||
(...skipping 20 matching lines...) Expand all
164 } 244 }
165 245
166 base::TimeTicks 246 base::TimeTicks
167 URLRequestThrottlerEntry::GetExponentialBackoffReleaseTime() const { 247 URLRequestThrottlerEntry::GetExponentialBackoffReleaseTime() const {
168 // If a site opts out, it's likely because they have problems that trigger 248 // 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 249 // 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 250 // 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 251 // wrong thing to do (i.e. it would likely be too long). Therefore, we
172 // return "now" so that retries are not delayed. 252 // return "now" so that retries are not delayed.
173 if (is_backoff_disabled_) 253 if (is_backoff_disabled_)
174 return GetTimeNow(); 254 return ImplGetTimeNow();
175 255
176 return GetBackoffEntry()->GetReleaseTime(); 256 return GetBackoffEntry()->GetReleaseTime();
177 } 257 }
178 258
179 void URLRequestThrottlerEntry::UpdateWithResponse( 259 void URLRequestThrottlerEntry::UpdateWithResponse(
180 const std::string& host, 260 const std::string& host,
181 const URLRequestThrottlerHeaderInterface* response) { 261 const URLRequestThrottlerHeaderInterface* response) {
182 if (response->GetResponseCode() >= 500) { 262 int status_code = response->GetResponseCode();
263 HandleMetricsTracking(status_code);
264
265 if (IsConsideredError(status_code)) {
183 GetBackoffEntry()->InformOfRequest(false); 266 GetBackoffEntry()->InformOfRequest(false);
184 } else { 267 } else {
185 GetBackoffEntry()->InformOfRequest(true); 268 GetBackoffEntry()->InformOfRequest(true);
186 269
187 std::string retry_header = response->GetNormalizedValue(kRetryHeaderName); 270 std::string retry_header = response->GetNormalizedValue(kRetryHeaderName);
188 if (!retry_header.empty()) 271 if (!retry_header.empty())
189 HandleCustomRetryAfter(retry_header); 272 HandleCustomRetryAfter(retry_header);
190 273
191 std::string throttling_header = response->GetNormalizedValue( 274 std::string throttling_header = response->GetNormalizedValue(
192 kExponentialThrottlingHeader); 275 kExponentialThrottlingHeader);
193 if (!throttling_header.empty()) 276 if (!throttling_header.empty())
194 HandleThrottlingHeader(throttling_header, host); 277 HandleThrottlingHeader(throttling_header, host);
195 } 278 }
196 } 279 }
197 280
198 void URLRequestThrottlerEntry::ReceivedContentWasMalformed() { 281 void URLRequestThrottlerEntry::ReceivedContentWasMalformed(int status_code) {
199 // A malformed body can only occur when the request to fetch a resource 282 // 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 283 // was successful. Therefore, in such a situation, we will receive one
201 // call to ReceivedContentWasMalformed() and one call to UpdateWithResponse() 284 // call to ReceivedContentWasMalformed() and one call to
202 // with a response categorized as "good". To end up counting one failure, 285 // UpdateWithResponse() with a response categorized as "good". To end
203 // we need to count two failures here against the one success in 286 // up counting one failure, we need to count two failures here against
204 // UpdateWithResponse(). 287 // the one success in UpdateWithResponse().
205 GetBackoffEntry()->InformOfRequest(false); 288 //
206 GetBackoffEntry()->InformOfRequest(false); 289 // We do nothing for a response that is already being considered an error
290 // based on its status code (otherwise we would count 3 errors instead of 1).
291 if (!IsConsideredError(status_code)) {
292 GetBackoffEntry()->InformOfRequest(false);
293 GetBackoffEntry()->InformOfRequest(false);
294 }
207 } 295 }
208 296
209 URLRequestThrottlerEntry::~URLRequestThrottlerEntry() { 297 URLRequestThrottlerEntry::~URLRequestThrottlerEntry() {
210 } 298 }
211 299
212 void URLRequestThrottlerEntry::Initialize() { 300 void URLRequestThrottlerEntry::Initialize() {
213 sliding_window_release_time_ = base::TimeTicks::Now(); 301 sliding_window_release_time_ = base::TimeTicks::Now();
214 backoff_policy_.num_errors_to_ignore = kDefaultNumErrorsToIgnore; 302 backoff_policy_.num_errors_to_ignore = kDefaultNumErrorsToIgnore;
215 backoff_policy_.initial_backoff_ms = kDefaultInitialBackoffMs; 303 backoff_policy_.initial_backoff_ms = kDefaultInitialBackoffMs;
216 backoff_policy_.multiply_factor = kDefaultMultiplyFactor; 304 backoff_policy_.multiply_factor = kDefaultMultiplyFactor;
217 backoff_policy_.jitter_factor = kDefaultJitterFactor; 305 backoff_policy_.jitter_factor = kDefaultJitterFactor;
218 backoff_policy_.maximum_backoff_ms = kDefaultMaximumBackoffMs; 306 backoff_policy_.maximum_backoff_ms = kDefaultMaximumBackoffMs;
219 backoff_policy_.entry_lifetime_ms = kDefaultEntryLifetimeMs; 307 backoff_policy_.entry_lifetime_ms = kDefaultEntryLifetimeMs;
308
309 // We pretend we just had a successful response so that we have a
310 // starting point to our tracking.
311 last_successful_response_time_ = base::TimeTicks::Now();
yzshen1 2011/05/25 03:49:06 It would be good to comment about why ImplGetTimeN
Jói 2011/05/25 14:30:35 Done.
312 last_response_was_success_ = true;
220 } 313 }
221 314
222 base::TimeTicks URLRequestThrottlerEntry::GetTimeNow() const { 315 bool URLRequestThrottlerEntry::IsConsideredError(int status_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 (status_code == 500 ||
334 status_code == 503 ||
335 status_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 status_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", status_code, 600);
396 if (base::FieldTrialList::TrialExists("ThrottlingEnabled")) {
397 UMA_HISTOGRAM_ENUMERATION(base::FieldTrial::MakeName(
398 "Throttling.HttpResponseCode", "ThrottlingEnabled"), status_code, 600);
399 }
400
401 // Note that we are not interested in whether the code is considered
402 // an error for the backoff logic, but whether it is a 5xx error in
403 // general. This is because here, we are tracking the apparent total
404 // downtime of a server.
405 if (status_code >= 500) {
406 last_response_was_success_ = false;
407 } else {
408 base::TimeTicks now = base::TimeTicks::Now();
yzshen1 2011/05/25 03:49:06 Is it intended to not use ImplGetTimeNow here?
Jói 2011/05/25 14:30:35 No, thanks for catching that. I am writing tests
409 if (!last_response_was_success_) {
410 // We are transitioning from failure to success, so generate our stats.
411 base::TimeDelta down_time = now - last_successful_response_time_;
412 int failure_count = GetBackoffEntry()->failure_count();
413
414 UMA_HISTOGRAM_COUNTS("Throttling.FailureCountAtSuccess", failure_count);
415 UMA_HISTOGRAM_CUSTOM_TIMES(
416 "Throttling.PerceivedDowntime", down_time,
417 base::TimeDelta::FromMilliseconds(10),
418 base::TimeDelta::FromHours(6), 50);
419
420 if (base::FieldTrialList::TrialExists("ThrottlingEnabled")) {
421 UMA_HISTOGRAM_COUNTS(base::FieldTrial::MakeName(
422 "Throttling.FailureCountAtSuccess", "ThrottlingEnabled"),
423 failure_count);
424 UMA_HISTOGRAM_CUSTOM_TIMES(base::FieldTrial::MakeName(
425 "Throttling.PerceivedDowntime", "ThrottlingEnabled"), down_time,
426 base::TimeDelta::FromMilliseconds(10),
427 base::TimeDelta::FromHours(6), 50);
428 }
429 }
430
431 last_successful_response_time_ = now;
432 last_response_was_success_ = true;
433 }
434 }
435
260 const BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() const { 436 const BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() const {
261 return &backoff_entry_; 437 return &backoff_entry_;
262 } 438 }
263 439
264 BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() { 440 BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() {
265 return &backoff_entry_; 441 return &backoff_entry_;
266 } 442 }
267 443
268 } // namespace net 444 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698