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