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..7e28332291890342fddaa49e3a53d25259844078 |
--- /dev/null |
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.cc |
@@ -0,0 +1,311 @@ |
+// 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/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"; |
+ |
+// This is an array of all criteria that may be evaluated on the URL. |
+// These MUST appear in alphabetical order in order to allow a binary search |
+// on them. |
+const char* kAllPathAttributes[] = { |
Matt Perry
2012/03/22 01:34:43
Putting these in a global map would remove the alp
battre
2012/03/26 18:35:51
Done.
|
+ kHostContainsKey, |
+ kHostEqualsKey, |
+ kHostPrefixKey, |
+ kHostSuffixKey, |
+ // kHostSuffixPathPrefixKey, // TODO(battre): support this. |
+ kPathContainsKey, |
+ kPathEqualsKey, |
+ kPathPrefixKey, |
+ kPathSuffixKey, |
+ kQueryContainsKey, |
+ kQueryEqualsKey, |
+ kQueryPrefixKey, |
+ kQuerySuffixKey, |
+ kURLContainsKey, |
+ kURLEqualsKey, |
+ kURLPrefixKey, |
+ kURLSuffixKey |
+}; |
+ |
+} // namespace |
+ |
+namespace extensions { |
+namespace declarative_webrequest { |
+ |
+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( |
+ URLMatcherConditionSet::ID url_match, |
+ net::URLRequest* request) const { |
+ if (url_match != url_matcher_condition_set_id()) |
+ return false; |
+ |
+ // 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; |
+} |
+ |
+void WebRequestCondition::AppendURLMatcherConditionSet( |
+ std::vector<URLMatcherConditionSet>* condition_sets) const { |
+ condition_sets->push_back(url_matcher_conditions_); |
+} |
+ |
+WebRequestConditionCollection::WebRequestConditionCollection( |
+ const std::vector<linked_ptr<WebRequestCondition> >& conditions) |
+ : conditions_(conditions) { |
+ for (Collection::iterator i = conditions_.begin(); i != conditions_.end(); |
+ ++i) { |
+ URLMatcherConditionSet::ID trigger_id = |
+ (*i)->url_matcher_condition_set_id(); |
+ match_triggers_[trigger_id] = i->get(); |
+ } |
+} |
+ |
+WebRequestConditionCollection::~WebRequestConditionCollection() {} |
+ |
+bool WebRequestConditionCollection::IsFulfilled( |
+ const std::set<URLMatcherConditionSet::ID>& url_matches, |
+ net::URLRequest* request) const { |
+ // The URL matcher found all SubstringPattern::ID in |url_matches|. |
+ // Let's see whether any of these is the primary SubstringPattern::ID |
+ // of a WebRequestCondition. |
+ for (std::set<URLMatcherConditionSet::ID>::const_iterator i = |
+ url_matches.begin(); i != url_matches.end(); ++i) { |
+ MatchTriggers::const_iterator trigger = match_triggers_.find(*i); |
+ if (trigger == match_triggers_.end()) |
+ continue; |
+ if (trigger->second->IsFulfilled(*i, request)) |
Matt Perry
2012/03/22 23:07:25
Is it necessary to pass in the set ID? If the cond
battre
2012/03/26 18:35:51
Done.
|
+ return true; |
+ } |
+ return false; |
+} |
+ |
+void WebRequestConditionCollection::AppendURLMatcherConditionSets( |
+ std::vector<URLMatcherConditionSet>* condition_sets) const { |
+ for (Collection::const_iterator i = conditions_.begin(); |
+ i != conditions_.end(); ++i) { |
+ (*i)->AppendURLMatcherConditionSet(condition_sets); |
+ } |
+} |
+ |
+// static |
+scoped_ptr<WebRequestCondition> WebRequestConditionFactory::CreateCondition( |
+ 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::key_iterator key = condition_dict->begin_keys(); |
Matt Perry
2012/03/22 23:07:25
Give DictionaryValue::Iterator a try, since you ne
battre
2012/03/26 18:35:51
Done.
|
+ key != condition_dict->end_keys(); ++key) { |
+ const std::string& condition_attribute_name = *key; |
+ if (condition_attribute_name == kInstanceType) |
+ continue; |
+ Value* condition_attribute_value = NULL; |
+ condition_dict->Get(condition_attribute_name, &condition_attribute_value); |
+ |
+ if (condition_attribute_name == instance_type) { |
Matt Perry
2012/03/22 23:07:25
When is this possible?
battre
2012/03/26 18:35:51
This was an error, I meant to compare to kInstance
|
+ // 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 (WebRequestConditionAttributeFactory::IsHandledByThisFactory( |
+ condition_attribute_name)) { |
+ scoped_ptr<WebRequestConditionAttribute> attribute = |
+ WebRequestConditionAttributeFactory::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 |
+scoped_ptr<WebRequestConditionCollection> |
+WebRequestConditionFactory::CreateConditionCollection( |
+ 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 = |
+ CreateCondition(url_matcher_condition_factory, (*i)->value(), error); |
+ if (!error->empty()) |
+ return scoped_ptr<WebRequestConditionCollection>(NULL); |
+ result.push_back(make_linked_ptr(condition.release())); |
+ } |
+ |
+ return scoped_ptr<WebRequestConditionCollection>( |
+ new WebRequestConditionCollection(result)); |
+} |
+ |
+// static |
+std::vector<std::string> WebRequestConditionFactory::GetAllPathAttributes() { |
+ return std::vector<std::string>( |
+ kAllPathAttributes, kAllPathAttributes + arraysize(kAllPathAttributes)); |
+} |
+ |
+// static |
+bool WebRequestConditionFactory::IsUrlMatcherConditionAttribute( |
+ const std::string& name) { |
+ return std::binary_search(kAllPathAttributes, |
+ kAllPathAttributes + arraysize(kAllPathAttributes), |
+ name); |
+} |
+ |
+// static |
+URLMatcherCondition WebRequestConditionFactory::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(); |
+ } |
+ |
+ URLMatcherConditionFactory* factory = url_matcher_condition_factory; |
+ if (condition_attribute_name == kHostContainsKey) { |
+ return factory->CreateHostContainsCondition(str_value); |
+ } else if (condition_attribute_name == kHostEqualsKey) { |
+ return factory->CreateHostEqualsCondition(str_value); |
+ } else if (condition_attribute_name == kHostPrefixKey) { |
+ return factory->CreateHostPrefixCondition(str_value); |
+ } else if (condition_attribute_name == kHostSuffixKey) { |
+ return factory->CreateHostSuffixCondition(str_value); |
+ } else if (condition_attribute_name == kHostSuffixPathPrefixKey) { |
+ NOTREACHED(); // Not implemented, yet. |
+ } else if (condition_attribute_name == kPathContainsKey) { |
+ return factory->CreatePathContainsCondition(str_value); |
+ } else if (condition_attribute_name == kPathEqualsKey) { |
+ return factory->CreatePathEqualsCondition(str_value); |
+ } else if (condition_attribute_name == kPathPrefixKey) { |
+ return factory->CreatePathPrefixCondition(str_value); |
+ } else if (condition_attribute_name == kPathSuffixKey) { |
+ return factory->CreatePathSuffixCondition(str_value); |
+ } else if (condition_attribute_name == kQueryContainsKey) { |
+ return factory->CreatePathContainsCondition(str_value); |
+ } else if (condition_attribute_name == kQueryEqualsKey) { |
+ return factory->CreateQueryEqualsCondition(str_value); |
+ } else if (condition_attribute_name == kQueryPrefixKey) { |
+ return factory->CreateQueryPrefixCondition(str_value); |
+ } else if (condition_attribute_name == kQuerySuffixKey) { |
+ return factory->CreateQuerySuffixCondition(str_value); |
+ } else if (condition_attribute_name == kURLContainsKey) { |
+ return factory->CreateURLContainsCondition(str_value); |
+ } else if (condition_attribute_name == kURLEqualsKey) { |
+ return factory->CreateURLEqualsCondition(str_value); |
+ } else if (condition_attribute_name == kURLPrefixKey) { |
+ return factory->CreateURLPrefixCondition(str_value); |
+ } else if (condition_attribute_name == kURLSuffixKey) { |
+ return factory->CreateURLSuffixCondition(str_value); |
+ } |
+ *error = "Unsupported url matching condition"; |
+ return URLMatcherCondition(); |
+} |
+ |
+} // namespace declarative_webrequest |
+} // namespace extensions |