| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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" | 10 #include "base/metrics/field_trial.h" |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 66 URLRequestThrottlerEntry::URLRequestThrottlerEntry( | 66 URLRequestThrottlerEntry::URLRequestThrottlerEntry( |
| 67 URLRequestThrottlerManager* manager, | 67 URLRequestThrottlerManager* manager, |
| 68 const std::string& url_id) | 68 const std::string& url_id) |
| 69 : sliding_window_period_( | 69 : sliding_window_period_( |
| 70 base::TimeDelta::FromMilliseconds(kDefaultSlidingWindowPeriodMs)), | 70 base::TimeDelta::FromMilliseconds(kDefaultSlidingWindowPeriodMs)), |
| 71 max_send_threshold_(kDefaultMaxSendThreshold), | 71 max_send_threshold_(kDefaultMaxSendThreshold), |
| 72 is_backoff_disabled_(false), | 72 is_backoff_disabled_(false), |
| 73 backoff_entry_(&backoff_policy_), | 73 backoff_entry_(&backoff_policy_), |
| 74 manager_(manager), | 74 manager_(manager), |
| 75 url_id_(url_id), | 75 url_id_(url_id), |
| 76 net_log_(BoundNetLog::Make( | 76 net_log_( |
| 77 manager->net_log(), NetLog::SOURCE_EXPONENTIAL_BACKOFF_THROTTLING)) { | 77 BoundNetLog::Make(manager->net_log(), |
| 78 NetLog::SOURCE_EXPONENTIAL_BACKOFF_THROTTLING)) { |
| 78 DCHECK(manager_); | 79 DCHECK(manager_); |
| 79 Initialize(); | 80 Initialize(); |
| 80 } | 81 } |
| 81 | 82 |
| 82 URLRequestThrottlerEntry::URLRequestThrottlerEntry( | 83 URLRequestThrottlerEntry::URLRequestThrottlerEntry( |
| 83 URLRequestThrottlerManager* manager, | 84 URLRequestThrottlerManager* manager, |
| 84 const std::string& url_id, | 85 const std::string& url_id, |
| 85 int sliding_window_period_ms, | 86 int sliding_window_period_ms, |
| 86 int max_send_threshold, | 87 int max_send_threshold, |
| 87 int initial_backoff_ms, | 88 int initial_backoff_ms, |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 153 const URLRequest& request) const { | 154 const URLRequest& request) const { |
| 154 bool reject_request = false; | 155 bool reject_request = false; |
| 155 if (!is_backoff_disabled_ && !ExplicitUserRequest(request.load_flags()) && | 156 if (!is_backoff_disabled_ && !ExplicitUserRequest(request.load_flags()) && |
| 156 (!request.context()->network_delegate() || | 157 (!request.context()->network_delegate() || |
| 157 request.context()->network_delegate()->CanThrottleRequest(request)) && | 158 request.context()->network_delegate()->CanThrottleRequest(request)) && |
| 158 GetBackoffEntry()->ShouldRejectRequest()) { | 159 GetBackoffEntry()->ShouldRejectRequest()) { |
| 159 int num_failures = GetBackoffEntry()->failure_count(); | 160 int num_failures = GetBackoffEntry()->failure_count(); |
| 160 int release_after_ms = | 161 int release_after_ms = |
| 161 GetBackoffEntry()->GetTimeUntilRelease().InMilliseconds(); | 162 GetBackoffEntry()->GetTimeUntilRelease().InMilliseconds(); |
| 162 | 163 |
| 163 net_log_.AddEvent( | 164 net_log_.AddEvent(NetLog::TYPE_THROTTLING_REJECTED_REQUEST, |
| 164 NetLog::TYPE_THROTTLING_REJECTED_REQUEST, | 165 base::Bind(&NetLogRejectedRequestCallback, |
| 165 base::Bind(&NetLogRejectedRequestCallback, | 166 &url_id_, |
| 166 &url_id_, num_failures, release_after_ms)); | 167 num_failures, |
| 168 release_after_ms)); |
| 167 | 169 |
| 168 reject_request = true; | 170 reject_request = true; |
| 169 } | 171 } |
| 170 | 172 |
| 171 int reject_count = reject_request ? 1 : 0; | 173 int reject_count = reject_request ? 1 : 0; |
| 172 UMA_HISTOGRAM_ENUMERATION( | 174 UMA_HISTOGRAM_ENUMERATION("Throttling.RequestThrottled", reject_count, 2); |
| 173 "Throttling.RequestThrottled", reject_count, 2); | |
| 174 | 175 |
| 175 return reject_request; | 176 return reject_request; |
| 176 } | 177 } |
| 177 | 178 |
| 178 int64 URLRequestThrottlerEntry::ReserveSendingTimeForNextRequest( | 179 int64 URLRequestThrottlerEntry::ReserveSendingTimeForNextRequest( |
| 179 const base::TimeTicks& earliest_time) { | 180 const base::TimeTicks& earliest_time) { |
| 180 base::TimeTicks now = ImplGetTimeNow(); | 181 base::TimeTicks now = ImplGetTimeNow(); |
| 181 | 182 |
| 182 // If a lot of requests were successfully made recently, | 183 // If a lot of requests were successfully made recently, |
| 183 // sliding_window_release_time_ may be greater than | 184 // sliding_window_release_time_ may be greater than |
| 184 // exponential_backoff_release_time_. | 185 // exponential_backoff_release_time_. |
| 185 base::TimeTicks recommended_sending_time = | 186 base::TimeTicks recommended_sending_time = |
| 186 std::max(std::max(now, earliest_time), | 187 std::max(std::max(now, earliest_time), |
| 187 std::max(GetBackoffEntry()->GetReleaseTime(), | 188 std::max(GetBackoffEntry()->GetReleaseTime(), |
| 188 sliding_window_release_time_)); | 189 sliding_window_release_time_)); |
| 189 | 190 |
| 190 DCHECK(send_log_.empty() || | 191 DCHECK(send_log_.empty() || recommended_sending_time >= send_log_.back()); |
| 191 recommended_sending_time >= send_log_.back()); | |
| 192 // Log the new send event. | 192 // Log the new send event. |
| 193 send_log_.push(recommended_sending_time); | 193 send_log_.push(recommended_sending_time); |
| 194 | 194 |
| 195 sliding_window_release_time_ = recommended_sending_time; | 195 sliding_window_release_time_ = recommended_sending_time; |
| 196 | 196 |
| 197 // Drop the out-of-date events in the event list. | 197 // Drop the out-of-date events in the event list. |
| 198 // We don't need to worry that the queue may become empty during this | 198 // We don't need to worry that the queue may become empty during this |
| 199 // operation, since the last element is sliding_window_release_time_. | 199 // operation, since the last element is sliding_window_release_time_. |
| 200 while ((send_log_.front() + sliding_window_period_ <= | 200 while ((send_log_.front() + sliding_window_period_ <= |
| 201 sliding_window_release_time_) || | 201 sliding_window_release_time_) || |
| 202 send_log_.size() > static_cast<unsigned>(max_send_threshold_)) { | 202 send_log_.size() > static_cast<unsigned>(max_send_threshold_)) { |
| 203 send_log_.pop(); | 203 send_log_.pop(); |
| 204 } | 204 } |
| 205 | 205 |
| 206 // Check if there are too many send events in recent time. | 206 // Check if there are too many send events in recent time. |
| 207 if (send_log_.size() == static_cast<unsigned>(max_send_threshold_)) | 207 if (send_log_.size() == static_cast<unsigned>(max_send_threshold_)) |
| 208 sliding_window_release_time_ = send_log_.front() + sliding_window_period_; | 208 sliding_window_release_time_ = send_log_.front() + sliding_window_period_; |
| 209 | 209 |
| 210 return (recommended_sending_time - now).InMillisecondsRoundedUp(); | 210 return (recommended_sending_time - now).InMillisecondsRoundedUp(); |
| 211 } | 211 } |
| 212 | 212 |
| 213 base::TimeTicks | 213 base::TimeTicks URLRequestThrottlerEntry::GetExponentialBackoffReleaseTime() |
| 214 URLRequestThrottlerEntry::GetExponentialBackoffReleaseTime() const { | 214 const { |
| 215 // If a site opts out, it's likely because they have problems that trigger | 215 // If a site opts out, it's likely because they have problems that trigger |
| 216 // the back-off mechanism when it shouldn't be triggered, in which case | 216 // the back-off mechanism when it shouldn't be triggered, in which case |
| 217 // returning the calculated back-off release time would probably be the | 217 // returning the calculated back-off release time would probably be the |
| 218 // wrong thing to do (i.e. it would likely be too long). Therefore, we | 218 // wrong thing to do (i.e. it would likely be too long). Therefore, we |
| 219 // return "now" so that retries are not delayed. | 219 // return "now" so that retries are not delayed. |
| 220 if (is_backoff_disabled_) | 220 if (is_backoff_disabled_) |
| 221 return ImplGetTimeNow(); | 221 return ImplGetTimeNow(); |
| 222 | 222 |
| 223 return GetBackoffEntry()->GetReleaseTime(); | 223 return GetBackoffEntry()->GetReleaseTime(); |
| 224 } | 224 } |
| 225 | 225 |
| 226 void URLRequestThrottlerEntry::UpdateWithResponse( | 226 void URLRequestThrottlerEntry::UpdateWithResponse( |
| 227 const std::string& host, | 227 const std::string& host, |
| 228 const URLRequestThrottlerHeaderInterface* response) { | 228 const URLRequestThrottlerHeaderInterface* response) { |
| 229 if (IsConsideredError(response->GetResponseCode())) { | 229 if (IsConsideredError(response->GetResponseCode())) { |
| 230 GetBackoffEntry()->InformOfRequest(false); | 230 GetBackoffEntry()->InformOfRequest(false); |
| 231 } else { | 231 } else { |
| 232 GetBackoffEntry()->InformOfRequest(true); | 232 GetBackoffEntry()->InformOfRequest(true); |
| 233 | 233 |
| 234 std::string throttling_header = response->GetNormalizedValue( | 234 std::string throttling_header = |
| 235 kExponentialThrottlingHeader); | 235 response->GetNormalizedValue(kExponentialThrottlingHeader); |
| 236 if (!throttling_header.empty()) | 236 if (!throttling_header.empty()) |
| 237 HandleThrottlingHeader(throttling_header, host); | 237 HandleThrottlingHeader(throttling_header, host); |
| 238 } | 238 } |
| 239 } | 239 } |
| 240 | 240 |
| 241 void URLRequestThrottlerEntry::ReceivedContentWasMalformed(int response_code) { | 241 void URLRequestThrottlerEntry::ReceivedContentWasMalformed(int response_code) { |
| 242 // A malformed body can only occur when the request to fetch a resource | 242 // A malformed body can only occur when the request to fetch a resource |
| 243 // was successful. Therefore, in such a situation, we will receive one | 243 // was successful. Therefore, in such a situation, we will receive one |
| 244 // call to ReceivedContentWasMalformed() and one call to | 244 // call to ReceivedContentWasMalformed() and one call to |
| 245 // UpdateWithResponse() with a response categorized as "good". To end | 245 // UpdateWithResponse() with a response categorized as "good". To end |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 279 // 503 is explicitly documented as a temporary state where the server | 279 // 503 is explicitly documented as a temporary state where the server |
| 280 // is either overloaded or down for maintenance. | 280 // is either overloaded or down for maintenance. |
| 281 // 509 is the (non-standard but widely implemented) Bandwidth Limit Exceeded | 281 // 509 is the (non-standard but widely implemented) Bandwidth Limit Exceeded |
| 282 // status code, which might indicate DDoS. | 282 // status code, which might indicate DDoS. |
| 283 // | 283 // |
| 284 // We do not back off on 502 or 504, which are reported by gateways | 284 // We do not back off on 502 or 504, which are reported by gateways |
| 285 // (proxies) on timeouts or failures, because in many cases these requests | 285 // (proxies) on timeouts or failures, because in many cases these requests |
| 286 // have not made it to the destination server and so we do not actually | 286 // have not made it to the destination server and so we do not actually |
| 287 // know that it is down or busy. One degenerate case could be a proxy on | 287 // know that it is down or busy. One degenerate case could be a proxy on |
| 288 // localhost, where you are not actually connected to the network. | 288 // localhost, where you are not actually connected to the network. |
| 289 return (response_code == 500 || | 289 return (response_code == 500 || response_code == 503 || response_code == 509); |
| 290 response_code == 503 || | |
| 291 response_code == 509); | |
| 292 } | 290 } |
| 293 | 291 |
| 294 base::TimeTicks URLRequestThrottlerEntry::ImplGetTimeNow() const { | 292 base::TimeTicks URLRequestThrottlerEntry::ImplGetTimeNow() const { |
| 295 return base::TimeTicks::Now(); | 293 return base::TimeTicks::Now(); |
| 296 } | 294 } |
| 297 | 295 |
| 298 void URLRequestThrottlerEntry::HandleThrottlingHeader( | 296 void URLRequestThrottlerEntry::HandleThrottlingHeader( |
| 299 const std::string& header_value, | 297 const std::string& header_value, |
| 300 const std::string& host) { | 298 const std::string& host) { |
| 301 if (header_value == kExponentialThrottlingDisableValue) { | 299 if (header_value == kExponentialThrottlingDisableValue) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 312 BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() { | 310 BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() { |
| 313 return &backoff_entry_; | 311 return &backoff_entry_; |
| 314 } | 312 } |
| 315 | 313 |
| 316 // static | 314 // static |
| 317 bool URLRequestThrottlerEntry::ExplicitUserRequest(const int load_flags) { | 315 bool URLRequestThrottlerEntry::ExplicitUserRequest(const int load_flags) { |
| 318 return (load_flags & LOAD_MAYBE_USER_GESTURE) != 0; | 316 return (load_flags & LOAD_MAYBE_USER_GESTURE) != 0; |
| 319 } | 317 } |
| 320 | 318 |
| 321 } // namespace net | 319 } // namespace net |
| OLD | NEW |