Revert "Fix broken channel icon in chrome://help on CrOS" and try again
[chromium-blink-merge.git] / extensions / browser / extension_throttle_manager.cc
blobf59b1b3acd4920b83ab019565fd12d86b9e45933
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 "extensions/browser/extension_throttle_manager.h"
7 #include "base/logging.h"
8 #include "base/metrics/field_trial.h"
9 #include "base/metrics/histogram.h"
10 #include "base/strings/string_util.h"
11 #include "extensions/browser/extension_request_limiting_throttle.h"
12 #include "extensions/common/constants.h"
13 #include "net/base/net_util.h"
14 #include "net/log/net_log.h"
15 #include "net/url_request/url_request.h"
17 namespace extensions {
19 const unsigned int ExtensionThrottleManager::kMaximumNumberOfEntries = 1500;
20 const unsigned int ExtensionThrottleManager::kRequestsBetweenCollecting = 200;
22 ExtensionThrottleManager::ExtensionThrottleManager()
23 : requests_since_last_gc_(0),
24 enable_thread_checks_(false),
25 logged_for_localhost_disabled_(false),
26 registered_from_thread_(base::kInvalidThreadId),
27 ignore_user_gesture_load_flag_for_tests_(false) {
28 url_id_replacements_.ClearPassword();
29 url_id_replacements_.ClearUsername();
30 url_id_replacements_.ClearQuery();
31 url_id_replacements_.ClearRef();
33 net::NetworkChangeNotifier::AddIPAddressObserver(this);
34 net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
37 ExtensionThrottleManager::~ExtensionThrottleManager() {
38 net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
39 net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
41 // Since the manager object might conceivably go away before the
42 // entries, detach the entries' back-pointer to the manager.
43 UrlEntryMap::iterator i = url_entries_.begin();
44 while (i != url_entries_.end()) {
45 if (i->second.get() != NULL) {
46 i->second->DetachManager();
48 ++i;
51 // Delete all entries.
52 url_entries_.clear();
55 scoped_ptr<content::ResourceThrottle>
56 ExtensionThrottleManager::MaybeCreateThrottle(const net::URLRequest* request) {
57 if (request->first_party_for_cookies().scheme() !=
58 extensions::kExtensionScheme) {
59 return nullptr;
61 return make_scoped_ptr(
62 new extensions::ExtensionRequestLimitingThrottle(request, this));
65 scoped_refptr<ExtensionThrottleEntryInterface>
66 ExtensionThrottleManager::RegisterRequestUrl(const GURL& url) {
67 DCHECK(!enable_thread_checks_ || CalledOnValidThread());
69 // Normalize the url.
70 std::string url_id = GetIdFromUrl(url);
72 // Periodically garbage collect old entries.
73 GarbageCollectEntriesIfNecessary();
75 // Find the entry in the map or create a new NULL entry.
76 scoped_refptr<ExtensionThrottleEntry>& entry = url_entries_[url_id];
78 // If the entry exists but could be garbage collected at this point, we
79 // start with a fresh entry so that we possibly back off a bit less
80 // aggressively (i.e. this resets the error count when the entry's URL
81 // hasn't been requested in long enough).
82 if (entry.get() && entry->IsEntryOutdated()) {
83 entry = NULL;
86 // Create the entry if needed.
87 if (entry.get() == NULL) {
88 if (backoff_policy_for_tests_) {
89 entry = new ExtensionThrottleEntry(
90 this, url_id, backoff_policy_for_tests_.get(),
91 ignore_user_gesture_load_flag_for_tests_);
92 } else {
93 entry = new ExtensionThrottleEntry(
94 this, url_id, ignore_user_gesture_load_flag_for_tests_);
97 // We only disable back-off throttling on an entry that we have
98 // just constructed. This is to allow unit tests to explicitly override
99 // the entry for localhost URLs.
100 std::string host = url.host();
101 if (net::IsLocalhost(host)) {
102 if (!logged_for_localhost_disabled_ && net::IsLocalhost(host)) {
103 logged_for_localhost_disabled_ = true;
104 net_log_.AddEvent(net::NetLog::TYPE_THROTTLING_DISABLED_FOR_HOST,
105 net::NetLog::StringCallback("host", &host));
108 // TODO(joi): Once sliding window is separate from back-off throttling,
109 // we can simply return a dummy implementation of
110 // ExtensionThrottleEntryInterface here that never blocks anything.
111 entry->DisableBackoffThrottling();
115 return entry;
118 void ExtensionThrottleManager::SetBackoffPolicyForTests(
119 scoped_ptr<net::BackoffEntry::Policy> policy) {
120 backoff_policy_for_tests_ = policy.Pass();
123 void ExtensionThrottleManager::OverrideEntryForTests(
124 const GURL& url,
125 ExtensionThrottleEntry* entry) {
126 // Normalize the url.
127 std::string url_id = GetIdFromUrl(url);
129 // Periodically garbage collect old entries.
130 GarbageCollectEntriesIfNecessary();
132 url_entries_[url_id] = entry;
135 void ExtensionThrottleManager::EraseEntryForTests(const GURL& url) {
136 // Normalize the url.
137 std::string url_id = GetIdFromUrl(url);
138 url_entries_.erase(url_id);
141 void ExtensionThrottleManager::SetIgnoreUserGestureLoadFlagForTests(
142 bool ignore_user_gesture_load_flag_for_tests) {
143 ignore_user_gesture_load_flag_for_tests_ = true;
146 void ExtensionThrottleManager::set_enable_thread_checks(bool enable) {
147 enable_thread_checks_ = enable;
150 bool ExtensionThrottleManager::enable_thread_checks() const {
151 return enable_thread_checks_;
154 void ExtensionThrottleManager::set_net_log(net::NetLog* net_log) {
155 DCHECK(net_log);
156 net_log_ = net::BoundNetLog::Make(
157 net_log, net::NetLog::SOURCE_EXPONENTIAL_BACKOFF_THROTTLING);
160 net::NetLog* ExtensionThrottleManager::net_log() const {
161 return net_log_.net_log();
164 void ExtensionThrottleManager::OnIPAddressChanged() {
165 OnNetworkChange();
168 void ExtensionThrottleManager::OnConnectionTypeChanged(
169 net::NetworkChangeNotifier::ConnectionType type) {
170 OnNetworkChange();
173 std::string ExtensionThrottleManager::GetIdFromUrl(const GURL& url) const {
174 if (!url.is_valid())
175 return url.possibly_invalid_spec();
177 GURL id = url.ReplaceComponents(url_id_replacements_);
178 return base::ToLowerASCII(id.spec());
181 void ExtensionThrottleManager::GarbageCollectEntriesIfNecessary() {
182 requests_since_last_gc_++;
183 if (requests_since_last_gc_ < kRequestsBetweenCollecting)
184 return;
185 requests_since_last_gc_ = 0;
187 GarbageCollectEntries();
190 void ExtensionThrottleManager::GarbageCollectEntries() {
191 UrlEntryMap::iterator i = url_entries_.begin();
192 while (i != url_entries_.end()) {
193 if ((i->second)->IsEntryOutdated()) {
194 url_entries_.erase(i++);
195 } else {
196 ++i;
200 // In case something broke we want to make sure not to grow indefinitely.
201 while (url_entries_.size() > kMaximumNumberOfEntries) {
202 url_entries_.erase(url_entries_.begin());
206 void ExtensionThrottleManager::OnNetworkChange() {
207 // Remove all entries. Any entries that in-flight requests have a reference
208 // to will live until those requests end, and these entries may be
209 // inconsistent with new entries for the same URLs, but since what we
210 // want is a clean slate for the new connection type, this is OK.
211 url_entries_.clear();
212 requests_since_last_gc_ = 0;
215 } // namespace extensions