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

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: Respond to review comments. 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 // If there is more than one reference on us, it means a URLRequestHttpJob 92 // 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 93 // or URLFetcher holds a reference. If we were garbage collected from the
63 // URLRequestThrottlerManager map while this is true, then separate clients 94 // URLRequestThrottlerManager map while this is true, then separate clients
64 // could end up holding separate objects for the "same" request, which 95 // could end up holding separate objects for the "same" request, which
65 // is undesirable. These clients are short-lived anyway, so they shouldn't 96 // is undesirable. These clients are short-lived anyway, so they shouldn't
66 // normally prevent items for being garbage collected for long. 97 // normally prevent items for being garbage collected for long.
67 if (!HasOneRef()) 98 if (!HasOneRef())
68 return false; 99 return false;
69 100
70 // If there are send events in the sliding window period, we still need this 101 // If there are send events in the sliding window period, we still need this
71 // entry. 102 // entry.
72 if (!send_log_.empty() && 103 if (!send_log_.empty() &&
73 send_log_.back() + sliding_window_period_ > GetTimeNow()) { 104 send_log_.back() + sliding_window_period_ > GetTimeNow()) {
74 return false; 105 return false;
75 } 106 }
76 107
77 return GetBackoffEntry()->CanDiscard(); 108 return GetBackoffEntry()->CanDiscard();
78 } 109 }
79 110
111 void URLRequestThrottlerEntry::DisableBackoffThrottling() {
112 is_backoff_disabled_ = true;
113 }
114
115 void URLRequestThrottlerEntry::DetachManager() {
116 manager_ = NULL;
117 }
118
80 bool URLRequestThrottlerEntry::IsDuringExponentialBackoff() const { 119 bool URLRequestThrottlerEntry::IsDuringExponentialBackoff() const {
120 if (is_backoff_disabled_)
121 return false;
122
81 return GetBackoffEntry()->ShouldRejectRequest(); 123 return GetBackoffEntry()->ShouldRejectRequest();
82 } 124 }
83 125
84 int64 URLRequestThrottlerEntry::ReserveSendingTimeForNextRequest( 126 int64 URLRequestThrottlerEntry::ReserveSendingTimeForNextRequest(
85 const base::TimeTicks& earliest_time) { 127 const base::TimeTicks& earliest_time) {
86 base::TimeTicks now = GetTimeNow(); 128 base::TimeTicks now = GetTimeNow();
87 129
88 // If a lot of requests were successfully made recently, 130 // If a lot of requests were successfully made recently,
89 // sliding_window_release_time_ may be greater than 131 // sliding_window_release_time_ may be greater than
90 // exponential_backoff_release_time_. 132 // exponential_backoff_release_time_.
(...skipping 20 matching lines...) Expand all
111 153
112 // Check if there are too many send events in recent time. 154 // Check if there are too many send events in recent time.
113 if (send_log_.size() == static_cast<unsigned>(max_send_threshold_)) 155 if (send_log_.size() == static_cast<unsigned>(max_send_threshold_))
114 sliding_window_release_time_ = send_log_.front() + sliding_window_period_; 156 sliding_window_release_time_ = send_log_.front() + sliding_window_period_;
115 157
116 return (recommended_sending_time - now).InMillisecondsRoundedUp(); 158 return (recommended_sending_time - now).InMillisecondsRoundedUp();
117 } 159 }
118 160
119 base::TimeTicks 161 base::TimeTicks
120 URLRequestThrottlerEntry::GetExponentialBackoffReleaseTime() const { 162 URLRequestThrottlerEntry::GetExponentialBackoffReleaseTime() const {
163 // If a site opts out, it's likely because they have problems that trigger
164 // the back-off mechanism when it shouldn't be triggered, in which case
165 // returning the calculated back-off release time would probably be the
166 // wrong thing to do (i.e. it would likely be too long). Therefore, we
167 // return "now" so that retries are not delayed.
168 if (is_backoff_disabled_)
169 return GetTimeNow();
170
121 return GetBackoffEntry()->GetReleaseTime(); 171 return GetBackoffEntry()->GetReleaseTime();
122 } 172 }
123 173
124 void URLRequestThrottlerEntry::UpdateWithResponse( 174 void URLRequestThrottlerEntry::UpdateWithResponse(
175 const std::string& host,
125 const URLRequestThrottlerHeaderInterface* response) { 176 const URLRequestThrottlerHeaderInterface* response) {
126 if (response->GetResponseCode() >= 500) { 177 if (response->GetResponseCode() >= 500) {
127 GetBackoffEntry()->InformOfRequest(false); 178 GetBackoffEntry()->InformOfRequest(false);
128 } else { 179 } else {
129 GetBackoffEntry()->InformOfRequest(true); 180 GetBackoffEntry()->InformOfRequest(true);
130 181
131 std::string retry_header = response->GetNormalizedValue(kRetryHeaderName); 182 std::string retry_header = response->GetNormalizedValue(kRetryHeaderName);
132 if (!retry_header.empty()) 183 if (!retry_header.empty())
133 HandleCustomRetryAfter(retry_header); 184 HandleCustomRetryAfter(retry_header);
185
186 std::string throttling_header = response->GetNormalizedValue(
187 kExponentialThrottlingHeader);
188 if (!throttling_header.empty())
189 HandleThrottlingHeader(throttling_header, host);
134 } 190 }
135 } 191 }
136 192
137 void URLRequestThrottlerEntry::ReceivedContentWasMalformed() { 193 void URLRequestThrottlerEntry::ReceivedContentWasMalformed() {
138 // We keep this simple and just count it as a single error. 194 // We keep this simple and just count it as a single error.
139 // 195 //
140 // If we wanted to get fancy, we would count two errors here, and decrease 196 // 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 197 // 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 198 // code) response. Instead, we keep things simple by always resetting the
143 // error count on success, and therefore counting only a single error here. 199 // error count on success, and therefore counting only a single error here.
144 GetBackoffEntry()->InformOfRequest(false); 200 GetBackoffEntry()->InformOfRequest(false);
145 } 201 }
146 202
147 URLRequestThrottlerEntry::~URLRequestThrottlerEntry() { 203 URLRequestThrottlerEntry::~URLRequestThrottlerEntry() {
148 } 204 }
149 205
150 void URLRequestThrottlerEntry::Initialize() { 206 void URLRequestThrottlerEntry::Initialize() {
151 sliding_window_release_time_ = base::TimeTicks::Now(); 207 sliding_window_release_time_ = base::TimeTicks::Now();
152 backoff_policy_.num_errors_to_ignore = 0; 208 backoff_policy_.num_errors_to_ignore = kDefaultNumErrorsToIgnore;
153 backoff_policy_.initial_backoff_ms = kDefaultInitialBackoffMs; 209 backoff_policy_.initial_backoff_ms = kDefaultInitialBackoffMs;
154 backoff_policy_.multiply_factor = kDefaultMultiplyFactor; 210 backoff_policy_.multiply_factor = kDefaultMultiplyFactor;
155 backoff_policy_.jitter_factor = kDefaultJitterFactor; 211 backoff_policy_.jitter_factor = kDefaultJitterFactor;
156 backoff_policy_.maximum_backoff_ms = kDefaultMaximumBackoffMs; 212 backoff_policy_.maximum_backoff_ms = kDefaultMaximumBackoffMs;
157 backoff_policy_.entry_lifetime_ms = kDefaultEntryLifetimeMs; 213 backoff_policy_.entry_lifetime_ms = kDefaultEntryLifetimeMs;
158 } 214 }
159 215
160 base::TimeTicks URLRequestThrottlerEntry::GetTimeNow() const { 216 base::TimeTicks URLRequestThrottlerEntry::GetTimeNow() const {
161 return base::TimeTicks::Now(); 217 return base::TimeTicks::Now();
162 } 218 }
(...skipping 13 matching lines...) Expand all
176 232
177 // We do not check for an upper bound; the server can set any Retry-After it 233 // 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. 234 // desires. Recovery from error would involve restarting the browser.
179 if (value_ms < 0) 235 if (value_ms < 0)
180 return; 236 return;
181 237
182 GetBackoffEntry()->SetCustomReleaseTime( 238 GetBackoffEntry()->SetCustomReleaseTime(
183 GetTimeNow() + base::TimeDelta::FromMilliseconds(value_ms)); 239 GetTimeNow() + base::TimeDelta::FromMilliseconds(value_ms));
184 } 240 }
185 241
242 void URLRequestThrottlerEntry::HandleThrottlingHeader(
243 const std::string& header_value,
244 const std::string& host) {
245 if (header_value == kExponentialThrottlingDisableValue) {
246 DisableBackoffThrottling();
247 if (manager_)
248 manager_->AddToOptOutList(host);
249 } else {
250 // TODO(joi): Log this.
251 }
252 }
253
186 const BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() const { 254 const BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() const {
187 return &backoff_entry_; 255 return &backoff_entry_;
188 } 256 }
189 257
190 BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() { 258 BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() {
191 return &backoff_entry_; 259 return &backoff_entry_;
192 } 260 }
193 261
194 } // namespace net 262 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698