blob: f03661ebab5d26cfd86efe331e5206a2b28fe416 [file] [log] [blame]
xunjieli413a68782015-06-16 17:15:431// 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.
4
Chris Mumford3f0eda92018-07-23 14:51:175#include "extensions/renderer/extension_throttle_manager.h"
xunjieli413a68782015-06-16 17:15:436
dchenge59eca1602015-12-18 17:48:007#include <utility>
8
xunjieli413a68782015-06-16 17:15:439#include "base/logging.h"
10#include "base/metrics/field_trial.h"
11#include "base/metrics/histogram.h"
12#include "base/strings/string_util.h"
xunjieli413a68782015-06-16 17:15:4313#include "extensions/common/constants.h"
Chris Mumford3f0eda92018-07-23 14:51:1714#include "extensions/renderer/extension_url_loader_throttle.h"
tfarina7ba5a622016-02-23 23:21:4415#include "net/base/url_util.h"
Chris Mumford3f0eda92018-07-23 14:51:1716#include "third_party/blink/public/platform/web_url.h"
17#include "third_party/blink/public/platform/web_url_request.h"
xunjieli413a68782015-06-16 17:15:4318
19namespace extensions {
20
21const unsigned int ExtensionThrottleManager::kMaximumNumberOfEntries = 1500;
22const unsigned int ExtensionThrottleManager::kRequestsBetweenCollecting = 200;
23
24ExtensionThrottleManager::ExtensionThrottleManager()
25 : requests_since_last_gc_(0),
xunjieli413a68782015-06-16 17:15:4326 ignore_user_gesture_load_flag_for_tests_(false) {
27 url_id_replacements_.ClearPassword();
28 url_id_replacements_.ClearUsername();
29 url_id_replacements_.ClearQuery();
30 url_id_replacements_.ClearRef();
xunjieli413a68782015-06-16 17:15:4331}
32
33ExtensionThrottleManager::~ExtensionThrottleManager() {
Chris Mumford3f0eda92018-07-23 14:51:1734 base::AutoLock auto_lock(lock_);
xunjieli413a68782015-06-16 17:15:4335 // Delete all entries.
36 url_entries_.clear();
37}
38
Chris Mumford3f0eda92018-07-23 14:51:1739std::unique_ptr<content::URLLoaderThrottle>
40ExtensionThrottleManager::MaybeCreateURLLoaderThrottle(
41 const blink::WebURLRequest& request) {
42 if (!request.SiteForCookies().ProtocolIs(extensions::kExtensionScheme))
xunjieli413a68782015-06-16 17:15:4343 return nullptr;
Chris Mumford3f0eda92018-07-23 14:51:1744 return std::make_unique<ExtensionURLLoaderThrottle>(this);
xunjieli413a68782015-06-16 17:15:4345}
46
Chris Mumfordc54b0c342018-07-23 21:29:4647ExtensionThrottleEntry* ExtensionThrottleManager::RegisterRequestUrl(
48 const GURL& url) {
Chris Mumford3f0eda92018-07-23 14:51:1749 // Internal function, no locking.
xunjieli413a68782015-06-16 17:15:4350
51 // Normalize the url.
52 std::string url_id = GetIdFromUrl(url);
53
54 // Periodically garbage collect old entries.
55 GarbageCollectEntriesIfNecessary();
56
Chris Mumfordc54b0c342018-07-23 21:29:4657 // Find the entry in the map or create a new null entry.
58 std::unique_ptr<ExtensionThrottleEntry>& entry = url_entries_[url_id];
xunjieli413a68782015-06-16 17:15:4359
60 // If the entry exists but could be garbage collected at this point, we
61 // start with a fresh entry so that we possibly back off a bit less
62 // aggressively (i.e. this resets the error count when the entry's URL
63 // hasn't been requested in long enough).
Chris Mumfordc54b0c342018-07-23 21:29:4664 if (entry && entry->IsEntryOutdated())
65 entry.reset();
xunjieli413a68782015-06-16 17:15:4366
67 // Create the entry if needed.
Chris Mumfordc54b0c342018-07-23 21:29:4668 if (!entry) {
xunjielie484e2d62015-06-19 14:31:2169 if (backoff_policy_for_tests_) {
Chris Mumfordc54b0c342018-07-23 21:29:4670 entry.reset(
71 new ExtensionThrottleEntry(url_id, backoff_policy_for_tests_.get(),
72 ignore_user_gesture_load_flag_for_tests_));
xunjielie484e2d62015-06-19 14:31:2173 } else {
Chris Mumfordc54b0c342018-07-23 21:29:4674 entry.reset(new ExtensionThrottleEntry(
75 url_id, ignore_user_gesture_load_flag_for_tests_));
xunjielie484e2d62015-06-19 14:31:2176 }
xunjieli413a68782015-06-16 17:15:4377
78 // We only disable back-off throttling on an entry that we have
79 // just constructed. This is to allow unit tests to explicitly override
80 // the entry for localhost URLs.
Rob Wuf79b3ba2018-01-14 01:54:3181 if (net::IsLocalhost(url)) {
xunjieli413a68782015-06-16 17:15:4382 // TODO(joi): Once sliding window is separate from back-off throttling,
83 // we can simply return a dummy implementation of
Chris Mumfordc54b0c342018-07-23 21:29:4684 // ExtensionThrottleEntry here that never blocks anything.
xunjieli413a68782015-06-16 17:15:4385 entry->DisableBackoffThrottling();
86 }
87 }
88
Chris Mumfordc54b0c342018-07-23 21:29:4689 return entry.get();
xunjieli413a68782015-06-16 17:15:4390}
91
Chris Mumford3f0eda92018-07-23 14:51:1792bool ExtensionThrottleManager::ShouldRejectRequest(const GURL& request_url,
93 int request_load_flags) {
94 base::AutoLock auto_lock(lock_);
95 return RegisterRequestUrl(request_url)
96 ->ShouldRejectRequest(request_load_flags);
97}
98
99bool ExtensionThrottleManager::ShouldRejectRedirect(
100 const GURL& request_url,
101 int request_load_flags,
102 const net::RedirectInfo& redirect_info) {
103 {
Chris Mumford475eede2018-07-25 20:55:03104 // An entry GC when requests are outstanding can purge entries so check
105 // before use.
Chris Mumford3f0eda92018-07-23 14:51:17106 base::AutoLock auto_lock(lock_);
Chris Mumford475eede2018-07-25 20:55:03107 auto it = url_entries_.find(GetIdFromUrl(request_url));
108 if (it != url_entries_.end())
109 it->second->UpdateWithResponse(redirect_info.status_code);
Chris Mumford3f0eda92018-07-23 14:51:17110 }
111 return ShouldRejectRequest(redirect_info.new_url, request_load_flags);
112}
113
114void ExtensionThrottleManager::WillProcessResponse(
115 const GURL& response_url,
116 const network::ResourceResponseHead& response_head) {
117 if (response_head.network_accessed) {
Chris Mumford475eede2018-07-25 20:55:03118 // An entry GC when requests are outstanding can purge entries so check
119 // before use.
Chris Mumford3f0eda92018-07-23 14:51:17120 base::AutoLock auto_lock(lock_);
Chris Mumford475eede2018-07-25 20:55:03121 auto it = url_entries_.find(GetIdFromUrl(response_url));
122 if (it != url_entries_.end())
123 it->second->UpdateWithResponse(response_head.headers->response_code());
Chris Mumford3f0eda92018-07-23 14:51:17124 }
125}
126
xunjielie484e2d62015-06-19 14:31:21127void ExtensionThrottleManager::SetBackoffPolicyForTests(
dchengf5d241082016-04-21 03:43:11128 std::unique_ptr<net::BackoffEntry::Policy> policy) {
Chris Mumford3f0eda92018-07-23 14:51:17129 base::AutoLock auto_lock(lock_);
dchenge59eca1602015-12-18 17:48:00130 backoff_policy_for_tests_ = std::move(policy);
xunjielie484e2d62015-06-19 14:31:21131}
132
xunjieli413a68782015-06-16 17:15:43133void ExtensionThrottleManager::OverrideEntryForTests(
134 const GURL& url,
Chris Mumfordc54b0c342018-07-23 21:29:46135 std::unique_ptr<ExtensionThrottleEntry> entry) {
Chris Mumford3f0eda92018-07-23 14:51:17136 base::AutoLock auto_lock(lock_);
xunjieli413a68782015-06-16 17:15:43137 // Normalize the url.
138 std::string url_id = GetIdFromUrl(url);
139
140 // Periodically garbage collect old entries.
141 GarbageCollectEntriesIfNecessary();
142
Chris Mumfordc54b0c342018-07-23 21:29:46143 url_entries_[url_id] = std::move(entry);
xunjieli413a68782015-06-16 17:15:43144}
145
146void ExtensionThrottleManager::EraseEntryForTests(const GURL& url) {
Chris Mumford3f0eda92018-07-23 14:51:17147 base::AutoLock auto_lock(lock_);
xunjieli413a68782015-06-16 17:15:43148 // Normalize the url.
149 std::string url_id = GetIdFromUrl(url);
150 url_entries_.erase(url_id);
151}
152
153void ExtensionThrottleManager::SetIgnoreUserGestureLoadFlagForTests(
154 bool ignore_user_gesture_load_flag_for_tests) {
Chris Mumford3f0eda92018-07-23 14:51:17155 base::AutoLock auto_lock(lock_);
xunjieli413a68782015-06-16 17:15:43156 ignore_user_gesture_load_flag_for_tests_ = true;
157}
158
Chris Mumford3f0eda92018-07-23 14:51:17159void ExtensionThrottleManager::SetOnline(bool is_online) {
Devlin Cronin5674beb2017-11-23 02:54:19160 // When we switch from online to offline or change IP addresses, we
161 // clear all back-off history. This is a precaution in case the change in
162 // online state now lets us communicate without error with servers that
163 // we were previously getting 500 or 503 responses from (perhaps the
164 // responses are from a badly-written proxy that should have returned a
165 // 502 or 504 because it's upstream connection was down or it had no route
166 // to the server).
167 // Remove all entries. Any entries that in-flight requests have a reference
168 // to will live until those requests end, and these entries may be
169 // inconsistent with new entries for the same URLs, but since what we
170 // want is a clean slate for the new connection type, this is OK.
Chris Mumford3f0eda92018-07-23 14:51:17171 base::AutoLock auto_lock(lock_);
Devlin Cronin5674beb2017-11-23 02:54:19172 url_entries_.clear();
173 requests_since_last_gc_ = 0;
xunjieli413a68782015-06-16 17:15:43174}
175
176std::string ExtensionThrottleManager::GetIdFromUrl(const GURL& url) const {
177 if (!url.is_valid())
178 return url.possibly_invalid_spec();
179
180 GURL id = url.ReplaceComponents(url_id_replacements_);
brettw8e2106d2015-08-11 19:30:22181 return base::ToLowerASCII(id.spec());
xunjieli413a68782015-06-16 17:15:43182}
183
184void ExtensionThrottleManager::GarbageCollectEntriesIfNecessary() {
185 requests_since_last_gc_++;
186 if (requests_since_last_gc_ < kRequestsBetweenCollecting)
187 return;
188 requests_since_last_gc_ = 0;
189
190 GarbageCollectEntries();
191}
192
193void ExtensionThrottleManager::GarbageCollectEntries() {
Chris Mumfordc54b0c342018-07-23 21:29:46194 base::EraseIf(url_entries_, [](const auto& entry) {
195 return entry.second->IsEntryOutdated();
196 });
xunjieli413a68782015-06-16 17:15:43197
198 // In case something broke we want to make sure not to grow indefinitely.
199 while (url_entries_.size() > kMaximumNumberOfEntries) {
200 url_entries_.erase(url_entries_.begin());
201 }
202}
203
xunjieli413a68782015-06-16 17:15:43204} // namespace extensions