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

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: Merge to head. 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;
88 backoff_policy_.num_errors_to_ignore = 0;
58 } 89 }
59 90
60 bool URLRequestThrottlerEntry::IsEntryOutdated() const { 91 bool URLRequestThrottlerEntry::IsEntryOutdated() const {
61 // This function is called by the URLRequestThrottlerManager to determine 92 // This function is called by the URLRequestThrottlerManager to determine
62 // whether entries should be discarded from its url_entries_ map. We 93 // whether entries should be discarded from its url_entries_ map. We
63 // want to ensure that it does not remove entries from the map while there 94 // want to ensure that it does not remove entries from the map while there
64 // are clients (objects other than the manager) holding references to 95 // are clients (objects other than the manager) holding references to
65 // the entry, otherwise separate clients could end up holding separate 96 // the entry, otherwise separate clients could end up holding separate
66 // entries for a request to the same URL, which is undesirable. Therefore, 97 // entries for a request to the same URL, which is undesirable. Therefore,
67 // if an entry has more than one reference (the map will always hold one), 98 // if an entry has more than one reference (the map will always hold one),
68 // it should not be considered outdated. 99 // it should not be considered outdated.
69 // 100 //
70 // TODO(joi): Once the manager is not a Singleton, revisit whether 101 // TODO(joi): Once the manager is not a Singleton, revisit whether
71 // refcounting is needed at all. 102 // refcounting is needed at all.
72 if (!HasOneRef()) 103 if (!HasOneRef())
73 return false; 104 return false;
74 105
75 // If there are send events in the sliding window period, we still need this 106 // If there are send events in the sliding window period, we still need this
76 // entry. 107 // entry.
77 if (!send_log_.empty() && 108 if (!send_log_.empty() &&
78 send_log_.back() + sliding_window_period_ > GetTimeNow()) { 109 send_log_.back() + sliding_window_period_ > GetTimeNow()) {
79 return false; 110 return false;
80 } 111 }
81 112
82 return GetBackoffEntry()->CanDiscard(); 113 return GetBackoffEntry()->CanDiscard();
83 } 114 }
84 115
116 void URLRequestThrottlerEntry::DisableBackoffThrottling() {
117 is_backoff_disabled_ = true;
118 }
119
120 void URLRequestThrottlerEntry::DetachManager() {
121 manager_ = NULL;
122 }
123
85 bool URLRequestThrottlerEntry::IsDuringExponentialBackoff() const { 124 bool URLRequestThrottlerEntry::IsDuringExponentialBackoff() const {
125 if (is_backoff_disabled_)
126 return false;
127
86 return GetBackoffEntry()->ShouldRejectRequest(); 128 return GetBackoffEntry()->ShouldRejectRequest();
87 } 129 }
88 130
89 int64 URLRequestThrottlerEntry::ReserveSendingTimeForNextRequest( 131 int64 URLRequestThrottlerEntry::ReserveSendingTimeForNextRequest(
90 const base::TimeTicks& earliest_time) { 132 const base::TimeTicks& earliest_time) {
91 base::TimeTicks now = GetTimeNow(); 133 base::TimeTicks now = GetTimeNow();
92 134
93 // If a lot of requests were successfully made recently, 135 // If a lot of requests were successfully made recently,
94 // sliding_window_release_time_ may be greater than 136 // sliding_window_release_time_ may be greater than
95 // exponential_backoff_release_time_. 137 // exponential_backoff_release_time_.
(...skipping 20 matching lines...) Expand all
116 158
117 // Check if there are too many send events in recent time. 159 // Check if there are too many send events in recent time.
118 if (send_log_.size() == static_cast<unsigned>(max_send_threshold_)) 160 if (send_log_.size() == static_cast<unsigned>(max_send_threshold_))
119 sliding_window_release_time_ = send_log_.front() + sliding_window_period_; 161 sliding_window_release_time_ = send_log_.front() + sliding_window_period_;
120 162
121 return (recommended_sending_time - now).InMillisecondsRoundedUp(); 163 return (recommended_sending_time - now).InMillisecondsRoundedUp();
122 } 164 }
123 165
124 base::TimeTicks 166 base::TimeTicks
125 URLRequestThrottlerEntry::GetExponentialBackoffReleaseTime() const { 167 URLRequestThrottlerEntry::GetExponentialBackoffReleaseTime() const {
168 // 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
170 // 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
172 // return "now" so that retries are not delayed.
173 if (is_backoff_disabled_)
174 return GetTimeNow();
175
126 return GetBackoffEntry()->GetReleaseTime(); 176 return GetBackoffEntry()->GetReleaseTime();
127 } 177 }
128 178
129 void URLRequestThrottlerEntry::UpdateWithResponse( 179 void URLRequestThrottlerEntry::UpdateWithResponse(
180 const std::string& host,
130 const URLRequestThrottlerHeaderInterface* response) { 181 const URLRequestThrottlerHeaderInterface* response) {
131 if (response->GetResponseCode() >= 500) { 182 if (response->GetResponseCode() >= 500) {
132 GetBackoffEntry()->InformOfRequest(false); 183 GetBackoffEntry()->InformOfRequest(false);
133 } else { 184 } else {
134 GetBackoffEntry()->InformOfRequest(true); 185 GetBackoffEntry()->InformOfRequest(true);
135 186
136 std::string retry_header = response->GetNormalizedValue(kRetryHeaderName); 187 std::string retry_header = response->GetNormalizedValue(kRetryHeaderName);
137 if (!retry_header.empty()) 188 if (!retry_header.empty())
138 HandleCustomRetryAfter(retry_header); 189 HandleCustomRetryAfter(retry_header);
190
191 std::string throttling_header = response->GetNormalizedValue(
192 kExponentialThrottlingHeader);
193 if (!throttling_header.empty())
194 HandleThrottlingHeader(throttling_header, host);
139 } 195 }
140 } 196 }
141 197
142 void URLRequestThrottlerEntry::ReceivedContentWasMalformed() { 198 void URLRequestThrottlerEntry::ReceivedContentWasMalformed() {
143 // We keep this simple and just count it as a single error. 199 // We keep this simple and just count it as a single error.
144 // 200 //
145 // If we wanted to get fancy, we would count two errors here, and decrease 201 // If we wanted to get fancy, we would count two errors here, and decrease
146 // the error count only by one when we receive a successful (by status 202 // the error count only by one when we receive a successful (by status
147 // code) response. Instead, we keep things simple by always resetting the 203 // code) response. Instead, we keep things simple by always resetting the
148 // error count on success, and therefore counting only a single error here. 204 // error count on success, and therefore counting only a single error here.
149 GetBackoffEntry()->InformOfRequest(false); 205 GetBackoffEntry()->InformOfRequest(false);
150 } 206 }
151 207
152 URLRequestThrottlerEntry::~URLRequestThrottlerEntry() { 208 URLRequestThrottlerEntry::~URLRequestThrottlerEntry() {
153 } 209 }
154 210
155 void URLRequestThrottlerEntry::Initialize() { 211 void URLRequestThrottlerEntry::Initialize() {
156 sliding_window_release_time_ = base::TimeTicks::Now(); 212 sliding_window_release_time_ = base::TimeTicks::Now();
157 backoff_policy_.num_errors_to_ignore = 0; 213 backoff_policy_.num_errors_to_ignore = kDefaultNumErrorsToIgnore;
158 backoff_policy_.initial_backoff_ms = kDefaultInitialBackoffMs; 214 backoff_policy_.initial_backoff_ms = kDefaultInitialBackoffMs;
159 backoff_policy_.multiply_factor = kDefaultMultiplyFactor; 215 backoff_policy_.multiply_factor = kDefaultMultiplyFactor;
160 backoff_policy_.jitter_factor = kDefaultJitterFactor; 216 backoff_policy_.jitter_factor = kDefaultJitterFactor;
161 backoff_policy_.maximum_backoff_ms = kDefaultMaximumBackoffMs; 217 backoff_policy_.maximum_backoff_ms = kDefaultMaximumBackoffMs;
162 backoff_policy_.entry_lifetime_ms = kDefaultEntryLifetimeMs; 218 backoff_policy_.entry_lifetime_ms = kDefaultEntryLifetimeMs;
163 } 219 }
164 220
165 base::TimeTicks URLRequestThrottlerEntry::GetTimeNow() const { 221 base::TimeTicks URLRequestThrottlerEntry::GetTimeNow() const {
166 return base::TimeTicks::Now(); 222 return base::TimeTicks::Now();
167 } 223 }
(...skipping 13 matching lines...) Expand all
181 237
182 // We do not check for an upper bound; the server can set any Retry-After it 238 // We do not check for an upper bound; the server can set any Retry-After it
183 // desires. Recovery from error would involve restarting the browser. 239 // desires. Recovery from error would involve restarting the browser.
184 if (value_ms < 0) 240 if (value_ms < 0)
185 return; 241 return;
186 242
187 GetBackoffEntry()->SetCustomReleaseTime( 243 GetBackoffEntry()->SetCustomReleaseTime(
188 GetTimeNow() + base::TimeDelta::FromMilliseconds(value_ms)); 244 GetTimeNow() + base::TimeDelta::FromMilliseconds(value_ms));
189 } 245 }
190 246
247 void URLRequestThrottlerEntry::HandleThrottlingHeader(
248 const std::string& header_value,
249 const std::string& host) {
250 if (header_value == kExponentialThrottlingDisableValue) {
251 DisableBackoffThrottling();
252 if (manager_)
253 manager_->AddToOptOutList(host);
254 } else {
255 // TODO(joi): Log this.
256 }
257 }
258
191 const BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() const { 259 const BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() const {
192 return &backoff_entry_; 260 return &backoff_entry_;
193 } 261 }
194 262
195 BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() { 263 BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() {
196 return &backoff_entry_; 264 return &backoff_entry_;
197 } 265 }
198 266
199 } // namespace net 267 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698