blob: 41472bd90ff9051ee64018b1d0041a9c115c3501 [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"
Lucas Furukawa Gadani011886592019-10-23 17:12:2416#include "services/network/public/mojom/url_response_head.mojom.h"
Chris Mumford3f0eda92018-07-23 14:51:1717#include "third_party/blink/public/platform/web_url.h"
18#include "third_party/blink/public/platform/web_url_request.h"
xunjieli413a68782015-06-16 17:15:4319
20namespace extensions {
21
22const unsigned int ExtensionThrottleManager::kMaximumNumberOfEntries = 1500;
23const unsigned int ExtensionThrottleManager::kRequestsBetweenCollecting = 200;
24
25ExtensionThrottleManager::ExtensionThrottleManager()
Matt Menke21850502019-10-09 22:34:2426 : requests_since_last_gc_(0) {
xunjieli413a68782015-06-16 17:15:4327 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
Minggang Wangf6840ecf2019-07-29 05:15:0239std::unique_ptr<blink::URLLoaderThrottle>
Chris Mumford3f0eda92018-07-23 14:51:1740ExtensionThrottleManager::MaybeCreateURLLoaderThrottle(
41 const blink::WebURLRequest& request) {
Maks Orlovichab27e242020-01-07 18:10:3942 // TODO(https://crbug.com/1039700): This relies on the extension scheme
43 // getting special handling via ShouldTreatURLSchemeAsFirstPartyWhenTopLevel,
44 // which has problems. Once that's removed this should probably look at top
45 // level directly instead.
46 if (request.SiteForCookies().scheme() != extensions::kExtensionScheme)
xunjieli413a68782015-06-16 17:15:4347 return nullptr;
Chris Mumford3f0eda92018-07-23 14:51:1748 return std::make_unique<ExtensionURLLoaderThrottle>(this);
xunjieli413a68782015-06-16 17:15:4349}
50
Chris Mumfordc54b0c342018-07-23 21:29:4651ExtensionThrottleEntry* ExtensionThrottleManager::RegisterRequestUrl(
52 const GURL& url) {
Chris Mumford3f0eda92018-07-23 14:51:1753 // Internal function, no locking.
xunjieli413a68782015-06-16 17:15:4354
55 // Normalize the url.
56 std::string url_id = GetIdFromUrl(url);
57
58 // Periodically garbage collect old entries.
59 GarbageCollectEntriesIfNecessary();
60
Chris Mumfordc54b0c342018-07-23 21:29:4661 // Find the entry in the map or create a new null entry.
62 std::unique_ptr<ExtensionThrottleEntry>& entry = url_entries_[url_id];
xunjieli413a68782015-06-16 17:15:4363
64 // If the entry exists but could be garbage collected at this point, we
65 // start with a fresh entry so that we possibly back off a bit less
66 // aggressively (i.e. this resets the error count when the entry's URL
67 // hasn't been requested in long enough).
Chris Mumfordc54b0c342018-07-23 21:29:4668 if (entry && entry->IsEntryOutdated())
69 entry.reset();
xunjieli413a68782015-06-16 17:15:4370
71 // Create the entry if needed.
Chris Mumfordc54b0c342018-07-23 21:29:4672 if (!entry) {
xunjielie484e2d62015-06-19 14:31:2173 if (backoff_policy_for_tests_) {
Matt Menke21850502019-10-09 22:34:2474 entry = std::make_unique<ExtensionThrottleEntry>(
75 url_id, backoff_policy_for_tests_.get());
xunjielie484e2d62015-06-19 14:31:2176 } else {
Matt Menke21850502019-10-09 22:34:2477 entry = std::make_unique<ExtensionThrottleEntry>(url_id);
xunjielie484e2d62015-06-19 14:31:2178 }
xunjieli413a68782015-06-16 17:15:4379
80 // We only disable back-off throttling on an entry that we have
81 // just constructed. This is to allow unit tests to explicitly override
82 // the entry for localhost URLs.
Rob Wuf79b3ba2018-01-14 01:54:3183 if (net::IsLocalhost(url)) {
xunjieli413a68782015-06-16 17:15:4384 // TODO(joi): Once sliding window is separate from back-off throttling,
85 // we can simply return a dummy implementation of
Chris Mumfordc54b0c342018-07-23 21:29:4686 // ExtensionThrottleEntry here that never blocks anything.
xunjieli413a68782015-06-16 17:15:4387 entry->DisableBackoffThrottling();
88 }
89 }
90
Chris Mumfordc54b0c342018-07-23 21:29:4691 return entry.get();
xunjieli413a68782015-06-16 17:15:4392}
93
Matt Menke21850502019-10-09 22:34:2494bool ExtensionThrottleManager::ShouldRejectRequest(const GURL& request_url) {
Chris Mumford3f0eda92018-07-23 14:51:1795 base::AutoLock auto_lock(lock_);
Matt Menke21850502019-10-09 22:34:2496 return RegisterRequestUrl(request_url)->ShouldRejectRequest();
Chris Mumford3f0eda92018-07-23 14:51:1797}
98
99bool ExtensionThrottleManager::ShouldRejectRedirect(
100 const GURL& request_url,
Chris Mumford3f0eda92018-07-23 14:51:17101 const net::RedirectInfo& redirect_info) {
102 {
Chris Mumford475eede2018-07-25 20:55:03103 // An entry GC when requests are outstanding can purge entries so check
104 // before use.
Chris Mumford3f0eda92018-07-23 14:51:17105 base::AutoLock auto_lock(lock_);
Chris Mumford475eede2018-07-25 20:55:03106 auto it = url_entries_.find(GetIdFromUrl(request_url));
107 if (it != url_entries_.end())
108 it->second->UpdateWithResponse(redirect_info.status_code);
Chris Mumford3f0eda92018-07-23 14:51:17109 }
Matt Menke21850502019-10-09 22:34:24110 return ShouldRejectRequest(redirect_info.new_url);
Chris Mumford3f0eda92018-07-23 14:51:17111}
112
113void ExtensionThrottleManager::WillProcessResponse(
114 const GURL& response_url,
Lucas Furukawa Gadani011886592019-10-23 17:12:24115 const network::mojom::URLResponseHead& response_head) {
Chris Mumford3f0eda92018-07-23 14:51:17116 if (response_head.network_accessed) {
Chris Mumford475eede2018-07-25 20:55:03117 // An entry GC when requests are outstanding can purge entries so check
118 // before use.
Chris Mumford3f0eda92018-07-23 14:51:17119 base::AutoLock auto_lock(lock_);
Chris Mumford475eede2018-07-25 20:55:03120 auto it = url_entries_.find(GetIdFromUrl(response_url));
121 if (it != url_entries_.end())
122 it->second->UpdateWithResponse(response_head.headers->response_code());
Chris Mumford3f0eda92018-07-23 14:51:17123 }
124}
125
xunjielie484e2d62015-06-19 14:31:21126void ExtensionThrottleManager::SetBackoffPolicyForTests(
dchengf5d241082016-04-21 03:43:11127 std::unique_ptr<net::BackoffEntry::Policy> policy) {
Chris Mumford3f0eda92018-07-23 14:51:17128 base::AutoLock auto_lock(lock_);
dchenge59eca1602015-12-18 17:48:00129 backoff_policy_for_tests_ = std::move(policy);
xunjielie484e2d62015-06-19 14:31:21130}
131
xunjieli413a68782015-06-16 17:15:43132void ExtensionThrottleManager::OverrideEntryForTests(
133 const GURL& url,
Chris Mumfordc54b0c342018-07-23 21:29:46134 std::unique_ptr<ExtensionThrottleEntry> entry) {
Chris Mumford3f0eda92018-07-23 14:51:17135 base::AutoLock auto_lock(lock_);
xunjieli413a68782015-06-16 17:15:43136 // Normalize the url.
137 std::string url_id = GetIdFromUrl(url);
138
139 // Periodically garbage collect old entries.
140 GarbageCollectEntriesIfNecessary();
141
Chris Mumfordc54b0c342018-07-23 21:29:46142 url_entries_[url_id] = std::move(entry);
xunjieli413a68782015-06-16 17:15:43143}
144
145void ExtensionThrottleManager::EraseEntryForTests(const GURL& url) {
Chris Mumford3f0eda92018-07-23 14:51:17146 base::AutoLock auto_lock(lock_);
xunjieli413a68782015-06-16 17:15:43147 // Normalize the url.
148 std::string url_id = GetIdFromUrl(url);
149 url_entries_.erase(url_id);
150}
151
Chris Mumford3f0eda92018-07-23 14:51:17152void ExtensionThrottleManager::SetOnline(bool is_online) {
Devlin Cronin5674beb2017-11-23 02:54:19153 // When we switch from online to offline or change IP addresses, we
154 // clear all back-off history. This is a precaution in case the change in
155 // online state now lets us communicate without error with servers that
156 // we were previously getting 500 or 503 responses from (perhaps the
157 // responses are from a badly-written proxy that should have returned a
158 // 502 or 504 because it's upstream connection was down or it had no route
159 // to the server).
160 // Remove all entries. Any entries that in-flight requests have a reference
161 // to will live until those requests end, and these entries may be
162 // inconsistent with new entries for the same URLs, but since what we
163 // want is a clean slate for the new connection type, this is OK.
Chris Mumford3f0eda92018-07-23 14:51:17164 base::AutoLock auto_lock(lock_);
Devlin Cronin5674beb2017-11-23 02:54:19165 url_entries_.clear();
166 requests_since_last_gc_ = 0;
xunjieli413a68782015-06-16 17:15:43167}
168
169std::string ExtensionThrottleManager::GetIdFromUrl(const GURL& url) const {
170 if (!url.is_valid())
171 return url.possibly_invalid_spec();
172
173 GURL id = url.ReplaceComponents(url_id_replacements_);
brettw8e2106d2015-08-11 19:30:22174 return base::ToLowerASCII(id.spec());
xunjieli413a68782015-06-16 17:15:43175}
176
177void ExtensionThrottleManager::GarbageCollectEntriesIfNecessary() {
178 requests_since_last_gc_++;
179 if (requests_since_last_gc_ < kRequestsBetweenCollecting)
180 return;
181 requests_since_last_gc_ = 0;
182
183 GarbageCollectEntries();
184}
185
186void ExtensionThrottleManager::GarbageCollectEntries() {
Chris Mumfordc54b0c342018-07-23 21:29:46187 base::EraseIf(url_entries_, [](const auto& entry) {
188 return entry.second->IsEntryOutdated();
189 });
xunjieli413a68782015-06-16 17:15:43190
191 // In case something broke we want to make sure not to grow indefinitely.
192 while (url_entries_.size() > kMaximumNumberOfEntries) {
193 url_entries_.erase(url_entries_.begin());
194 }
195}
196
xunjieli413a68782015-06-16 17:15:43197} // namespace extensions