Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / url_request / url_request_throttler_manager.cc
blob3f08e9e1ac817da746345c7e1429123f8c0a1e19
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
3 // found in the LICENSE file.
5 #include "net/url_request/url_request_throttler_manager.h"
7 #include "base/logging.h"
8 #include "base/strings/string_util.h"
9 #include "net/base/net_util.h"
10 #include "net/log/net_log.h"
12 namespace net {
14 const unsigned int URLRequestThrottlerManager::kMaximumNumberOfEntries = 1500;
15 const unsigned int URLRequestThrottlerManager::kRequestsBetweenCollecting = 200;
17 URLRequestThrottlerManager::URLRequestThrottlerManager()
18 : requests_since_last_gc_(0),
19 enable_thread_checks_(false),
20 logged_for_localhost_disabled_(false),
21 registered_from_thread_(base::kInvalidThreadId) {
22 url_id_replacements_.ClearPassword();
23 url_id_replacements_.ClearUsername();
24 url_id_replacements_.ClearQuery();
25 url_id_replacements_.ClearRef();
27 NetworkChangeNotifier::AddIPAddressObserver(this);
28 NetworkChangeNotifier::AddConnectionTypeObserver(this);
31 URLRequestThrottlerManager::~URLRequestThrottlerManager() {
32 NetworkChangeNotifier::RemoveIPAddressObserver(this);
33 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
35 // Since the manager object might conceivably go away before the
36 // entries, detach the entries' back-pointer to the manager.
37 UrlEntryMap::iterator i = url_entries_.begin();
38 while (i != url_entries_.end()) {
39 if (i->second.get() != NULL) {
40 i->second->DetachManager();
42 ++i;
45 // Delete all entries.
46 url_entries_.clear();
49 scoped_refptr<URLRequestThrottlerEntryInterface>
50 URLRequestThrottlerManager::RegisterRequestUrl(const GURL &url) {
51 DCHECK(!enable_thread_checks_ || CalledOnValidThread());
53 // Normalize the url.
54 std::string url_id = GetIdFromUrl(url);
56 // Periodically garbage collect old entries.
57 GarbageCollectEntriesIfNecessary();
59 // Find the entry in the map or create a new NULL entry.
60 scoped_refptr<URLRequestThrottlerEntry>& entry = url_entries_[url_id];
62 // If the entry exists but could be garbage collected at this point, we
63 // start with a fresh entry so that we possibly back off a bit less
64 // aggressively (i.e. this resets the error count when the entry's URL
65 // hasn't been requested in long enough).
66 if (entry.get() && entry->IsEntryOutdated()) {
67 entry = NULL;
70 // Create the entry if needed.
71 if (entry.get() == NULL) {
72 entry = new URLRequestThrottlerEntry(this, url_id);
74 // We only disable back-off throttling on an entry that we have
75 // just constructed. This is to allow unit tests to explicitly override
76 // the entry for localhost URLs.
77 std::string host = url.host();
78 if (IsLocalhost(host)) {
79 if (!logged_for_localhost_disabled_ && IsLocalhost(host)) {
80 logged_for_localhost_disabled_ = true;
81 net_log_.AddEvent(NetLog::TYPE_THROTTLING_DISABLED_FOR_HOST,
82 NetLog::StringCallback("host", &host));
85 // TODO(joi): Once sliding window is separate from back-off throttling,
86 // we can simply return a dummy implementation of
87 // URLRequestThrottlerEntryInterface here that never blocks anything.
88 entry->DisableBackoffThrottling();
92 return entry;
95 void URLRequestThrottlerManager::OverrideEntryForTests(
96 const GURL& url,
97 URLRequestThrottlerEntry* entry) {
98 // Normalize the url.
99 std::string url_id = GetIdFromUrl(url);
101 // Periodically garbage collect old entries.
102 GarbageCollectEntriesIfNecessary();
104 url_entries_[url_id] = entry;
107 void URLRequestThrottlerManager::EraseEntryForTests(const GURL& url) {
108 // Normalize the url.
109 std::string url_id = GetIdFromUrl(url);
110 url_entries_.erase(url_id);
113 void URLRequestThrottlerManager::set_enable_thread_checks(bool enable) {
114 enable_thread_checks_ = enable;
117 bool URLRequestThrottlerManager::enable_thread_checks() const {
118 return enable_thread_checks_;
121 void URLRequestThrottlerManager::set_net_log(NetLog* net_log) {
122 DCHECK(net_log);
123 net_log_ = BoundNetLog::Make(net_log,
124 NetLog::SOURCE_EXPONENTIAL_BACKOFF_THROTTLING);
127 NetLog* URLRequestThrottlerManager::net_log() const {
128 return net_log_.net_log();
131 void URLRequestThrottlerManager::OnIPAddressChanged() {
132 OnNetworkChange();
135 void URLRequestThrottlerManager::OnConnectionTypeChanged(
136 NetworkChangeNotifier::ConnectionType type) {
137 OnNetworkChange();
140 std::string URLRequestThrottlerManager::GetIdFromUrl(const GURL& url) const {
141 if (!url.is_valid())
142 return url.possibly_invalid_spec();
144 GURL id = url.ReplaceComponents(url_id_replacements_);
145 return base::ToLowerASCII(id.spec());
148 void URLRequestThrottlerManager::GarbageCollectEntriesIfNecessary() {
149 requests_since_last_gc_++;
150 if (requests_since_last_gc_ < kRequestsBetweenCollecting)
151 return;
152 requests_since_last_gc_ = 0;
154 GarbageCollectEntries();
157 void URLRequestThrottlerManager::GarbageCollectEntries() {
158 UrlEntryMap::iterator i = url_entries_.begin();
159 while (i != url_entries_.end()) {
160 if ((i->second)->IsEntryOutdated()) {
161 url_entries_.erase(i++);
162 } else {
163 ++i;
167 // In case something broke we want to make sure not to grow indefinitely.
168 while (url_entries_.size() > kMaximumNumberOfEntries) {
169 url_entries_.erase(url_entries_.begin());
173 void URLRequestThrottlerManager::OnNetworkChange() {
174 // Remove all entries. Any entries that in-flight requests have a reference
175 // to will live until those requests end, and these entries may be
176 // inconsistent with new entries for the same URLs, but since what we
177 // want is a clean slate for the new connection type, this is OK.
178 url_entries_.clear();
179 requests_since_last_gc_ = 0;
182 } // namespace net