blob: ca5b7cc4315a2a6afda06e1a0fdcbe9ef888e51d [file] [log] [blame]
[email protected]716c0162013-12-13 20:36:531// Copyright 2013 The Chromium Authors. All rights reserved.
[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
[email protected]ffbb60a2013-01-23 08:24:527#include <algorithm>
8#include <cctype>
Gyuyoung Kim8b084c02018-01-23 13:34:379#include <memory>
dcheng51ace48a2015-12-26 22:45:1710#include <utility>
[email protected]ffbb60a2013-01-23 08:24:5211
Hans Wennborgdf87046c2020-04-28 11:06:2412#include "base/check.h"
[email protected]dc1e471422012-04-18 19:54:3113#include "base/lazy_instance.h"
[email protected]f4390962013-06-11 07:29:2214#include "base/strings/stringprintf.h"
[email protected]dc1e471422012-04-18 19:54:3115#include "base/values.h"
[email protected]716c0162013-12-13 20:36:5316#include "components/url_matcher/url_matcher_constants.h"
Yann Dagoe65b7ee2022-01-04 19:01:3517#include "components/url_matcher/url_util.h"
battre0739c642015-12-21 17:45:2718#include "third_party/re2/src/re2/re2.h"
[email protected]dc1e471422012-04-18 19:54:3119
[email protected]716c0162013-12-13 20:36:5320namespace url_matcher {
21
[email protected]716c0162013-12-13 20:36:5322namespace keys = url_matcher_constants;
[email protected]dc1e471422012-04-18 19:54:3123
24namespace {
[email protected]716c0162013-12-13 20:36:5325
[email protected]dc1e471422012-04-18 19:54:3126// Error messages:
27const char kInvalidPortRanges[] = "Invalid port ranges in UrlFilter.";
28const char kVectorOfStringsExpected[] =
[email protected]716c0162013-12-13 20:36:5329 "UrlFilter attribute '%s' expected a vector of strings as parameter.";
[email protected]dc1e471422012-04-18 19:54:3130const char kUnknownURLFilterAttribute[] =
[email protected]716c0162013-12-13 20:36:5331 "Unknown attribute '%s' in UrlFilter.";
[email protected]dc1e471422012-04-18 19:54:3132const char kAttributeExpectedString[] =
[email protected]716c0162013-12-13 20:36:5333 "UrlFilter attribute '%s' expected a string value.";
[email protected]7a80ce82012-10-15 20:37:2134const char kUnparseableRegexString[] =
[email protected]716c0162013-12-13 20:36:5335 "Could not parse regular expression '%s': %s";
36const char kLowerCaseExpected[] = "%s values need to be in lower case.";
[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,
[email protected]dc1e471422012-04-18 19:54:31112 URLMatcherConditionSet::ID id,
113 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;
[email protected]dc1e471422012-04-18 19:54:31116 URLMatcherConditionSet::Conditions url_matcher_conditions;
117
Dan Sandersab2a47162022-04-27 20:12:00118 for (const auto iter : url_filter_dict) {
119 const std::string& condition_attribute_name = iter.first;
120 const base::Value& condition_attribute_value = iter.second;
[email protected]dc1e471422012-04-18 19:54:31121 if (IsURLMatcherConditionAttribute(condition_attribute_name)) {
122 // Handle {host, path, ...}{Prefix, Suffix, Contains, Equals}.
123 URLMatcherCondition url_matcher_condition =
124 CreateURLMatcherCondition(
125 url_matcher_condition_factory,
126 condition_attribute_name,
127 &condition_attribute_value,
128 error);
129 if (!error->empty())
Ivan Kotenkov75b1c3a2017-10-24 14:47:24130 return scoped_refptr<URLMatcherConditionSet>(nullptr);
[email protected]dc1e471422012-04-18 19:54:31131 url_matcher_conditions.insert(url_matcher_condition);
132 } else if (condition_attribute_name == keys::kSchemesKey) {
133 // Handle scheme.
134 url_matcher_schema_filter = CreateURLMatcherScheme(
135 &condition_attribute_value, error);
136 if (!error->empty())
Ivan Kotenkov75b1c3a2017-10-24 14:47:24137 return scoped_refptr<URLMatcherConditionSet>(nullptr);
[email protected]dc1e471422012-04-18 19:54:31138 } else if (condition_attribute_name == keys::kPortsKey) {
139 // Handle ports.
140 url_matcher_port_filter = CreateURLMatcherPorts(
141 &condition_attribute_value, error);
142 if (!error->empty())
Ivan Kotenkov75b1c3a2017-10-24 14:47:24143 return scoped_refptr<URLMatcherConditionSet>(nullptr);
[email protected]dc1e471422012-04-18 19:54:31144 } else {
145 // Handle unknown attributes.
[email protected]716c0162013-12-13 20:36:53146 *error = base::StringPrintf(kUnknownURLFilterAttribute,
147 condition_attribute_name.c_str());
Ivan Kotenkov75b1c3a2017-10-24 14:47:24148 return scoped_refptr<URLMatcherConditionSet>(nullptr);
[email protected]dc1e471422012-04-18 19:54:31149 }
150 }
151
152 // As the URL is the preliminary matching criterion that triggers the tests
153 // for the remaining condition attributes, we insert an empty URL match if
154 // no other url match conditions were specified. Such an empty URL is always
155 // matched.
156 if (url_matcher_conditions.empty()) {
157 url_matcher_conditions.insert(
[email protected]007b3f82013-04-09 08:46:45158 url_matcher_condition_factory->CreateHostPrefixCondition(
159 std::string()));
[email protected]dc1e471422012-04-18 19:54:31160 }
161
162 scoped_refptr<URLMatcherConditionSet> url_matcher_condition_set(
163 new URLMatcherConditionSet(id, url_matcher_conditions,
dcheng51ace48a2015-12-26 22:45:17164 std::move(url_matcher_schema_filter),
165 std::move(url_matcher_port_filter)));
[email protected]dc1e471422012-04-18 19:54:31166 return url_matcher_condition_set;
167}
168
169// static
170bool URLMatcherFactory::IsURLMatcherConditionAttribute(
171 const std::string& condition_attribute_name) {
172 return g_url_matcher_condition_factory_methods.Get().Contains(
173 condition_attribute_name);
174}
175
[email protected]ffbb60a2013-01-23 08:24:52176namespace {
177
178// Returns true if some alphabetic characters in this string are upper case.
179bool ContainsUpperCase(const std::string& str) {
180 return std::find_if(str.begin(), str.end(), ::isupper) != str.end();
181}
182
183} // namespace
184
[email protected]dc1e471422012-04-18 19:54:31185// static
186URLMatcherCondition URLMatcherFactory::CreateURLMatcherCondition(
187 URLMatcherConditionFactory* url_matcher_condition_factory,
188 const std::string& condition_attribute_name,
189 const base::Value* value,
190 std::string* error) {
tom4970e292021-07-16 14:27:52191 if (!value->is_string()) {
[email protected]716c0162013-12-13 20:36:53192 *error = base::StringPrintf(kAttributeExpectedString,
193 condition_attribute_name.c_str());
[email protected]dc1e471422012-04-18 19:54:31194 return URLMatcherCondition();
195 }
tom4970e292021-07-16 14:27:52196 const std::string& str_value = value->GetString();
[email protected]ffbb60a2013-01-23 08:24:52197 if (condition_attribute_name == keys::kHostContainsKey ||
198 condition_attribute_name == keys::kHostPrefixKey ||
199 condition_attribute_name == keys::kHostSuffixKey ||
200 condition_attribute_name == keys::kHostEqualsKey) {
201 if (ContainsUpperCase(str_value)) {
[email protected]716c0162013-12-13 20:36:53202 *error = base::StringPrintf(kLowerCaseExpected, "Host");
[email protected]ffbb60a2013-01-23 08:24:52203 return URLMatcherCondition();
204 }
205 }
206
[email protected]7a80ce82012-10-15 20:37:21207 // Test regular expressions for validity.
[email protected]1a3a0212013-04-29 13:14:27208 if (condition_attribute_name == keys::kURLMatchesKey ||
209 condition_attribute_name == keys::kOriginAndPathMatchesKey) {
[email protected]7a80ce82012-10-15 20:37:21210 re2::RE2 regex(str_value);
211 if (!regex.ok()) {