1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/url_request/url_request_backoff_manager.h"
7 #include "base/logging.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/string_piece.h"
10 #include "base/strings/string_util.h"
11 #include "net/http/http_response_headers.h"
15 const uint16
URLRequestBackoffManager::kMinimumBackoffInSeconds
= 1;
16 const uint16
URLRequestBackoffManager::kMaximumBackoffInSeconds
= 50000;
17 const uint16
URLRequestBackoffManager::kNewEntriesBetweenCollecting
= 200;
19 URLRequestBackoffManager::URLRequestBackoffManager()
20 : new_entries_since_last_gc_(0) {
21 url_id_replacements_
.ClearPassword();
22 url_id_replacements_
.ClearUsername();
23 url_id_replacements_
.ClearQuery();
24 url_id_replacements_
.ClearRef();
26 NetworkChangeNotifier::AddIPAddressObserver(this);
27 NetworkChangeNotifier::AddConnectionTypeObserver(this);
30 URLRequestBackoffManager::~URLRequestBackoffManager() {
31 NetworkChangeNotifier::RemoveIPAddressObserver(this);
32 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
33 for (UrlEntryMap::iterator it
= url_entries_
.begin();
34 it
!= url_entries_
.end(); ++it
) {
40 void URLRequestBackoffManager::UpdateWithResponse(
42 HttpResponseHeaders
* headers
,
43 const base::Time
& response_time
) {
44 CalledOnValidThread();
45 base::TimeDelta result
;
46 if (GetBackoffTime(headers
, &result
)) {
47 new_entries_since_last_gc_
++;
48 std::string url_id
= GetIdFromUrl(url
);
49 url_entries_
[url_id
] =
50 new Entry(response_time
+ result
, response_time
+ result
* 1.1);
51 GarbageCollectEntriesIfNecessary();
55 bool URLRequestBackoffManager::ShouldRejectRequest(
57 const base::Time
& request_time
) {
58 CalledOnValidThread();
59 std::string url_id
= GetIdFromUrl(url
);
60 UrlEntryMap::iterator it
= url_entries_
.find(url_id
);
61 if (it
== url_entries_
.end())
63 Entry
* entry
= it
->second
;
64 if (request_time
< entry
->throttled_time
)
66 // Allow one request between throttled_time and release_time.
67 if (request_time
>= entry
->throttled_time
&&
68 request_time
< entry
->release_time
) {
76 void URLRequestBackoffManager::OnIPAddressChanged() {
80 void URLRequestBackoffManager::OnConnectionTypeChanged(
81 NetworkChangeNotifier::ConnectionType type
) {
85 int URLRequestBackoffManager::GetNumberOfEntriesForTests() const {
86 return url_entries_
.size();
89 void URLRequestBackoffManager::GarbageCollectEntriesIfNecessary() {
90 CalledOnValidThread();
91 if (new_entries_since_last_gc_
< kNewEntriesBetweenCollecting
)
94 new_entries_since_last_gc_
= 0;
95 UrlEntryMap::iterator it
= url_entries_
.begin();
96 while (it
!= url_entries_
.end()) {
97 Entry
* entry
= it
->second
;
98 if (entry
->IsOutDated()) {
99 url_entries_
.erase(it
++);
107 bool URLRequestBackoffManager::GetBackoffTime(HttpResponseHeaders
* headers
,
108 base::TimeDelta
* result
) const {
109 base::StringPiece
name("Backoff");
112 while (headers
->EnumerateHeader(&iter
, name
, &value
)) {
114 base::StringToInt64(value
, &seconds
);
115 if (seconds
>= kMinimumBackoffInSeconds
&&
116 seconds
<= kMaximumBackoffInSeconds
) {
117 *result
= base::TimeDelta::FromSeconds(seconds
);
124 std::string
URLRequestBackoffManager::GetIdFromUrl(const GURL
& url
) const {
126 return url
.possibly_invalid_spec();
128 GURL id
= url
.ReplaceComponents(url_id_replacements_
);
129 return base::StringToLowerASCII(id
.spec()).c_str();
132 void URLRequestBackoffManager::OnNetworkChange() {
133 CalledOnValidThread();
135 new_entries_since_last_gc_
= 0;
136 // Remove all entries.
137 for (UrlEntryMap::iterator it
= url_entries_
.begin();
138 it
!= url_entries_
.end(); ++it
) {
141 url_entries_
.clear();