blob: 5a385addde925a51abb79a7ced5a48c35cda918e [file] [log] [blame]
Avi Drissman8ba1bad2022-09-13 19:22:361// Copyright 2013 The Chromium Authors
[email protected]dc1e471422012-04-18 19:54:312// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]716c0162013-12-13 20:36:535#include "components/url_matcher/url_matcher_factory.h"
[email protected]dc1e471422012-04-18 19:54:316
Peter Kastingccea09832025-01-27 18:38:227#include <algorithm>
Gyuyoung Kim8b084c02018-01-23 13:34:378#include <memory>
dcheng51ace48a2015-12-26 22:45:179#include <utility>
[email protected]ffbb60a2013-01-23 08:24:5210
Hans Wennborgdf87046c2020-04-28 11:06:2411#include "base/check.h"
[email protected]dc1e471422012-04-18 19:54:3112#include "base/lazy_instance.h"
[email protected]f4390962013-06-11 07:29:2213#include "base/strings/stringprintf.h"
[email protected]dc1e471422012-04-18 19:54:3114#include "base/values.h"
[email protected]716c0162013-12-13 20:36:5315#include "components/url_matcher/url_matcher_constants.h"
Yann Dagoe65b7ee2022-01-04 19:01:3516#include "components/url_matcher/url_util.h"
battre0739c642015-12-21 17:45:2717#include "third_party/re2/src/re2/re2.h"
[email protected]dc1e471422012-04-18 19:54:3118
[email protected]716c0162013-12-13 20:36:5319namespace url_matcher {
20
[email protected]716c0162013-12-13 20:36:5321namespace keys = url_matcher_constants;
[email protected]dc1e471422012-04-18 19:54:3122
23namespace {
[email protected]716c0162013-12-13 20:36:5324
[email protected]dc1e471422012-04-18 19:54:3125// Error messages:
26const char kInvalidPortRanges[] = "Invalid port ranges in UrlFilter.";
27const char kVectorOfStringsExpected[] =
[email protected]716c0162013-12-13 20:36:5328 "UrlFilter attribute '%s' expected a vector of strings as parameter.";
[email protected]dc1e471422012-04-18 19:54:3129const char kUnknownURLFilterAttribute[] =
[email protected]716c0162013-12-13 20:36:5330 "Unknown attribute '%s' in UrlFilter.";
[email protected]dc1e471422012-04-18 19:54:3131const char kAttributeExpectedString[] =
[email protected]716c0162013-12-13 20:36:5332 "UrlFilter attribute '%s' expected a string value.";
[email protected]7a80ce82012-10-15 20:37:2133const char kUnparseableRegexString[] =
[email protected]716c0162013-12-13 20:36:5334 "Could not parse regular expression '%s': %s";
35const char kLowerCaseExpected[] = "%s values need to be in lower case.";
Chen Mor-Yosef281dee842024-02-06 18:37:4036const char kInvalidCidrBlocks[] = "Invalid CIDR blocks in UrlFilter.";
[email protected]dc1e471422012-04-18 19:54:3137
[email protected]716c0162013-12-13 20:36:5338// Registry for all factory methods of URLMatcherConditionFactory
[email protected]dc1e471422012-04-18 19:54:3139// that allows translating string literals from the extension API into
40// the corresponding factory method to be called.
41class URLMatcherConditionFactoryMethods {
42 public:
43 URLMatcherConditionFactoryMethods() {
[email protected]716c0162013-12-13 20:36:5344 typedef URLMatcherConditionFactory F;
[email protected]dc1e471422012-04-18 19:54:3145 factory_methods_[keys::kHostContainsKey] = &F::CreateHostContainsCondition;
46 factory_methods_[keys::kHostEqualsKey] = &F::CreateHostEqualsCondition;
47 factory_methods_[keys::kHostPrefixKey] = &F::CreateHostPrefixCondition;
48 factory_methods_[keys::kHostSuffixKey] = &F::CreateHostSuffixCondition;
[email protected]2280dc82013-04-11 20:04:0149 factory_methods_[keys::kOriginAndPathMatchesKey] =
50 &F::CreateOriginAndPathMatchesCondition;
[email protected]dc1e471422012-04-18 19:54:3151 factory_methods_[keys::kPathContainsKey] = &F::CreatePathContainsCondition;
52 factory_methods_[keys::kPathEqualsKey] = &F::CreatePathEqualsCondition;
53 factory_methods_[keys::kPathPrefixKey] = &F::CreatePathPrefixCondition;
54 factory_methods_[keys::kPathSuffixKey] = &F::CreatePathSuffixCondition;
55 factory_methods_[keys::kQueryContainsKey] =
56 &F::CreateQueryContainsCondition;
57 factory_methods_[keys::kQueryEqualsKey] = &F::CreateQueryEqualsCondition;
58 factory_methods_[keys::kQueryPrefixKey] = &F::CreateQueryPrefixCondition;
59 factory_methods_[keys::kQuerySuffixKey] = &F::CreateQuerySuffixCondition;
60 factory_methods_[keys::kURLContainsKey] = &F::CreateURLContainsCondition;
61 factory_methods_[keys::kURLEqualsKey] = &F::CreateURLEqualsCondition;
62 factory_methods_[keys::kURLPrefixKey] = &F::CreateURLPrefixCondition;
63 factory_methods_[keys::kURLSuffixKey] = &F::CreateURLSuffixCondition;
[email protected]5bcf3b72012-09-14 00:20:2864 factory_methods_[keys::kURLMatchesKey] = &F::CreateURLMatchesCondition;
[email protected]dc1e471422012-04-18 19:54:3165 }
66
Peter Boström9f667c382021-10-01 20:09:3167 URLMatcherConditionFactoryMethods(const URLMatcherConditionFactoryMethods&) =
68 delete;
69 URLMatcherConditionFactoryMethods& operator=(
70 const URLMatcherConditionFactoryMethods&) = delete;
71
[email protected]dc1e471422012-04-18 19:54:3172 // Returns whether a factory method for the specified |pattern_type| (e.g.
73 // "host_suffix") is known.
74 bool Contains(const std::string& pattern_type) const {
75 return factory_methods_.find(pattern_type) != factory_methods_.end();
76 }
77
78 // Creates a URLMatcherCondition instance from |url_matcher_condition_factory|
79 // of the given |pattern_type| (e.g. "host_suffix") for the given
80 // |pattern_value| (e.g. "example.com").
81 // The |pattern_type| needs to be known to this class (see Contains()) or
82 // a CHECK is triggered.
[email protected]716c0162013-12-13 20:36:5383 URLMatcherCondition Call(
84 URLMatcherConditionFactory* url_matcher_condition_factory,
[email protected]dc1e471422012-04-18 19:54:3185 const std::string& pattern_type,
86 const std::string& pattern_value) const {
jdoerrie3feb1852018-10-05 12:16:4487 auto i = factory_methods_.find(pattern_type);
[email protected]dc1e471422012-04-18 19:54:3188 CHECK(i != factory_methods_.end());
89 const FactoryMethod& method = i->second;
90 return (url_matcher_condition_factory->*method)(pattern_value);
91 }
92
93 private:
[email protected]716c0162013-12-13 20:36:5394 typedef URLMatcherCondition
95 (URLMatcherConditionFactory::* FactoryMethod)
[email protected]dc1e471422012-04-18 19:54:3196 (const std::string& prefix);
97 typedef std::map<std::string, FactoryMethod> FactoryMethods;
98
99 FactoryMethods factory_methods_;
[email protected]dc1e471422012-04-18 19:54:31100};
101
scottmg5e65e3a2017-03-08 08:48:46102static base::LazyInstance<URLMatcherConditionFactoryMethods>::DestructorAtExit
[email protected]dc1e471422012-04-18 19:54:31103 g_url_matcher_condition_factory_methods = LAZY_INSTANCE_INITIALIZER;
104
105} // namespace
106
[email protected]dc1e471422012-04-18 19:54:31107// static
108scoped_refptr<URLMatcherConditionSet>
109URLMatcherFactory::CreateFromURLFilterDictionary(
110 URLMatcherConditionFactory* url_matcher_condition_factory,
Dan Sandersab2a47162022-04-27 20:12:00111 const base::Value::Dict& url_filter_dict,
Peter Kasting78549f32022-05-31 18:20:20112 base::MatcherStringPattern::ID id,
[email protected]dc1e471422012-04-18 19:54:31113 std::string* error) {
dcheng3f767dc32016-04-25 22:54:22114 std::unique_ptr<URLMatcherSchemeFilter> url_matcher_schema_filter;
115 std::unique_ptr<URLMatcherPortFilter> url_matcher_port_filter;
Chen Mor-Yosef281dee842024-02-06 18:37:40116 std::unique_ptr<URLMatcherCidrBlockFilter> url_matcher_cidr_block_filter;
[email protected]dc1e471422012-04-18 19:54:31117 URLMatcherConditionSet::Conditions url_matcher_conditions;
118
Dan Sandersab2a47162022-04-27 20:12:00119 for (const auto iter : url_filter_dict) {
120 const std::string& condition_attribute_name = iter.first;
121 const base::Value& condition_attribute_value = iter.second;
[email protected]dc1e471422012-04-18 19:54:31122 if (IsURLMatcherConditionAttribute(condition_attribute_name)) {
123 // Handle {host, path, ...}{Prefix, Suffix, Contains, Equals}.
124 URLMatcherCondition url_matcher_condition =
125 CreateURLMatcherCondition(
126 url_matcher_condition_factory,
127 condition_attribute_name,
128 &condition_attribute_value,
129 error);
130 if (!error->empty())
Ivan Kotenkov75b1c3a2017-10-24 14:47:24131 return scoped_refptr<URLMatcherConditionSet>(nullptr);
[email protected]dc1e471422012-04-18 19:54:31132 url_matcher_conditions.insert(url_matcher_condition);
133 } else if (condition_attribute_name == keys::kSchemesKey) {
134 // Handle scheme.
135 url_matcher_schema_filter = CreateURLMatcherScheme(
136 &condition_attribute_value, error);
137 if (!error->empty())
Ivan Kotenkov75b1c3a2017-10-24 14:47:24138 return scoped_refptr<URLMatcherConditionSet>(nullptr);
[email protected]dc1e471422012-04-18 19:54:31139 } else if (condition_attribute_name == keys::kPortsKey) {
140 // Handle ports.
141 url_matcher_port_filter = CreateURLMatcherPorts(
142 &condition_attribute_value, error);
143 if (!error->empty())
Ivan Kotenkov75b1c3a2017-10-24 14:47:24144 return scoped_refptr<URLMatcherConditionSet>(nullptr);
Chen Mor-Yosef281dee842024-02-06 18:37:40145 } else if (condition_attribute_name == keys::kCidrBlocksKey) {
146 // Handle CIDR blocks.
147 url_matcher_cidr_block_filter =
148 CreateURLMatcherCidrBlocks(&condition_attribute_value, error);
149 if (!error->empty()) {
150 return scoped_refptr<URLMatcherConditionSet>(nullptr);
151 }
[email protected]dc1e471422012-04-18 19:54:31152 } else {
153 // Handle unknown attributes.
[email protected]716c0162013-12-13 20:36:53154 *error = base::StringPrintf(kUnknownURLFilterAttribute,
155 condition_attribute_name.c_str());
Ivan Kotenkov75b1c3a2017-10-24 14:47:24156 return scoped_refptr<URLMatcherConditionSet>(nullptr);
[email protected]dc1e471422012-04-18 19:54:31157 }
158 }
159
160 // As the URL is the preliminary matching criterion that triggers the tests
161 // for the remaining condition attributes, we insert an empty URL match if
162 // no other url match conditions were specified. Such an empty URL is always
163 // matched.
164 if (url_matcher_conditions.empty()) {
165 url_matcher_conditions.insert(
[email protected]007b3f82013-04-09 08:46:45166 url_matcher_condition_factory->CreateHostPrefixCondition(
167 std::string()));
[email protected]dc1e471422012-04-18 19:54:31168 }
169
170 scoped_refptr<URLMatcherConditionSet> url_matcher_condition_set(
171 new URLMatcherConditionSet(id, url_matcher_conditions,
dcheng51ace48a2015-12-26 22:45:17172 std::move(url_matcher_schema_filter),
Chen Mor-Yosef281dee842024-02-06 18:37:40173 std::move(url_matcher_port_filter),
174 std::move(url_matcher_cidr_block_filter)));
[email protected]dc1e471422012-04-18 19:54:31175 return url_matcher_condition_set;
176}
177
178// static
179bool URLMatcherFactory::IsURLMatcherConditionAttribute(
180 const std::string& condition_attribute_name) {
181 return g_url_matcher_condition_factory_methods.Get().Contains(
182 condition_attribute_name);
183}
184
[email protected]ffbb60a2013-01-23 08:24:52185namespace {
186
187// Returns true if some alphabetic characters in this string are upper case.
188bool ContainsUpperCase(const std::string& str) {
Peter Kastingccea09832025-01-27 18:38:22189 return std::ranges::any_of(str, ::isupper);
[email protected]ffbb60a2013-01-23 08:24:52190}
191
192} // namespace
193
[email protected]dc1e471422012-04-18 19:54:31194// static
195URLMatcherCondition URLMatcherFactory::CreateURLMatcherCondition(
196 URLMatcherConditionFactory* url_matcher_condition_factory,
197 const std::string& condition_attribute_name,
198 const base::Value* value,
199 std::string* error) {
tom4970e292021-07-16 14:27:52200 if (!value->is_string()) {
[email protected]716c0162013-12-13 20:36:53201 *error = base::StringPrintf(kAttributeExpectedString,
202 condition_attribute_name.c_str());
[email protected]dc1e471422012-04-18 19:54:31203 return URLMatcherCondition();
204 }
tom4970e292021-07-16 14:27:52205 const std::string& str_value = value->GetString();
[email protected]ffbb60a2013-01-23 08:24:52206 if (condition_attribute_name == keys::kHostContainsKey ||
207 condition_attribute_name == keys::kHostPrefixKey ||
208 condition_attribute_name == keys::kHostSuffixKey ||
209 condition_attribute_name == keys::kHostEqualsKey) {
210 if (ContainsUpperCase(str_value)) {
[email protected]716c0162013-12-13 20:36:53211 *error = base::StringPrintf(kLowerCaseExpected, "Host");
[email protected]ffbb60a2013-01-23 08:24:52212 return URLMatcherCondition();
213 }
214 }
215
[email protected]7a80ce82012-10-15 20:37:21216 // Test regular expressions for validity.
[email protected]1a3a0212013-04-29 13:14:27217 if (condition_attribute_name == keys::kURLMatchesKey ||
218 condition_attribute_name == keys::kOriginAndPathMatchesKey) {
[email protected]7a80ce82012-10-15 20:37:21219 re2::RE2 regex(str_value);
220 if (!regex.ok()) {
[email protected]716c0162013-12-13 20:36:53221 *error = base::StringPrintf(
222 kUnparseableRegexString, str_value.c_str(), regex.error().c_str());
[email protected]7a80ce82012-10-15 20:37:21223 return URLMatcherCondition();
224 }
225 }
[email protected]dc1e471422012-04-18 19:54:31226 return g_url_matcher_condition_factory_methods.Get().Call(
227 url_matcher_condition_factory, condition_attribute_name, str_value);
228}
229
230// static
dcheng3f767dc32016-04-25 22:54:22231std::unique_ptr<URLMatcherSchemeFilter>
232URLMatcherFactory::CreateURLMatcherScheme(const base::Value* value,
233 std::string* error) {
[email protected]dc1e471422012-04-18 19:54:31234 std::vector<std::string> schemas;
Yann Dagoe65b7ee2022-01-04 19:01:35235 if (!util::GetAsStringVector(value, &schemas)) {
[email protected]716c0162013-12-13 20:36:53236 *error = base::StringPrintf(kVectorOfStringsExpected, keys::kSchemesKey);
dcheng3f767dc32016-04-25 22:54:22237 return nullptr;
[email protected]dc1e471422012-04-18 19:54:31238 }
[email protected]ffbb60a2013-01-23 08:24:52239 for (std::vector<std::string>::const_iterator it = schemas.begin();
240 it != schemas.end(); ++it) {
241 if (ContainsUpperCase(*it)) {
[email protected]716c0162013-12-13 20:36:53242 *error = base::StringPrintf(kLowerCaseExpected, "Scheme");
dcheng3f767dc32016-04-25 22:54:22243 return nullptr;
[email protected]ffbb60a2013-01-23 08:24:52244 }
245 }
Gyuyoung Kim8b084c02018-01-23 13:34:37246 return std::make_unique<URLMatcherSchemeFilter>(schemas);
[email protected]dc1e471422012-04-18 19:54:31247}
248
249// static
dcheng3f767dc32016-04-25 22:54:22250std::unique_ptr<URLMatcherPortFilter> URLMatcherFactory::CreateURLMatcherPorts(
[email protected]dc1e471422012-04-18 19:54:31251 const base::Value* value,
252 std::string* error) {
253 std::vector<URLMatcherPortFilter::Range> ranges;
Alex Cooperf017a032021-07-14 07:58:16254 if (!value->is_list()) {
[email protected]dc1e471422012-04-18 19:54:31255 *error = kInvalidPortRanges;
dcheng3f767dc32016-04-25 22:54:22256 return nullptr;
[email protected]dc1e471422012-04-18 19:54:31257 }
David Bertoni0c667462022-09-21 08:00:34258 const base::Value::List& value_list = value->GetList();
[email protected]dc1e471422012-04-18 19:54:31259
Alex Cooperf017a032021-07-14 07:58:16260 for (const auto& entry : value_list) {
Minoru Chikamune2ab98e92021-04-17 02:21:18261 if (entry.is_int()) {
262 ranges.push_back(URLMatcherPortFilter::CreateRange(entry.GetInt()));
Alex Cooperf017a032021-07-14 07:58:16263 } else if (entry.is_list()) {
David Bertoni0c667462022-09-21 08:00:34264 const base::Value::List& entry_list = entry.GetList();
Alex Cooperf017a032021-07-14 07:58:16265 if (entry_list.size() != 2u || !entry_list[0].is_int() ||
266 !entry_list[1].is_int()) {
[email protected]dc1e471422012-04-18 19:54:31267 *error = kInvalidPortRanges;
dcheng3f767dc32016-04-25 22:54:22268 return nullptr;
[email protected]dc1e471422012-04-18 19:54:31269 }
Alex Cooperf017a032021-07-14 07:58:16270 int from = entry_list[0].GetInt();
271 int to = entry_list[1].GetInt();
[email protected]dc1e471422012-04-18 19:54:31272 ranges.push_back(URLMatcherPortFilter::CreateRange(from, to));
273 } else {
274 *error = kInvalidPortRanges;
dcheng3f767dc32016-04-25 22:54:22275 return nullptr;
[email protected]dc1e471422012-04-18 19:54:31276 }
277 }
278
Gyuyoung Kim8b084c02018-01-23 13:34:37279 return std::make_unique<URLMatcherPortFilter>(ranges);
[email protected]dc1e471422012-04-18 19:54:31280}
281
Chen Mor-Yosef281dee842024-02-06 18:37:40282// static
283std::unique_ptr<URLMatcherCidrBlockFilter>
284URLMatcherFactory::CreateURLMatcherCidrBlocks(const base::Value* value,
285 std::string* error) {
286 std::vector<URLMatcherCidrBlockFilter::CidrBlock> cidr_blocks;
287 if (!value->is_list()) {
288 *error = kInvalidCidrBlocks;
289 return nullptr;
290 }
291
292 cidr_blocks.reserve(value->GetList().size());
293 for (const auto& entry : value->GetList()) {
294 if (!entry.is_string()) {
295 *error = kInvalidCidrBlocks;
296 return nullptr;
297 }
298
299 base::expected<URLMatcherCidrBlockFilter::CidrBlock, std::string>
300 cidr_block =
301 URLMatcherCidrBlockFilter::CreateCidrBlock(entry.GetString());
302 if (!cidr_block.has_value()) {
303 *error = cidr_block.error();
304 return nullptr;
305 }
306
307 cidr_blocks.push_back(std::move(*cidr_block));
308 }
309
310 return std::make_unique<URLMatcherCidrBlockFilter>(std::move(cidr_blocks));
311}
312
[email protected]716c0162013-12-13 20:36:53313} // namespace url_matcher