Index: chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.cc |
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4523dcebfe3b517e8c8199876ce5ad25304e9fc3 |
--- /dev/null |
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.cc |
@@ -0,0 +1,290 @@ |
+// 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 "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h" |
+ |
+#include "base/bind.h" |
+#include "base/lazy_instance.h" |
+#include "base/logging.h" |
+#include "base/stringprintf.h" |
+#include "base/values.h" |
+#include "chrome/browser/extensions/api/declarative_webrequest/request_stages.h" |
+#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h" |
+#include "net/url_request/url_request.h" |
+ |
+namespace { |
+static extensions::URLMatcherConditionSet::ID g_next_id = 0; |
+ |
+// TODO(battre): improve error messaging to give more meaningful messages |
+// to the extension developer. |
+// Error messages: |
+const char kExpectedDictionary[] = "A condition has to be a dictionary."; |
+const char kConditionWithoutInstanceType[] = "A condition had no instanceType"; |
+const char kExpectedOtherConditionType[] = "Expected a condition of type " |
+ "experimental.webRequest.RequestMatcher"; |
+const char kUnknownConditionAttribute[] = "UnKnown condition attribute '%s'"; |
+const char kConditionExpectedString[] = |
+ "Condition '%s' expected a string value"; |
+ |
+// String literals from the JavaScript API: |
+const char kRequestMatcher[] = "experimental.webRequest.RequestMatcher"; |
+const char kInstanceType[] = "instanceType"; |
+ |
+const char kHostContainsKey[] = "host_contains"; |
+const char kHostEqualsKey[] = "host_equals"; |
+const char kHostPrefixKey[] = "host_prefix"; |
+const char kHostSuffixKey[] = "host_suffix"; |
+const char kHostSuffixPathPrefixKey[] = "host_suffix_path_prefix"; |
+const char kPathContainsKey[] = "path_contains"; |
+const char kPathEqualsKey[] = "path_equals"; |
+const char kPathPrefixKey[] = "path_prefix"; |
+const char kPathSuffixKey[] = "path_suffix"; |
+const char kQueryContainsKey[] = "query_contains"; |
+const char kQueryEqualsKey[] = "query_equals"; |
+const char kQueryPrefixKey[] = "query_prefix"; |
+const char kQuerySuffixKey[] = "query_suffix"; |
+const char kURLContainsKey[] = "url_contains"; |
+const char kURLEqualsKey[] = "url_equals"; |
+const char kURLPrefixKey[] = "url_prefix"; |
+const char kURLSuffixKey[] = "url_suffix"; |
+ |
+// Registry for all factory methods of extensions::URLMatcherConditionFactory |
+// that allows translating string literals from the extension API into |
+// the corresponding factory method to be called. |
+class URLMatcherConditionFactoryMethods { |
+ public: |
+ URLMatcherConditionFactoryMethods() { |
+ typedef extensions::URLMatcherConditionFactory F; |
+ factory_methods_[kHostContainsKey] = &F::CreateHostContainsCondition; |
+ factory_methods_[kHostEqualsKey] = &F::CreateHostEqualsCondition; |
+ factory_methods_[kHostPrefixKey] = &F::CreateHostPrefixCondition; |
+ factory_methods_[kHostSuffixKey] = &F::CreateHostSuffixCondition; |
+ factory_methods_[kPathContainsKey] = &F::CreatePathContainsCondition; |
+ factory_methods_[kPathEqualsKey] = &F::CreatePathEqualsCondition; |
+ factory_methods_[kPathPrefixKey] = &F::CreatePathPrefixCondition; |
+ factory_methods_[kPathSuffixKey] = &F::CreatePathSuffixCondition; |
+ factory_methods_[kQueryContainsKey] = &F::CreateQueryContainsCondition; |
+ factory_methods_[kQueryEqualsKey] = &F::CreateQueryEqualsCondition; |
+ factory_methods_[kQueryPrefixKey] = &F::CreateQueryPrefixCondition; |
+ factory_methods_[kQuerySuffixKey] = &F::CreateQuerySuffixCondition; |
+ factory_methods_[kURLContainsKey] = &F::CreateURLContainsCondition; |
+ factory_methods_[kURLEqualsKey] = &F::CreateURLEqualsCondition; |
+ factory_methods_[kURLPrefixKey] = &F::CreateURLPrefixCondition; |
+ factory_methods_[kURLSuffixKey] = &F::CreateURLSuffixCondition; |
+ } |
+ |
+ // 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. |
+ extensions::URLMatcherCondition Call( |
+ extensions::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 extensions::URLMatcherCondition |
+ (extensions::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 |
+ |
+namespace extensions { |
+ |
+// |
+// WebRequestCondition |
+// |
+ |
+WebRequestCondition::WebRequestCondition( |
+ const URLMatcherConditionSet& url_matcher_conditions, |
+ const WebRequestConditionAttributes& condition_attributes) |
+ : url_matcher_conditions_(url_matcher_conditions), |
+ condition_attributes_(condition_attributes) {} |
+ |
+WebRequestCondition::~WebRequestCondition() {} |
+ |
+bool WebRequestCondition::IsFulfilled(net::URLRequest* request) const { |
+ // All condition attributes must be fulfilled for a fulfilled condition. |
+ for (WebRequestConditionAttributes::const_iterator i = |
+ condition_attributes_.begin(); i != condition_attributes_.end(); ++i) { |
+ if (!(*i)->IsFulfilled(request)) |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+// static |
+scoped_ptr<WebRequestCondition> WebRequestCondition::Create( |
+ URLMatcherConditionFactory* url_matcher_condition_factory, |
+ const base::Value& condition, |
+ std::string* error) { |
+ const base::DictionaryValue* condition_dict = NULL; |
+ if (!condition.GetAsDictionary(&condition_dict)) { |
+ *error = kExpectedDictionary; |
+ return scoped_ptr<WebRequestCondition>(NULL); |
+ } |
+ |
+ // Verify that we are dealing with a Condition whose type we understand. |
+ std::string instance_type; |
+ if (!condition_dict->GetString(kInstanceType, &instance_type)) { |
+ *error = kConditionWithoutInstanceType; |
+ return scoped_ptr<WebRequestCondition>(NULL); |
+ } |
+ if (instance_type != kRequestMatcher) { |
+ *error = kExpectedOtherConditionType; |
+ return scoped_ptr<WebRequestCondition>(NULL); |
+ } |
+ |
+ WebRequestConditionAttributes attributes; |
+ URLMatcherConditionSet::Conditions url_matcher_conditions; |
+ |
+ for (base::DictionaryValue::Iterator iter(*condition_dict); |
+ iter.HasNext(); iter.Advance()) { |
+ const std::string& condition_attribute_name = iter.key(); |
+ const Value& condition_attribute_value = iter.value(); |
+ if (condition_attribute_name == kInstanceType) { |
+ // Skip this. |
+ } else if (IsURLMatcherConditionAttribute(condition_attribute_name)) { |
+ URLMatcherCondition url_matcher_condition = |
+ CreateURLMatcherCondition( |
+ url_matcher_condition_factory, |
+ condition_attribute_name, |
+ &condition_attribute_value, |
+ error); |
+ if (!error->empty()) |
+ return scoped_ptr<WebRequestCondition>(NULL); |
+ url_matcher_conditions.insert(url_matcher_condition); |
+ } else if (WebRequestConditionAttribute::IsKnownType( |
+ condition_attribute_name)) { |
+ scoped_ptr<WebRequestConditionAttribute> attribute = |
+ WebRequestConditionAttribute::Create( |
+ condition_attribute_name, |
+ &condition_attribute_value, |
+ error); |
+ if (!error->empty()) |
+ return scoped_ptr<WebRequestCondition>(NULL); |
+ attributes.push_back(make_linked_ptr(attribute.release())); |
+ } else { |
+ *error = base::StringPrintf(kUnknownConditionAttribute, |
+ condition_attribute_name.c_str()); |
+ return scoped_ptr<WebRequestCondition>(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("")); |
+ } |
+ |
+ URLMatcherConditionSet url_matcher_condition_set(++g_next_id, |
+ url_matcher_conditions); |
+ return scoped_ptr<WebRequestCondition>( |
+ new WebRequestCondition(url_matcher_condition_set, attributes)); |
+} |
+ |
+// static |
+bool WebRequestCondition::IsURLMatcherConditionAttribute( |
+ const std::string& condition_attribute_name) { |
+ return g_url_matcher_condition_factory_methods.Get().Contains( |
+ condition_attribute_name); |
+} |
+ |
+// static |
+URLMatcherCondition WebRequestCondition::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(kConditionExpectedString, |
+ condition_attribute_name.c_str()); |
+ return URLMatcherCondition(); |
+ } |
+ return g_url_matcher_condition_factory_methods.Get().Call( |
+ url_matcher_condition_factory, condition_attribute_name, str_value); |
+} |
+ |
+ |
+// |
+// WebRequestConditionSet |
+// |
+ |
+WebRequestConditionSet::WebRequestConditionSet( |
+ const std::vector<linked_ptr<WebRequestCondition> >& conditions) |
+ : conditions_(conditions) { |
+ for (Conditions::iterator i = conditions_.begin(); i != conditions_.end(); |
+ ++i) { |
+ URLMatcherConditionSet::ID trigger_id = |
+ (*i)->url_matcher_condition_set_id(); |
+ match_triggers_[trigger_id] = i->get(); |
+ } |
+} |
+ |
+WebRequestConditionSet::~WebRequestConditionSet() {} |
+ |
+bool WebRequestConditionSet::IsFulfilled( |
+ URLMatcherConditionSet::ID url_match, |
+ net::URLRequest* request) const { |
+ MatchTriggers::const_iterator trigger = match_triggers_.find(url_match); |
+ DCHECK(trigger != match_triggers_.end()); |
+ DCHECK_EQ(url_match, trigger->second->url_matcher_condition_set_id()); |
+ return trigger->second->IsFulfilled(request); |
+} |
+ |
+void WebRequestConditionSet::GetURLMatcherConditionSets( |
+ std::vector<URLMatcherConditionSet>* condition_sets) const { |
+ for (Conditions::const_iterator i = conditions_.begin(); |
+ i != conditions_.end(); ++i) { |
+ condition_sets->push_back((*i)->url_matcher_condition_set()); |
+ } |
+} |
+ |
+// static |
+scoped_ptr<WebRequestConditionSet> WebRequestConditionSet::Create( |
+ URLMatcherConditionFactory* url_matcher_condition_factory, |
+ const AnyVector& conditions, |
+ std::string* error) { |
+ std::vector<linked_ptr<WebRequestCondition> > result; |
+ |
+ for (AnyVector::const_iterator i = conditions.begin(); |
+ i != conditions.end(); ++i) { |
+ CHECK(i->get()); |
+ scoped_ptr<WebRequestCondition> condition = |
+ WebRequestCondition::Create(url_matcher_condition_factory, |
+ (*i)->value(), error); |
+ if (!error->empty()) |
+ return scoped_ptr<WebRequestConditionSet>(NULL); |
+ result.push_back(make_linked_ptr(condition.release())); |
+ } |
+ |
+ return scoped_ptr<WebRequestConditionSet>(new WebRequestConditionSet(result)); |
+} |
+ |
+} // namespace extensions |