summaryrefslogtreecommitdiffstats
path: root/components/url_matcher/url_matcher_factory.cc
diff options
context:
space:
mode:
authorjoaodasilva@chromium.org <joaodasilva@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-13 20:36:53 +0000
committerjoaodasilva@chromium.org <joaodasilva@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-13 20:36:53 +0000
commit716c016d95025a8f4d42baab6639b9dc90498f2d (patch)
tree9efb703e070ecbfb1b73bfac9b350a3b81af14f6 /components/url_matcher/url_matcher_factory.cc
parent32c90a98f03fa68da4ba3d97a8e56ca70e92a07d (diff)
downloadchromium_src-716c016d95025a8f4d42baab6639b9dc90498f2d.zip
chromium_src-716c016d95025a8f4d42baab6639b9dc90498f2d.tar.gz
chromium_src-716c016d95025a8f4d42baab6639b9dc90498f2d.tar.bz2
Move extensions/common/matcher into components/url_matcher.
This allows using that code in builds that don't include extensions without having to introduce layering exceptions. This is meant for inclusion on the iOS build. BUG=271392 TBR=brettw@chromium.org Review URL: https://codereview.chromium.org/113903002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@240736 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'components/url_matcher/url_matcher_factory.cc')
-rw-r--r--components/url_matcher/url_matcher_factory.cc273
1 files changed, 273 insertions, 0 deletions
diff --git a/components/url_matcher/url_matcher_factory.cc b/components/url_matcher/url_matcher_factory.cc
new file mode 100644
index 0000000..ab1c365
--- /dev/null
+++ b/components/url_matcher/url_matcher_factory.cc
@@ -0,0 +1,273 @@
+// Copyright 2013 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 "components/url_matcher/url_matcher_factory.h"
+
+#include <algorithm>
+#include <cctype>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "base/values.h"
+#include "components/url_matcher/url_matcher_constants.h"
+#include "components/url_matcher/url_matcher_helpers.h"
+#include "third_party/re2/re2/re2.h"
+
+namespace url_matcher {
+
+namespace helpers = url_matcher_helpers;
+namespace keys = url_matcher_constants;
+
+namespace {
+
+// Error messages:
+const char kInvalidPortRanges[] = "Invalid port ranges in UrlFilter.";
+const char kVectorOfStringsExpected[] =
+ "UrlFilter attribute '%s' expected a vector of strings as parameter.";
+const char kUnknownURLFilterAttribute[] =
+ "Unknown attribute '%s' in UrlFilter.";
+const char kAttributeExpectedString[] =
+ "UrlFilter attribute '%s' expected a string value.";
+const char kUnparseableRegexString[] =
+ "Could not parse regular expression '%s': %s";
+const char kLowerCaseExpected[] = "%s values need to be in lower case.";
+
+// Registry for all factory methods of URLMatcherConditionFactory
+// that allows translating string literals from the extension API into
+// the corresponding factory method to be called.
+class URLMatcherConditionFactoryMethods {
+ public:
+ URLMatcherConditionFactoryMethods() {
+ typedef URLMatcherConditionFactory F;
+ factory_methods_[keys::kHostContainsKey] = &F::CreateHostContainsCondition;
+ factory_methods_[keys::kHostEqualsKey] = &F::CreateHostEqualsCondition;
+ factory_methods_[keys::kHostPrefixKey] = &F::CreateHostPrefixCondition;
+ factory_methods_[keys::kHostSuffixKey] = &F::CreateHostSuffixCondition;
+ factory_methods_[keys::kOriginAndPathMatchesKey] =
+ &F::CreateOriginAndPathMatchesCondition;
+ factory_methods_[keys::kPathContainsKey] = &F::CreatePathContainsCondition;
+ factory_methods_[keys::kPathEqualsKey] = &F::CreatePathEqualsCondition;
+ factory_methods_[keys::kPathPrefixKey] = &F::CreatePathPrefixCondition;
+ factory_methods_[keys::kPathSuffixKey] = &F::CreatePathSuffixCondition;
+ factory_methods_[keys::kQueryContainsKey] =
+ &F::CreateQueryContainsCondition;
+ factory_methods_[keys::kQueryEqualsKey] = &F::CreateQueryEqualsCondition;
+ factory_methods_[keys::kQueryPrefixKey] = &F::CreateQueryPrefixCondition;
+ factory_methods_[keys::kQuerySuffixKey] = &F::CreateQuerySuffixCondition;
+ factory_methods_[keys::kURLContainsKey] = &F::CreateURLContainsCondition;
+ factory_methods_[keys::kURLEqualsKey] = &F::CreateURLEqualsCondition;
+ factory_methods_[keys::kURLPrefixKey] = &F::CreateURLPrefixCondition;
+ factory_methods_[keys::kURLSuffixKey] = &F::CreateURLSuffixCondition;
+ factory_methods_[keys::kURLMatchesKey] = &F::CreateURLMatchesCondition;
+ }
+
+ // Returns whether a factory method for the specified |pattern_type| (e.g.
+ // "host_suffix") is known.
+ bool Contains(const std::string& pattern_type) const {
+ return factory_methods_.find(pattern_type) != factory_methods_.end();
+ }
+
+ // Creates a URLMatcherCondition instance from |url_matcher_condition_factory|
+ // of the given |pattern_type| (e.g. "host_suffix") for the given
+ // |pattern_value| (e.g. "example.com").
+ // The |pattern_type| needs to be known to this class (see Contains()) or
+ // a CHECK is triggered.
+ URLMatcherCondition Call(
+ URLMatcherConditionFactory* url_matcher_condition_factory,
+ const std::string& pattern_type,
+ const std::string& pattern_value) const {
+ FactoryMethods::const_iterator i = factory_methods_.find(pattern_type);
+ CHECK(i != factory_methods_.end());
+ const FactoryMethod& method = i->second;
+ return (url_matcher_condition_factory->*method)(pattern_value);
+ }
+
+ private:
+ typedef URLMatcherCondition
+ (URLMatcherConditionFactory::* FactoryMethod)
+ (const std::string& prefix);
+ typedef std::map<std::string, FactoryMethod> FactoryMethods;
+
+ FactoryMethods factory_methods_;
+
+ DISALLOW_COPY_AND_ASSIGN(URLMatcherConditionFactoryMethods);
+};
+
+static base::LazyInstance<URLMatcherConditionFactoryMethods>
+ g_url_matcher_condition_factory_methods = LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+// static
+scoped_refptr<URLMatcherConditionSet>
+URLMatcherFactory::CreateFromURLFilterDictionary(
+ URLMatcherConditionFactory* url_matcher_condition_factory,
+ const base::DictionaryValue* url_filter_dict,
+ URLMatcherConditionSet::ID id,
+ std::string* error) {
+ scoped_ptr<URLMatcherSchemeFilter> url_matcher_schema_filter;
+ scoped_ptr<URLMatcherPortFilter> url_matcher_port_filter;
+ URLMatcherConditionSet::Conditions url_matcher_conditions;
+
+ for (base::DictionaryValue::Iterator iter(*url_filter_dict);
+ !iter.IsAtEnd(); iter.Advance()) {
+ const std::string& condition_attribute_name = iter.key();
+ const Value& condition_attribute_value = iter.value();
+ if (IsURLMatcherConditionAttribute(condition_attribute_name)) {
+ // Handle {host, path, ...}{Prefix, Suffix, Contains, Equals}.
+ URLMatcherCondition url_matcher_condition =
+ CreateURLMatcherCondition(
+ url_matcher_condition_factory,
+ condition_attribute_name,
+ &condition_attribute_value,
+ error);
+ if (!error->empty())
+ return scoped_refptr<URLMatcherConditionSet>(NULL);
+ url_matcher_conditions.insert(url_matcher_condition);
+ } else if (condition_attribute_name == keys::kSchemesKey) {
+ // Handle scheme.
+ url_matcher_schema_filter = CreateURLMatcherScheme(
+ &condition_attribute_value, error);
+ if (!error->empty())
+ return scoped_refptr<URLMatcherConditionSet>(NULL);
+ } else if (condition_attribute_name == keys::kPortsKey) {
+ // Handle ports.
+ url_matcher_port_filter = CreateURLMatcherPorts(
+ &condition_attribute_value, error);
+ if (!error->empty())
+ return scoped_refptr<URLMatcherConditionSet>(NULL);
+ } else {
+ // Handle unknown attributes.
+ *error = base::StringPrintf(kUnknownURLFilterAttribute,
+ condition_attribute_name.c_str());
+ return scoped_refptr<URLMatcherConditionSet>(NULL);
+ }
+ }
+
+ // As the URL is the preliminary matching criterion that triggers the tests
+ // for the remaining condition attributes, we insert an empty URL match if
+ // no other url match conditions were specified. Such an empty URL is always
+ // matched.
+ if (url_matcher_conditions.empty()) {
+ url_matcher_conditions.insert(
+ url_matcher_condition_factory->CreateHostPrefixCondition(
+ std::string()));
+ }
+
+ scoped_refptr<URLMatcherConditionSet> url_matcher_condition_set(
+ new URLMatcherConditionSet(id, url_matcher_conditions,
+ url_matcher_schema_filter.Pass(), url_matcher_port_filter.Pass()));
+ return url_matcher_condition_set;
+}
+
+// static
+bool URLMatcherFactory::IsURLMatcherConditionAttribute(
+ const std::string& condition_attribute_name) {
+ return g_url_matcher_condition_factory_methods.Get().Contains(
+ condition_attribute_name);
+}
+
+namespace {
+
+// Returns true if some alphabetic characters in this string are upper case.
+bool ContainsUpperCase(const std::string& str) {
+ return std::find_if(str.begin(), str.end(), ::isupper) != str.end();
+}
+
+} // namespace
+
+// static
+URLMatcherCondition URLMatcherFactory::CreateURLMatcherCondition(
+ URLMatcherConditionFactory* url_matcher_condition_factory,
+ const std::string& condition_attribute_name,
+ const base::Value* value,
+ std::string* error) {
+ std::string str_value;
+ if (!value->GetAsString(&str_value)) {
+ *error = base::StringPrintf(kAttributeExpectedString,
+ condition_attribute_name.c_str());
+ return URLMatcherCondition();
+ }
+ if (condition_attribute_name == keys::kHostContainsKey ||
+ condition_attribute_name == keys::kHostPrefixKey ||
+ condition_attribute_name == keys::kHostSuffixKey ||
+ condition_attribute_name == keys::kHostEqualsKey) {
+ if (ContainsUpperCase(str_value)) {
+ *error = base::StringPrintf(kLowerCaseExpected, "Host");
+ return URLMatcherCondition();
+ }
+ }
+
+ // Test regular expressions for validity.
+ if (condition_attribute_name == keys::kURLMatchesKey ||
+ condition_attribute_name == keys::kOriginAndPathMatchesKey) {
+ re2::RE2 regex(str_value);
+ if (!regex.ok()) {
+ *error = base::StringPrintf(
+ kUnparseableRegexString, str_value.c_str(), regex.error().c_str());
+ return URLMatcherCondition();
+ }
+ }
+ return g_url_matcher_condition_factory_methods.Get().Call(
+ url_matcher_condition_factory, condition_attribute_name, str_value);
+}
+
+// static
+scoped_ptr<URLMatcherSchemeFilter> URLMatcherFactory::CreateURLMatcherScheme(
+ const base::Value* value,
+ std::string* error) {
+ std::vector<std::string> schemas;
+ if (!helpers::GetAsStringVector(value, &schemas)) {
+ *error = base::StringPrintf(kVectorOfStringsExpected, keys::kSchemesKey);
+ return scoped_ptr<URLMatcherSchemeFilter>();
+ }
+ for (std::vector<std::string>::const_iterator it = schemas.begin();
+ it != schemas.end(); ++it) {
+ if (ContainsUpperCase(*it)) {
+ *error = base::StringPrintf(kLowerCaseExpected, "Scheme");
+ return scoped_ptr<URLMatcherSchemeFilter>();
+ }
+ }
+ return scoped_ptr<URLMatcherSchemeFilter>(
+ new URLMatcherSchemeFilter(schemas));
+}
+
+// static
+scoped_ptr<URLMatcherPortFilter> URLMatcherFactory::CreateURLMatcherPorts(
+ const base::Value* value,
+ std::string* error) {
+ std::vector<URLMatcherPortFilter::Range> ranges;
+ const base::ListValue* value_list = NULL;
+ if (!value->GetAsList(&value_list)) {
+ *error = kInvalidPortRanges;
+ return scoped_ptr<URLMatcherPortFilter>();
+ }
+
+ for (ListValue::const_iterator i = value_list->begin();
+ i != value_list->end(); ++i) {
+ Value* entry = *i;
+ int port = 0;
+ base::ListValue* range = NULL;
+ if (entry->GetAsInteger(&port)) {
+ ranges.push_back(URLMatcherPortFilter::CreateRange(port));
+ } else if (entry->GetAsList(&range)) {
+ int from = 0, to = 0;
+ if (range->GetSize() != 2u ||
+ !range->GetInteger(0, &from) ||
+ !range->GetInteger(1, &to)) {
+ *error = kInvalidPortRanges;
+ return scoped_ptr<URLMatcherPortFilter>();
+ }
+ ranges.push_back(URLMatcherPortFilter::CreateRange(from, to));
+ } else {
+ *error = kInvalidPortRanges;
+ return scoped_ptr<URLMatcherPortFilter>();
+ }
+ }
+
+ return scoped_ptr<URLMatcherPortFilter>(new URLMatcherPortFilter(ranges));
+}
+
+} // namespace url_matcher