| 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 |