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

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: Merge to head. 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/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
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
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
OLDNEW
« no previous file with comments | « net/url_request/url_request_throttler_entry.h ('k') | net/url_request/url_request_throttler_entry_interface.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698