OLD | NEW |
1 // Copyright (c) 2011 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_manager.h" | 5 #include "net/url_request/url_request_throttler_manager.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/metrics/field_trial.h" |
| 9 #include "base/metrics/histogram.h" |
8 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| 11 #include "net/base/net_log.h" |
9 #include "net/base/net_util.h" | 12 #include "net/base/net_util.h" |
10 | 13 |
11 namespace net { | 14 namespace net { |
12 | 15 |
13 const unsigned int URLRequestThrottlerManager::kMaximumNumberOfEntries = 1500; | 16 const unsigned int URLRequestThrottlerManager::kMaximumNumberOfEntries = 1500; |
14 const unsigned int URLRequestThrottlerManager::kRequestsBetweenCollecting = 200; | 17 const unsigned int URLRequestThrottlerManager::kRequestsBetweenCollecting = 200; |
15 | 18 |
16 URLRequestThrottlerManager* URLRequestThrottlerManager::GetInstance() { | 19 URLRequestThrottlerManager* URLRequestThrottlerManager::GetInstance() { |
17 return Singleton<URLRequestThrottlerManager>::get(); | 20 return Singleton<URLRequestThrottlerManager>::get(); |
18 } | 21 } |
19 | 22 |
20 scoped_refptr<URLRequestThrottlerEntryInterface> | 23 scoped_refptr<URLRequestThrottlerEntryInterface> |
21 URLRequestThrottlerManager::RegisterRequestUrl(const GURL &url) { | 24 URLRequestThrottlerManager::RegisterRequestUrl(const GURL &url) { |
22 DCHECK(!enable_thread_checks_ || CalledOnValidThread()); | 25 DCHECK(!enable_thread_checks_ || CalledOnValidThread()); |
23 | 26 |
24 // Normalize the url. | 27 // Normalize the url. |
25 std::string url_id = GetIdFromUrl(url); | 28 std::string url_id = GetIdFromUrl(url); |
26 | 29 |
27 // Periodically garbage collect old entries. | 30 // Periodically garbage collect old entries. |
28 GarbageCollectEntriesIfNecessary(); | 31 GarbageCollectEntriesIfNecessary(); |
29 | 32 |
30 // Find the entry in the map or create it. | 33 // Find the entry in the map or create a new NULL entry. |
31 scoped_refptr<URLRequestThrottlerEntry>& entry = url_entries_[url_id]; | 34 scoped_refptr<URLRequestThrottlerEntry>& entry = url_entries_[url_id]; |
| 35 |
| 36 // If the entry exists but could be garbage collected at this point, we |
| 37 // start with a fresh entry so that we possibly back off a bit less |
| 38 // aggressively (i.e. this resets the error count when the entry's URL |
| 39 // hasn't been requested in long enough). |
| 40 if (entry.get() && entry->IsEntryOutdated()) { |
| 41 entry = NULL; |
| 42 } |
| 43 |
| 44 // Create the entry if needed. |
32 if (entry.get() == NULL) { | 45 if (entry.get() == NULL) { |
33 entry = new URLRequestThrottlerEntry(this); | 46 entry = new URLRequestThrottlerEntry(this, url_id); |
34 | 47 |
35 // We only disable back-off throttling on an entry that we have | 48 // We only disable back-off throttling on an entry that we have |
36 // just constructed. This is to allow unit tests to explicitly override | 49 // just constructed. This is to allow unit tests to explicitly override |
37 // the entry for localhost URLs. Given that we do not attempt to | 50 // the entry for localhost URLs. Given that we do not attempt to |
38 // disable throttling for entries already handed out (see comment | 51 // disable throttling for entries already handed out (see comment |
39 // in AddToOptOutList), this is not a problem. | 52 // in AddToOptOutList), this is not a problem. |
40 std::string host = url.host(); | 53 std::string host = url.host(); |
41 if (opt_out_hosts_.find(host) != opt_out_hosts_.end() || | 54 if (opt_out_hosts_.find(host) != opt_out_hosts_.end() || |
42 IsLocalhost(host)) { | 55 IsLocalhost(host)) { |
| 56 if (!logged_for_localhost_disabled_ && IsLocalhost(host)) { |
| 57 logged_for_localhost_disabled_ = true; |
| 58 net_log_->AddEvent( |
| 59 NetLog::TYPE_THROTTLING_DISABLED_FOR_HOST, |
| 60 make_scoped_refptr(new NetLogStringParameter("host", host))); |
| 61 } |
| 62 |
43 // TODO(joi): Once sliding window is separate from back-off throttling, | 63 // TODO(joi): Once sliding window is separate from back-off throttling, |
44 // we can simply return a dummy implementation of | 64 // we can simply return a dummy implementation of |
45 // URLRequestThrottlerEntryInterface here that never blocks anything (and | 65 // URLRequestThrottlerEntryInterface here that never blocks anything (and |
46 // not keep entries in url_entries_ for opted-out sites). | 66 // not keep entries in url_entries_ for opted-out sites). |
47 entry->DisableBackoffThrottling(); | 67 entry->DisableBackoffThrottling(); |
48 } | 68 } |
49 } | 69 } |
50 | 70 |
51 return entry; | 71 return entry; |
52 } | 72 } |
53 | 73 |
54 void URLRequestThrottlerManager::AddToOptOutList(const std::string& host) { | 74 void URLRequestThrottlerManager::AddToOptOutList(const std::string& host) { |
55 // There is an edge case here that we are not handling, to keep things | 75 // There is an edge case here that we are not handling, to keep things |
56 // simple. If a host starts adding the opt-out header to its responses | 76 // simple. If a host starts adding the opt-out header to its responses |
57 // after there are already one or more entries in url_entries_ for that | 77 // after there are already one or more entries in url_entries_ for that |
58 // host, the pre-existing entries may still perform back-off throttling. | 78 // host, the pre-existing entries may still perform back-off throttling. |
59 // In practice, this would almost never occur. | 79 // In practice, this would almost never occur. |
60 opt_out_hosts_.insert(host); | 80 if (opt_out_hosts_.find(host) == opt_out_hosts_.end()) { |
| 81 UMA_HISTOGRAM_COUNTS("Throttling.SiteOptedOut", 1); |
| 82 if (base::FieldTrialList::TrialExists("ThrottlingEnabled")) { |
| 83 UMA_HISTOGRAM_COUNTS(base::FieldTrial::MakeName( |
| 84 "Throttling.SiteOptedOut", "ThrottlingEnabled"), 1); |
| 85 } |
| 86 |
| 87 net_log_->EndEvent( |
| 88 NetLog::TYPE_THROTTLING_DISABLED_FOR_HOST, |
| 89 make_scoped_refptr(new NetLogStringParameter("host", host))); |
| 90 opt_out_hosts_.insert(host); |
| 91 } |
61 } | 92 } |
62 | 93 |
63 void URLRequestThrottlerManager::OverrideEntryForTests( | 94 void URLRequestThrottlerManager::OverrideEntryForTests( |
64 const GURL& url, | 95 const GURL& url, |
65 URLRequestThrottlerEntry* entry) { | 96 URLRequestThrottlerEntry* entry) { |
66 // Normalize the url. | 97 // Normalize the url. |
67 std::string url_id = GetIdFromUrl(url); | 98 std::string url_id = GetIdFromUrl(url); |
68 | 99 |
69 // Periodically garbage collect old entries. | 100 // Periodically garbage collect old entries. |
70 GarbageCollectEntriesIfNecessary(); | 101 GarbageCollectEntriesIfNecessary(); |
(...skipping 16 matching lines...) Expand all Loading... |
87 } | 118 } |
88 | 119 |
89 void URLRequestThrottlerManager::set_enforce_throttling(bool enforce) { | 120 void URLRequestThrottlerManager::set_enforce_throttling(bool enforce) { |
90 enforce_throttling_ = enforce; | 121 enforce_throttling_ = enforce; |
91 } | 122 } |
92 | 123 |
93 bool URLRequestThrottlerManager::enforce_throttling() { | 124 bool URLRequestThrottlerManager::enforce_throttling() { |
94 return enforce_throttling_; | 125 return enforce_throttling_; |
95 } | 126 } |
96 | 127 |
| 128 void URLRequestThrottlerManager::set_net_log(NetLog* net_log) { |
| 129 DCHECK(net_log); |
| 130 NetLog::Source source(NetLog::SOURCE_EXPONENTIAL_BACKOFF_THROTTLING, |
| 131 net_log->NextID()); |
| 132 net_log_.reset(new BoundNetLog(source, net_log)); |
| 133 } |
| 134 |
| 135 NetLog* URLRequestThrottlerManager::net_log() const { |
| 136 return net_log_->net_log(); |
| 137 } |
| 138 |
| 139 void URLRequestThrottlerManager::OnIPAddressChanged() { |
| 140 OnNetworkChange(); |
| 141 } |
| 142 |
| 143 void URLRequestThrottlerManager::OnOnlineStateChanged(bool online) { |
| 144 OnNetworkChange(); |
| 145 } |
| 146 |
97 // TODO(joi): Turn throttling on by default when appropriate. | 147 // TODO(joi): Turn throttling on by default when appropriate. |
98 URLRequestThrottlerManager::URLRequestThrottlerManager() | 148 URLRequestThrottlerManager::URLRequestThrottlerManager() |
99 : requests_since_last_gc_(0), | 149 : requests_since_last_gc_(0), |
100 enforce_throttling_(false), | 150 enforce_throttling_(false), |
101 enable_thread_checks_(false) { | 151 enable_thread_checks_(false), |
| 152 logged_for_localhost_disabled_(false) { |
102 // Construction/destruction is on main thread (because BrowserMain | 153 // Construction/destruction is on main thread (because BrowserMain |
103 // retrieves an instance to call InitializeOptions), but is from then on | 154 // retrieves an instance to call InitializeOptions), but is from then on |
104 // used on I/O thread. | 155 // used on I/O thread. |
105 DetachFromThread(); | 156 DetachFromThread(); |
106 | 157 |
107 url_id_replacements_.ClearPassword(); | 158 url_id_replacements_.ClearPassword(); |
108 url_id_replacements_.ClearUsername(); | 159 url_id_replacements_.ClearUsername(); |
109 url_id_replacements_.ClearQuery(); | 160 url_id_replacements_.ClearQuery(); |
110 url_id_replacements_.ClearRef(); | 161 url_id_replacements_.ClearRef(); |
| 162 |
| 163 // Make sure there is always a net_log_ instance, even if it logs to |
| 164 // nowhere. |
| 165 net_log_.reset(new BoundNetLog()); |
| 166 |
| 167 NetworkChangeNotifier::AddIPAddressObserver(this); |
| 168 NetworkChangeNotifier::AddOnlineStateObserver(this); |
111 } | 169 } |
112 | 170 |
113 URLRequestThrottlerManager::~URLRequestThrottlerManager() { | 171 URLRequestThrottlerManager::~URLRequestThrottlerManager() { |
114 // Destruction is on main thread (AtExit), but real use is on I/O thread. | 172 // Destruction is on main thread (AtExit), but real use is on I/O thread. |
115 DetachFromThread(); | 173 DetachFromThread(); |
116 | 174 |
| 175 NetworkChangeNotifier::RemoveIPAddressObserver(this); |
| 176 NetworkChangeNotifier::RemoveOnlineStateObserver(this); |
| 177 |
117 // Since, for now, the manager object might conceivably go away before | 178 // Since, for now, the manager object might conceivably go away before |
118 // the entries, detach the entries' back-pointer to the manager. | 179 // the entries, detach the entries' back-pointer to the manager. |
119 // | 180 // |
120 // TODO(joi): Revisit whether to make entries non-refcounted. | 181 // TODO(joi): Revisit whether to make entries non-refcounted. |
121 UrlEntryMap::iterator i = url_entries_.begin(); | 182 UrlEntryMap::iterator i = url_entries_.begin(); |
122 while (i != url_entries_.end()) { | 183 while (i != url_entries_.end()) { |
123 if (i->second != NULL) { | 184 if (i->second != NULL) { |
124 i->second->DetachManager(); | 185 i->second->DetachManager(); |
125 } | 186 } |
126 ++i; | 187 ++i; |
(...skipping 29 matching lines...) Expand all Loading... |
156 ++i; | 217 ++i; |
157 } | 218 } |
158 } | 219 } |
159 | 220 |
160 // In case something broke we want to make sure not to grow indefinitely. | 221 // In case something broke we want to make sure not to grow indefinitely. |
161 while (url_entries_.size() > kMaximumNumberOfEntries) { | 222 while (url_entries_.size() > kMaximumNumberOfEntries) { |
162 url_entries_.erase(url_entries_.begin()); | 223 url_entries_.erase(url_entries_.begin()); |
163 } | 224 } |
164 } | 225 } |
165 | 226 |
| 227 void URLRequestThrottlerManager::OnNetworkChange() { |
| 228 // Remove all entries. Any entries that in-flight requests have a reference |
| 229 // to will live until those requests end, and these entries may be |
| 230 // inconsistent with new entries for the same URLs, but since what we |
| 231 // want is a clean slate for the new connection state, this is OK. |
| 232 url_entries_.clear(); |
| 233 requests_since_last_gc_ = 0; |
| 234 } |
| 235 |
166 } // namespace net | 236 } // namespace net |
OLD | NEW |