blob: 23ffab916d4080e5c2e9ae72f1e6305c48087e3b [file] [log] [blame]
[email protected]fba65f7b2012-03-15 05:22:131// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]6b3f9642010-11-25 02:29:062// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/url_request/url_request_throttler_manager.h"
6
[email protected]b1a761e2011-02-14 23:17:477#include "base/logging.h"
[email protected]4dc3ad4f2013-06-11 07:15:508#include "base/strings/string_util.h"
tfarina7ba5a622016-02-23 23:21:449#include "net/base/url_util.h"
eroman87c53d62015-04-02 06:51:0710#include "net/log/net_log.h"
mikecirone8b85c432016-09-08 19:11:0011#include "net/log/net_log_event_type.h"
12#include "net/log/net_log_source_type.h"
[email protected]6b3f9642010-11-25 02:29:0613
14namespace net {
15
16const unsigned int URLRequestThrottlerManager::kMaximumNumberOfEntries = 1500;
17const unsigned int URLRequestThrottlerManager::kRequestsBetweenCollecting = 200;
18
[email protected]a73a2802012-05-02 19:20:1519URLRequestThrottlerManager::URLRequestThrottlerManager()
20 : requests_since_last_gc_(0),
[email protected]332a8c962013-07-17 22:31:2321 enable_thread_checks_(false),
[email protected]a73a2802012-05-02 19:20:1522 logged_for_localhost_disabled_(false),
23 registered_from_thread_(base::kInvalidThreadId) {
24 url_id_replacements_.ClearPassword();
25 url_id_replacements_.ClearUsername();
26 url_id_replacements_.ClearQuery();
27 url_id_replacements_.ClearRef();
28
29 NetworkChangeNotifier::AddIPAddressObserver(this);
[email protected]8bbc7a792012-05-24 11:30:0530 NetworkChangeNotifier::AddConnectionTypeObserver(this);
[email protected]a73a2802012-05-02 19:20:1531}
32
33URLRequestThrottlerManager::~URLRequestThrottlerManager() {
gab47aa7da2017-06-02 16:09:4334 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
[email protected]a73a2802012-05-02 19:20:1535 NetworkChangeNotifier::RemoveIPAddressObserver(this);
[email protected]8bbc7a792012-05-24 11:30:0536 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
[email protected]a73a2802012-05-02 19:20:1537
[email protected]a1d4ab072012-06-07 13:21:1538 // Since the manager object might conceivably go away before the
39 // entries, detach the entries' back-pointer to the manager.
[email protected]a73a2802012-05-02 19:20:1540 UrlEntryMap::iterator i = url_entries_.begin();
41 while (i != url_entries_.end()) {
[email protected]90499482013-06-01 00:39:5042 if (i->second.get() != NULL) {
[email protected]a73a2802012-05-02 19:20:1543 i->second->DetachManager();
44 }
45 ++i;
46 }
47
48 // Delete all entries.
49 url_entries_.clear();
[email protected]6b3f9642010-11-25 02:29:0650}
51
52scoped_refptr<URLRequestThrottlerEntryInterface>
53 URLRequestThrottlerManager::RegisterRequestUrl(const GURL &url) {
gab47aa7da2017-06-02 16:09:4354#if DCHECK_IS_ON()
55 DCHECK(!enable_thread_checks_ || thread_checker_.CalledOnValidThread());
56#endif
[email protected]30e427d2011-02-25 02:26:4757
[email protected]6b3f9642010-11-25 02:29:0658 // Normalize the url.
59 std::string url_id = GetIdFromUrl(url);
60
61 // Periodically garbage collect old entries.
62 GarbageCollectEntriesIfNecessary();
63
[email protected]82c71ba2011-05-27 18:51:5364 // Find the entry in the map or create a new NULL entry.
[email protected]30e427d2011-02-25 02:26:4765 scoped_refptr<URLRequestThrottlerEntry>& entry = url_entries_[url_id];
[email protected]82c71ba2011-05-27 18:51:5366
67 // If the entry exists but could be garbage collected at this point, we
68 // start with a fresh entry so that we possibly back off a bit less
69 // aggressively (i.e. this resets the error count when the entry's URL
70 // hasn't been requested in long enough).
71 if (entry.get() && entry->IsEntryOutdated()) {
72 entry = NULL;
73 }
74
75 // Create the entry if needed.
[email protected]2fd33ee92011-03-25 22:30:2176 if (entry.get() == NULL) {
[email protected]82c71ba2011-05-27 18:51:5377 entry = new URLRequestThrottlerEntry(this, url_id);
[email protected]2fd33ee92011-03-25 22:30:2178
79 // We only disable back-off throttling on an entry that we have
80 // just constructed. This is to allow unit tests to explicitly override
xunjieli041e9392015-05-19 21:51:3381 // the entry for localhost URLs.
[email protected]2fd33ee92011-03-25 22:30:2182 std::string host = url.host();
xunjieli041e9392015-05-19 21:51:3383 if (IsLocalhost(host)) {
[email protected]82c71ba2011-05-27 18:51:5384 if (!logged_for_localhost_disabled_ && IsLocalhost(host)) {
85 logged_for_localhost_disabled_ = true;
mikecirone8b85c432016-09-08 19:11:0086 net_log_.AddEvent(NetLogEventType::THROTTLING_DISABLED_FOR_HOST,
[email protected]55b8a6c12012-06-13 22:03:4287 NetLog::StringCallback("host", &host));
[email protected]82c71ba2011-05-27 18:51:5388 }
89
[email protected]332a8c962013-07-17 22:31:2390 // TODO(joi): Once sliding window is separate from back-off throttling,
91 // we can simply return a dummy implementation of
xunjieli041e9392015-05-19 21:51:3392 // URLRequestThrottlerEntryInterface here that never blocks anything.
[email protected]2fd33ee92011-03-25 22:30:2193 entry->DisableBackoffThrottling();
94 }
95 }
[email protected]6b3f9642010-11-25 02:29:0696
[email protected]30e427d2011-02-25 02:26:4797 return entry;
[email protected]6b3f9642010-11-25 02:29:0698}
99
[email protected]5394e422011-01-20 22:07:43100void URLRequestThrottlerManager::OverrideEntryForTests(
101 const GURL& url,
102 URLRequestThrottlerEntry* entry) {
[email protected]5394e422011-01-20 22:07:43103 // Normalize the url.
104 std::string url_id = GetIdFromUrl(url);
105
106 // Periodically garbage collect old entries.
107 GarbageCollectEntriesIfNecessary();
108
109 url_entries_[url_id] = entry;
110}
111
112void URLRequestThrottlerManager::EraseEntryForTests(const GURL& url) {
113 // Normalize the url.
114 std::string url_id = GetIdFromUrl(url);
115 url_entries_.erase(url_id);
116}
117
[email protected]332a8c962013-07-17 22:31:23118void URLRequestThrottlerManager::set_enable_thread_checks(bool enable) {
119 enable_thread_checks_ = enable;
120}
121
122bool URLRequestThrottlerManager::enable_thread_checks() const {
123 return enable_thread_checks_;
124}
125
[email protected]82c71ba2011-05-27 18:51:53126void URLRequestThrottlerManager::set_net_log(NetLog* net_log) {
127 DCHECK(net_log);
tfarina428341112016-09-22 13:38:20128 net_log_ = NetLogWithSource::Make(
mikecirone8b85c432016-09-08 19:11:00129 net_log, NetLogSourceType::EXPONENTIAL_BACKOFF_THROTTLING);
[email protected]82c71ba2011-05-27 18:51:53130}
131
132NetLog* URLRequestThrottlerManager::net_log() const {
[email protected]fba65f7b2012-03-15 05:22:13133 return net_log_.net_log();
[email protected]82c71ba2011-05-27 18:51:53134}
135
136void URLRequestThrottlerManager::OnIPAddressChanged() {
137 OnNetworkChange();
138}
139
[email protected]8bbc7a792012-05-24 11:30:05140void URLRequestThrottlerManager::OnConnectionTypeChanged(
141 NetworkChangeNotifier::ConnectionType type) {
[email protected]82c71ba2011-05-27 18:51:53142 OnNetworkChange();
143}
144
[email protected]6b3f9642010-11-25 02:29:06145std::string URLRequestThrottlerManager::GetIdFromUrl(const GURL& url) const {
146 if (!url.is_valid())
147 return url.possibly_invalid_spec();
148
[email protected]30e427d2011-02-25 02:26:47149 GURL id = url.ReplaceComponents(url_id_replacements_);
brettw8e2106d2015-08-11 19:30:22150 return base::ToLowerASCII(id.spec());
[email protected]6b3f9642010-11-25 02:29:06151}
152
[email protected]5394e422011-01-20 22:07:43153void URLRequestThrottlerManager::GarbageCollectEntriesIfNecessary() {
154 requests_since_last_gc_++;
155 if (requests_since_last_gc_ < kRequestsBetweenCollecting)
156 return;
[email protected]5394e422011-01-20 22:07:43157 requests_since_last_gc_ = 0;
[email protected]30e427d2011-02-25 02:26:47158
[email protected]5394e422011-01-20 22:07:43159 GarbageCollectEntries();
160}
161
[email protected]6b3f9642010-11-25 02:29:06162void URLRequestThrottlerManager::GarbageCollectEntries() {
[email protected]c35d5502011-03-02 01:27:14163 UrlEntryMap::iterator i = url_entries_.begin();
[email protected]30e427d2011-02-25 02:26:47164 while (i != url_entries_.end()) {
[email protected]a1077c342011-04-05 13:53:00165 if ((i->second)->IsEntryOutdated()) {
[email protected]30e427d2011-02-25 02:26:47166 url_entries_.erase(i++);
167 } else {
168 ++i;
169 }
[email protected]6b3f9642010-11-25 02:29:06170 }
171
172 // In case something broke we want to make sure not to grow indefinitely.
173 while (url_entries_.size() > kMaximumNumberOfEntries) {
174 url_entries_.erase(url_entries_.begin());
175 }
176}
177
[email protected]82c71ba2011-05-27 18:51:53178void URLRequestThrottlerManager::OnNetworkChange() {
179 // Remove all entries. Any entries that in-flight requests have a reference
180 // to will live until those requests end, and these entries may be
181 // inconsistent with new entries for the same URLs, but since what we
[email protected]8bbc7a792012-05-24 11:30:05182 // want is a clean slate for the new connection type, this is OK.
[email protected]82c71ba2011-05-27 18:51:53183 url_entries_.clear();
184 requests_since_last_gc_ = 0;
185}
186
[email protected]6b3f9642010-11-25 02:29:06187} // namespace net