forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathextension_throttle_manager.cc
204 lines (171 loc) · 7.05 KB
/
extension_throttle_manager.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "extensions/renderer/extension_throttle_manager.h"
#include <utility>
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "base/strings/string_util.h"
#include "extensions/common/constants.h"
#include "extensions/renderer/extension_url_loader_throttle.h"
#include "net/base/url_util.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/platform/web_url_request.h"
namespace extensions {
const unsigned int ExtensionThrottleManager::kMaximumNumberOfEntries = 1500;
const unsigned int ExtensionThrottleManager::kRequestsBetweenCollecting = 200;
ExtensionThrottleManager::ExtensionThrottleManager()
: requests_since_last_gc_(0),
ignore_user_gesture_load_flag_for_tests_(false) {
url_id_replacements_.ClearPassword();
url_id_replacements_.ClearUsername();
url_id_replacements_.ClearQuery();
url_id_replacements_.ClearRef();
}
ExtensionThrottleManager::~ExtensionThrottleManager() {
base::AutoLock auto_lock(lock_);
// Delete all entries.
url_entries_.clear();
}
std::unique_ptr<content::URLLoaderThrottle>
ExtensionThrottleManager::MaybeCreateURLLoaderThrottle(
const blink::WebURLRequest& request) {
if (!request.SiteForCookies().ProtocolIs(extensions::kExtensionScheme))
return nullptr;
return std::make_unique<ExtensionURLLoaderThrottle>(this);
}
ExtensionThrottleEntry* ExtensionThrottleManager::RegisterRequestUrl(
const GURL& url) {
// Internal function, no locking.
// Normalize the url.
std::string url_id = GetIdFromUrl(url);
// Periodically garbage collect old entries.
GarbageCollectEntriesIfNecessary();
// Find the entry in the map or create a new null entry.
std::unique_ptr<ExtensionThrottleEntry>& entry = url_entries_[url_id];
// If the entry exists but could be garbage collected at this point, we
// start with a fresh entry so that we possibly back off a bit less
// aggressively (i.e. this resets the error count when the entry's URL
// hasn't been requested in long enough).
if (entry && entry->IsEntryOutdated())
entry.reset();
// Create the entry if needed.
if (!entry) {
if (backoff_policy_for_tests_) {
entry.reset(
new ExtensionThrottleEntry(url_id, backoff_policy_for_tests_.get(),
ignore_user_gesture_load_flag_for_tests_));
} else {
entry.reset(new ExtensionThrottleEntry(
url_id, ignore_user_gesture_load_flag_for_tests_));
}
// We only disable back-off throttling on an entry that we have
// just constructed. This is to allow unit tests to explicitly override
// the entry for localhost URLs.
if (net::IsLocalhost(url)) {
// TODO(joi): Once sliding window is separate from back-off throttling,
// we can simply return a dummy implementation of
// ExtensionThrottleEntry here that never blocks anything.
entry->DisableBackoffThrottling();
}
}
return entry.get();
}
bool ExtensionThrottleManager::ShouldRejectRequest(const GURL& request_url,
int request_load_flags) {
base::AutoLock auto_lock(lock_);
return RegisterRequestUrl(request_url)
->ShouldRejectRequest(request_load_flags);
}
bool ExtensionThrottleManager::ShouldRejectRedirect(
const GURL& request_url,
int request_load_flags,
const net::RedirectInfo& redirect_info) {
{
// An entry GC when requests are outstanding can purge entries so check
// before use.
base::AutoLock auto_lock(lock_);
auto it = url_entries_.find(GetIdFromUrl(request_url));
if (it != url_entries_.end())
it->second->UpdateWithResponse(redirect_info.status_code);
}
return ShouldRejectRequest(redirect_info.new_url, request_load_flags);
}
void ExtensionThrottleManager::WillProcessResponse(
const GURL& response_url,
const network::ResourceResponseHead& response_head) {
if (response_head.network_accessed) {
// An entry GC when requests are outstanding can purge entries so check
// before use.
base::AutoLock auto_lock(lock_);
auto it = url_entries_.find(GetIdFromUrl(response_url));
if (it != url_entries_.end())
it->second->UpdateWithResponse(response_head.headers->response_code());
}
}
void ExtensionThrottleManager::SetBackoffPolicyForTests(
std::unique_ptr<net::BackoffEntry::Policy> policy) {
base::AutoLock auto_lock(lock_);
backoff_policy_for_tests_ = std::move(policy);
}
void ExtensionThrottleManager::OverrideEntryForTests(
const GURL& url,
std::unique_ptr<ExtensionThrottleEntry> entry) {
base::AutoLock auto_lock(lock_);
// Normalize the url.
std::string url_id = GetIdFromUrl(url);
// Periodically garbage collect old entries.
GarbageCollectEntriesIfNecessary();
url_entries_[url_id] = std::move(entry);
}
void ExtensionThrottleManager::EraseEntryForTests(const GURL& url) {
base::AutoLock auto_lock(lock_);
// Normalize the url.
std::string url_id = GetIdFromUrl(url);
url_entries_.erase(url_id);
}
void ExtensionThrottleManager::SetIgnoreUserGestureLoadFlagForTests(
bool ignore_user_gesture_load_flag_for_tests) {
base::AutoLock auto_lock(lock_);
ignore_user_gesture_load_flag_for_tests_ = true;
}
void ExtensionThrottleManager::SetOnline(bool is_online) {
// When we switch from online to offline or change IP addresses, we
// clear all back-off history. This is a precaution in case the change in
// online state now lets us communicate without error with servers that
// we were previously getting 500 or 503 responses from (perhaps the
// responses are from a badly-written proxy that should have returned a
// 502 or 504 because it's upstream connection was down or it had no route
// to the server).
// Remove all entries. Any entries that in-flight requests have a reference
// to will live until those requests end, and these entries may be
// inconsistent with new entries for the same URLs, but since what we
// want is a clean slate for the new connection type, this is OK.
base::AutoLock auto_lock(lock_);
url_entries_.clear();
requests_since_last_gc_ = 0;
}
std::string ExtensionThrottleManager::GetIdFromUrl(const GURL& url) const {
if (!url.is_valid())
return url.possibly_invalid_spec();
GURL id = url.ReplaceComponents(url_id_replacements_);
return base::ToLowerASCII(id.spec());
}
void ExtensionThrottleManager::GarbageCollectEntriesIfNecessary() {
requests_since_last_gc_++;
if (requests_since_last_gc_ < kRequestsBetweenCollecting)
return;
requests_since_last_gc_ = 0;
GarbageCollectEntries();
}
void ExtensionThrottleManager::GarbageCollectEntries() {
base::EraseIf(url_entries_, [](const auto& entry) {
return entry.second->IsEntryOutdated();
});
// In case something broke we want to make sure not to grow indefinitely.
while (url_entries_.size() > kMaximumNumberOfEntries) {
url_entries_.erase(url_entries_.begin());
}
}
} // namespace extensions