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 6711046: Add an opt-out header for HTTP throttling. Never throttle for localhost. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Update copyright years. Created 9 years, 9 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) 2010 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/rand_util.h" 10 #include "base/rand_util.h"
11 #include "base/string_number_conversions.h" 11 #include "base/string_number_conversions.h"
12 #include "net/url_request/url_request_throttler_header_interface.h" 12 #include "net/url_request/url_request_throttler_header_interface.h"
13 #include "net/url_request/url_request_throttler_manager.h"
13 14
14 namespace net { 15 namespace net {
15 16
16 const int URLRequestThrottlerEntry::kDefaultSlidingWindowPeriodMs = 2000; 17 const int URLRequestThrottlerEntry::kDefaultSlidingWindowPeriodMs = 2000;
17 const int URLRequestThrottlerEntry::kDefaultMaxSendThreshold = 20; 18 const int URLRequestThrottlerEntry::kDefaultMaxSendThreshold = 20;
19
20 // This set of back-off parameters will (at maximum values, i.e. without
21 // the reduction caused by jitter) add 0-41% (distributed uniformly
22 // 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
24 // about a second at a time. Once the maximum back-off is reached, the added
25 // perceived downtime decreases rapidly, percentage-wise.
26 //
27 // 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
29 // 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
31 // 48 minutes.
32 //
33 // Ignoring the first 4 errors helps avoid back-off from kicking in on
34 // flaky connections.
35 const int URLRequestThrottlerEntry::kDefaultNumErrorsToIgnore = 4;
18 const int URLRequestThrottlerEntry::kDefaultInitialBackoffMs = 700; 36 const int URLRequestThrottlerEntry::kDefaultInitialBackoffMs = 700;
19 const double URLRequestThrottlerEntry::kDefaultMultiplyFactor = 1.4; 37 const double URLRequestThrottlerEntry::kDefaultMultiplyFactor = 1.4;
20 const double URLRequestThrottlerEntry::kDefaultJitterFactor = 0.4; 38 const double URLRequestThrottlerEntry::kDefaultJitterFactor = 0.4;
21 const int URLRequestThrottlerEntry::kDefaultMaximumBackoffMs = 60 * 60 * 1000; 39 const int URLRequestThrottlerEntry::kDefaultMaximumBackoffMs = 15 * 60 * 1000;
22 const int URLRequestThrottlerEntry::kDefaultEntryLifetimeMs = 120000; 40 const int URLRequestThrottlerEntry::kDefaultEntryLifetimeMs = 2 * 60 * 1000;
23 const char URLRequestThrottlerEntry::kRetryHeaderName[] = "X-Retry-After"; 41 const char URLRequestThrottlerEntry::kRetryHeaderName[] = "X-Retry-After";
42 const char URLRequestThrottlerEntry::kExponentialThrottlingHeader[] =
43 "X-Chrome-Exponential-Throttling";
44 const char URLRequestThrottlerEntry::kExponentialThrottlingDisableValue[] =
45 "disable";
24 46
25 URLRequestThrottlerEntry::URLRequestThrottlerEntry() 47 URLRequestThrottlerEntry::URLRequestThrottlerEntry(
48 URLRequestThrottlerManager* manager)
26 : sliding_window_period_( 49 : sliding_window_period_(
27 base::TimeDelta::FromMilliseconds(kDefaultSlidingWindowPeriodMs)), 50 base::TimeDelta::FromMilliseconds(kDefaultSlidingWindowPeriodMs)),
28 max_send_threshold_(kDefaultMaxSendThreshold), 51 max_send_threshold_(kDefaultMaxSendThreshold),
29 backoff_entry_(&backoff_policy_) { 52 is_backoff_disabled_(false),
53 backoff_entry_(&backoff_policy_),
54 manager_(manager) {
55 DCHECK(manager_);
30 Initialize(); 56 Initialize();
31 } 57 }
32 58
33 URLRequestThrottlerEntry::URLRequestThrottlerEntry( 59 URLRequestThrottlerEntry::URLRequestThrottlerEntry(
60 URLRequestThrottlerManager* manager,
34 int sliding_window_period_ms, 61 int sliding_window_period_ms,
35 int max_send_threshold, 62 int max_send_threshold,
36 int initial_backoff_ms, 63 int initial_backoff_ms,
37 double multiply_factor, 64 double multiply_factor,
38 double jitter_factor, 65 double jitter_factor,
39 int maximum_backoff_ms) 66 int maximum_backoff_ms)
40 : sliding_window_period_( 67 : sliding_window_period_(
41 base::TimeDelta::FromMilliseconds(sliding_window_period_ms)), 68 base::TimeDelta::FromMilliseconds(sliding_window_period_ms)),
42 max_send_threshold_(max_send_threshold), 69 max_send_threshold_(max_send_threshold),
43 backoff_entry_(&backoff_policy_) { 70 is_backoff_disabled_(false),
71 backoff_entry_(&backoff_policy_),
72 manager_(manager) {
44 DCHECK_GT(sliding_window_period_ms, 0); 73 DCHECK_GT(sliding_window_period_ms, 0);
45 DCHECK_GT(max_send_threshold_, 0); 74 DCHECK_GT(max_send_threshold_, 0);
46 DCHECK_GE(initial_backoff_ms, 0); 75 DCHECK_GE(initial_backoff_ms, 0);
47 DCHECK_GT(multiply_factor, 0); 76 DCHECK_GT(multiply_factor, 0);
48 DCHECK_GE(jitter_factor, 0.0); 77 DCHECK_GE(jitter_factor, 0.0);
49 DCHECK_LT(jitter_factor, 1.0); 78 DCHECK_LT(jitter_factor, 1.0);
50 DCHECK_GE(maximum_backoff_ms, 0); 79 DCHECK_GE(maximum_backoff_ms, 0);
80 DCHECK(manager_);
51 81
52 Initialize(); 82 Initialize();
53 backoff_policy_.initial_backoff_ms = initial_backoff_ms; 83 backoff_policy_.initial_backoff_ms = initial_backoff_ms;
54 backoff_policy_.multiply_factor = multiply_factor; 84 backoff_policy_.multiply_factor = multiply_factor;
55 backoff_policy_.jitter_factor = jitter_factor; 85 backoff_policy_.jitter_factor = jitter_factor;
56 backoff_policy_.maximum_backoff_ms = maximum_backoff_ms; 86 backoff_policy_.maximum_backoff_ms = maximum_backoff_ms;
57 backoff_policy_.entry_lifetime_ms = -1; 87 backoff_policy_.entry_lifetime_ms = -1;
58 } 88 }
59 89
60 bool URLRequestThrottlerEntry::IsEntryOutdated() const { 90 bool URLRequestThrottlerEntry::IsEntryOutdated() const {
61 // If there is more than one reference on us, it means a URLRequestHttpJob 91 // If there is more than one reference on us, it means a URLRequestHttpJob
62 // or URLFetcher holds a reference. If we were garbage collected from the 92 // or URLFetcher holds a reference. If we were garbage collected from the
63 // URLRequestThrottlerManager map while this is true, then separate clients 93 // URLRequestThrottlerManager map while this is true, then separate clients
64 // could end up holding separate objects for the "same" request, which 94 // could end up holding separate objects for the "same" request, which
65 // is undesirable. These clients are short-lived anyway, so they shouldn't 95 // is undesirable. These clients are short-lived anyway, so they shouldn't
66 // normally prevent items for being garbage collected for long. 96 // normally prevent items for being garbage collected for long.
67 if (!HasOneRef()) 97 if (!HasOneRef())
68 return false; 98 return false;
69 99
70 // If there are send events in the sliding window period, we still need this 100 // If there are send events in the sliding window period, we still need this
71 // entry. 101 // entry.
72 if (!send_log_.empty() && 102 if (!send_log_.empty() &&
73 send_log_.back() + sliding_window_period_ > GetTimeNow()) { 103 send_log_.back() + sliding_window_period_ > GetTimeNow()) {
74 return false; 104 return false;
75 } 105 }
76 106
77 return GetBackoffEntry()->CanDiscard(); 107 return GetBackoffEntry()->CanDiscard();
78 } 108 }
79 109
110 void URLRequestThrottlerEntry::DisableBackoffThrottling() {
111 is_backoff_disabled_ = true;
112 }
113
80 bool URLRequestThrottlerEntry::IsDuringExponentialBackoff() const { 114 bool URLRequestThrottlerEntry::IsDuringExponentialBackoff() const {
115 if (is_backoff_disabled_)
yzshen1 2011/03/18 22:49:51 [optional] We have a enforce_throttling member in
Jói 2011/03/23 23:38:24 I don't think so; it's enforced in URLRequestHttpJ
116 return false;
117
81 return GetBackoffEntry()->ShouldRejectRequest(); 118 return GetBackoffEntry()->ShouldRejectRequest();
82 } 119 }
83 120
84 int64 URLRequestThrottlerEntry::ReserveSendingTimeForNextRequest( 121 int64 URLRequestThrottlerEntry::ReserveSendingTimeForNextRequest(
85 const base::TimeTicks& earliest_time) { 122 const base::TimeTicks& earliest_time) {
86 base::TimeTicks now = GetTimeNow(); 123 base::TimeTicks now = GetTimeNow();
87 124
88 // If a lot of requests were successfully made recently, 125 // If a lot of requests were successfully made recently,
89 // sliding_window_release_time_ may be greater than 126 // sliding_window_release_time_ may be greater than
90 // exponential_backoff_release_time_. 127 // exponential_backoff_release_time_.
(...skipping 20 matching lines...) Expand all
111 148
112 // Check if there are too many send events in recent time. 149 // Check if there are too many send events in recent time.
113 if (send_log_.size() == static_cast<unsigned>(max_send_threshold_)) 150 if (send_log_.size() == static_cast<unsigned>(max_send_threshold_))
114 sliding_window_release_time_ = send_log_.front() + sliding_window_period_; 151 sliding_window_release_time_ = send_log_.front() + sliding_window_period_;
115 152
116 return (recommended_sending_time - now).InMillisecondsRoundedUp(); 153 return (recommended_sending_time - now).InMillisecondsRoundedUp();
117 } 154 }
118 155
119 base::TimeTicks 156 base::TimeTicks
120 URLRequestThrottlerEntry::GetExponentialBackoffReleaseTime() const { 157 URLRequestThrottlerEntry::GetExponentialBackoffReleaseTime() const {
158 if (is_backoff_disabled_)
159 return GetTimeNow();
yzshen1 2011/03/18 22:49:51 [I don't have a strong opinion here, just to make
Jói 2011/03/23 23:38:24 I believe if a site opts out, it's likely because
160
121 return GetBackoffEntry()->GetReleaseTime(); 161 return GetBackoffEntry()->GetReleaseTime();
122 } 162 }
123 163
124 void URLRequestThrottlerEntry::UpdateWithResponse( 164 void URLRequestThrottlerEntry::UpdateWithResponse(
165 const std::string& host,
125 const URLRequestThrottlerHeaderInterface* response) { 166 const URLRequestThrottlerHeaderInterface* response) {
126 if (response->GetResponseCode() >= 500) { 167 if (response->GetResponseCode() >= 500) {
127 GetBackoffEntry()->InformOfRequest(false); 168 GetBackoffEntry()->InformOfRequest(false);
128 } else { 169 } else {
129 GetBackoffEntry()->InformOfRequest(true); 170 GetBackoffEntry()->InformOfRequest(true);
130 171
131 std::string retry_header = response->GetNormalizedValue(kRetryHeaderName); 172 std::string retry_header = response->GetNormalizedValue(kRetryHeaderName);
132 if (!retry_header.empty()) 173 if (!retry_header.empty())
133 HandleCustomRetryAfter(retry_header); 174 HandleCustomRetryAfter(retry_header);
175
176 std::string throttling_header = response->GetNormalizedValue(
177 kExponentialThrottlingHeader);
178 if (!throttling_header.empty())
179 HandleThrottlingHeader(throttling_header, host);
134 } 180 }
135 } 181 }
136 182
137 void URLRequestThrottlerEntry::ReceivedContentWasMalformed() { 183 void URLRequestThrottlerEntry::ReceivedContentWasMalformed() {
138 // We keep this simple and just count it as a single error. 184 // We keep this simple and just count it as a single error.
139 // 185 //
140 // If we wanted to get fancy, we would count two errors here, and decrease 186 // If we wanted to get fancy, we would count two errors here, and decrease
141 // the error count only by one when we receive a successful (by status 187 // the error count only by one when we receive a successful (by status
142 // code) response. Instead, we keep things simple by always resetting the 188 // code) response. Instead, we keep things simple by always resetting the
143 // error count on success, and therefore counting only a single error here. 189 // error count on success, and therefore counting only a single error here.
144 GetBackoffEntry()->InformOfRequest(false); 190 GetBackoffEntry()->InformOfRequest(false);
145 } 191 }
146 192
147 URLRequestThrottlerEntry::~URLRequestThrottlerEntry() { 193 URLRequestThrottlerEntry::~URLRequestThrottlerEntry() {
148 } 194 }
149 195
150 void URLRequestThrottlerEntry::Initialize() { 196 void URLRequestThrottlerEntry::Initialize() {
151 sliding_window_release_time_ = base::TimeTicks::Now(); 197 sliding_window_release_time_ = base::TimeTicks::Now();
152 backoff_policy_.num_errors_to_ignore = 0; 198 backoff_policy_.num_errors_to_ignore = kDefaultNumErrorsToIgnore;
153 backoff_policy_.initial_backoff_ms = kDefaultInitialBackoffMs; 199 backoff_policy_.initial_backoff_ms = kDefaultInitialBackoffMs;
154 backoff_policy_.multiply_factor = kDefaultMultiplyFactor; 200 backoff_policy_.multiply_factor = kDefaultMultiplyFactor;
155 backoff_policy_.jitter_factor = kDefaultJitterFactor; 201 backoff_policy_.jitter_factor = kDefaultJitterFactor;
156 backoff_policy_.maximum_backoff_ms = kDefaultMaximumBackoffMs; 202 backoff_policy_.maximum_backoff_ms = kDefaultMaximumBackoffMs;
157 backoff_policy_.entry_lifetime_ms = kDefaultEntryLifetimeMs; 203 backoff_policy_.entry_lifetime_ms = kDefaultEntryLifetimeMs;
158 } 204 }
159 205
160 base::TimeTicks URLRequestThrottlerEntry::GetTimeNow() const { 206 base::TimeTicks URLRequestThrottlerEntry::GetTimeNow() const {
161 return base::TimeTicks::Now(); 207 return base::TimeTicks::Now();
162 } 208 }
(...skipping 13 matching lines...) Expand all
176 222
177 // We do not check for an upper bound; the server can set any Retry-After it 223 // We do not check for an upper bound; the server can set any Retry-After it
178 // desires. Recovery from error would involve restarting the browser. 224 // desires. Recovery from error would involve restarting the browser.
179 if (value_ms < 0) 225 if (value_ms < 0)
180 return; 226 return;
181 227
182 GetBackoffEntry()->SetCustomReleaseTime( 228 GetBackoffEntry()->SetCustomReleaseTime(
183 GetTimeNow() + base::TimeDelta::FromMilliseconds(value_ms)); 229 GetTimeNow() + base::TimeDelta::FromMilliseconds(value_ms));
184 } 230 }
185 231
232 void URLRequestThrottlerEntry::HandleThrottlingHeader(
233 const std::string& header_value,
234 const std::string& host) {
235 if (header_value == kExponentialThrottlingDisableValue) {
236 DisableBackoffThrottling();
237 manager_->AddToOptOutList(host);
238 } else {
239 // TODO(joi): Log this.
240 }
241 }
242
186 const BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() const { 243 const BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() const {
187 return &backoff_entry_; 244 return &backoff_entry_;
188 } 245 }
189 246
190 BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() { 247 BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() {
191 return &backoff_entry_; 248 return &backoff_entry_;
192 } 249 }
193 250
194 } // namespace net 251 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698