Hook up WebRequestRulesRegistry into old WebRequest API
[chromium-blink-merge.git] / chrome / browser / extensions / api / declarative_webrequest / webrequest_condition.cc
blob609a1096cc0e03587b5ccab5a219916a40ba4b10
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h"
7 #include "base/bind.h"
8 #include "base/lazy_instance.h"
9 #include "base/logging.h"
10 #include "base/stringprintf.h"
11 #include "base/values.h"
12 #include "chrome/browser/extensions/api/declarative_webrequest/request_stages.h"
13 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h"
14 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h"
15 #include "net/url_request/url_request.h"
17 namespace {
18 static extensions::URLMatcherConditionSet::ID g_next_id = 0;
20 // TODO(battre): improve error messaging to give more meaningful messages
21 // to the extension developer.
22 // Error messages:
23 const char kExpectedDictionary[] = "A condition has to be a dictionary.";
24 const char kConditionWithoutInstanceType[] = "A condition had no instanceType";
25 const char kExpectedOtherConditionType[] = "Expected a condition of type "
26 "experimental.webRequest.RequestMatcher";
27 const char kUnknownConditionAttribute[] = "UnKnown condition attribute '%s'";
28 const char kConditionExpectedString[] =
29 "Condition '%s' expected a string value";
31 // String literals from the JavaScript API:
32 const char kHostContainsKey[] = "host_contains";
33 const char kHostEqualsKey[] = "host_equals";
34 const char kHostPrefixKey[] = "host_prefix";
35 const char kHostSuffixKey[] = "host_suffix";
36 const char kHostSuffixPathPrefixKey[] = "host_suffix_path_prefix";
37 const char kPathContainsKey[] = "path_contains";
38 const char kPathEqualsKey[] = "path_equals";
39 const char kPathPrefixKey[] = "path_prefix";
40 const char kPathSuffixKey[] = "path_suffix";
41 const char kQueryContainsKey[] = "query_contains";
42 const char kQueryEqualsKey[] = "query_equals";
43 const char kQueryPrefixKey[] = "query_prefix";
44 const char kQuerySuffixKey[] = "query_suffix";
45 const char kURLContainsKey[] = "url_contains";
46 const char kURLEqualsKey[] = "url_equals";
47 const char kURLPrefixKey[] = "url_prefix";
48 const char kURLSuffixKey[] = "url_suffix";
50 // Registry for all factory methods of extensions::URLMatcherConditionFactory
51 // that allows translating string literals from the extension API into
52 // the corresponding factory method to be called.
53 class URLMatcherConditionFactoryMethods {
54 public:
55 URLMatcherConditionFactoryMethods() {
56 typedef extensions::URLMatcherConditionFactory F;
57 factory_methods_[kHostContainsKey] = &F::CreateHostContainsCondition;
58 factory_methods_[kHostEqualsKey] = &F::CreateHostEqualsCondition;
59 factory_methods_[kHostPrefixKey] = &F::CreateHostPrefixCondition;
60 factory_methods_[kHostSuffixKey] = &F::CreateHostSuffixCondition;
61 factory_methods_[kPathContainsKey] = &F::CreatePathContainsCondition;
62 factory_methods_[kPathEqualsKey] = &F::CreatePathEqualsCondition;
63 factory_methods_[kPathPrefixKey] = &F::CreatePathPrefixCondition;
64 factory_methods_[kPathSuffixKey] = &F::CreatePathSuffixCondition;
65 factory_methods_[kQueryContainsKey] = &F::CreateQueryContainsCondition;
66 factory_methods_[kQueryEqualsKey] = &F::CreateQueryEqualsCondition;
67 factory_methods_[kQueryPrefixKey] = &F::CreateQueryPrefixCondition;
68 factory_methods_[kQuerySuffixKey] = &F::CreateQuerySuffixCondition;
69 factory_methods_[kURLContainsKey] = &F::CreateURLContainsCondition;
70 factory_methods_[kURLEqualsKey] = &F::CreateURLEqualsCondition;
71 factory_methods_[kURLPrefixKey] = &F::CreateURLPrefixCondition;
72 factory_methods_[kURLSuffixKey] = &F::CreateURLSuffixCondition;
75 // Returns whether a factory method for the specified |pattern_type| (e.g.
76 // "host_suffix") is known.
77 bool Contains(const std::string& pattern_type) const {
78 return factory_methods_.find(pattern_type) != factory_methods_.end();
81 // Creates a URLMatcherCondition instance from |url_matcher_condition_factory|
82 // of the given |pattern_type| (e.g. "host_suffix") for the given
83 // |pattern_value| (e.g. "example.com").
84 // The |pattern_type| needs to be known to this class (see Contains()) or
85 // a CHECK is triggered.
86 extensions::URLMatcherCondition Call(
87 extensions::URLMatcherConditionFactory* url_matcher_condition_factory,
88 const std::string& pattern_type,
89 const std::string& pattern_value) const {
90 FactoryMethods::const_iterator i = factory_methods_.find(pattern_type);
91 CHECK(i != factory_methods_.end());
92 const FactoryMethod& method = i->second;
93 return (url_matcher_condition_factory->*method)(pattern_value);
96 private:
97 typedef extensions::URLMatcherCondition
98 (extensions::URLMatcherConditionFactory::* FactoryMethod)
99 (const std::string& prefix);
100 typedef std::map<std::string, FactoryMethod> FactoryMethods;
102 FactoryMethods factory_methods_;
104 DISALLOW_COPY_AND_ASSIGN(URLMatcherConditionFactoryMethods);
107 static base::LazyInstance<URLMatcherConditionFactoryMethods>
108 g_url_matcher_condition_factory_methods = LAZY_INSTANCE_INITIALIZER;
110 } // namespace
112 namespace extensions {
114 namespace keys = declarative_webrequest_constants;
117 // WebRequestCondition
120 WebRequestCondition::WebRequestCondition(
121 const URLMatcherConditionSet& url_matcher_conditions,
122 const WebRequestConditionAttributes& condition_attributes)
123 : url_matcher_conditions_(url_matcher_conditions),
124 condition_attributes_(condition_attributes),
125 applicable_request_stages_(~0) {
126 for (WebRequestConditionAttributes::const_iterator i =
127 condition_attributes_.begin(); i != condition_attributes_.end(); ++i) {
128 applicable_request_stages_ &= (*i)->GetStages();
132 WebRequestCondition::~WebRequestCondition() {}
134 bool WebRequestCondition::IsFulfilled(net::URLRequest* request,
135 RequestStages request_stage) const {
136 // All condition attributes must be fulfilled for a fulfilled condition.
137 if (!(request_stage & applicable_request_stages_)) {
138 // A condition that cannot be evaluated is considered as violated.
139 return false;
142 for (WebRequestConditionAttributes::const_iterator i =
143 condition_attributes_.begin(); i != condition_attributes_.end(); ++i) {
144 if (!(*i)->IsFulfilled(request, request_stage))
145 return false;
147 return true;
150 // static
151 scoped_ptr<WebRequestCondition> WebRequestCondition::Create(
152 URLMatcherConditionFactory* url_matcher_condition_factory,
153 const base::Value& condition,
154 std::string* error) {
155 const base::DictionaryValue* condition_dict = NULL;
156 if (!condition.GetAsDictionary(&condition_dict)) {
157 *error = kExpectedDictionary;
158 return scoped_ptr<WebRequestCondition>(NULL);
161 // Verify that we are dealing with a Condition whose type we understand.
162 std::string instance_type;
163 if (!condition_dict->GetString(keys::kInstanceTypeKey, &instance_type)) {
164 *error = kConditionWithoutInstanceType;
165 return scoped_ptr<WebRequestCondition>(NULL);
167 if (instance_type != keys::kRequestMatcherType) {
168 *error = kExpectedOtherConditionType;
169 return scoped_ptr<WebRequestCondition>(NULL);
172 WebRequestConditionAttributes attributes;
173 URLMatcherConditionSet::Conditions url_matcher_conditions;
175 for (base::DictionaryValue::Iterator iter(*condition_dict);
176 iter.HasNext(); iter.Advance()) {
177 const std::string& condition_attribute_name = iter.key();
178 const Value& condition_attribute_value = iter.value();
179 if (condition_attribute_name == keys::kInstanceTypeKey) {
180 // Skip this.
181 } else if (IsURLMatcherConditionAttribute(condition_attribute_name)) {
182 URLMatcherCondition url_matcher_condition =
183 CreateURLMatcherCondition(
184 url_matcher_condition_factory,
185 condition_attribute_name,
186 &condition_attribute_value,
187 error);
188 if (!error->empty())
189 return scoped_ptr<WebRequestCondition>(NULL);
190 url_matcher_conditions.insert(url_matcher_condition);
191 } else if (WebRequestConditionAttribute::IsKnownType(
192 condition_attribute_name)) {
193 scoped_ptr<WebRequestConditionAttribute> attribute =
194 WebRequestConditionAttribute::Create(
195 condition_attribute_name,
196 &condition_attribute_value,
197 error);
198 if (!error->empty())
199 return scoped_ptr<WebRequestCondition>(NULL);
200 attributes.push_back(make_linked_ptr(attribute.release()));
201 } else {
202 *error = base::StringPrintf(kUnknownConditionAttribute,
203 condition_attribute_name.c_str());
204 return scoped_ptr<WebRequestCondition>(NULL);
208 // As the URL is the preliminary matching criterion that triggers the tests
209 // for the remaining condition attributes, we insert an empty URL match if
210 // no other url match conditions were specified. Such an empty URL is always
211 // matched.
212 if (url_matcher_conditions.empty()) {
213 url_matcher_conditions.insert(
214 url_matcher_condition_factory->CreateHostPrefixCondition(""));
217 URLMatcherConditionSet url_matcher_condition_set(++g_next_id,
218 url_matcher_conditions);
219 return scoped_ptr<WebRequestCondition>(
220 new WebRequestCondition(url_matcher_condition_set, attributes));
223 // static
224 bool WebRequestCondition::IsURLMatcherConditionAttribute(
225 const std::string& condition_attribute_name) {
226 return g_url_matcher_condition_factory_methods.Get().Contains(
227 condition_attribute_name);
230 // static
231 URLMatcherCondition WebRequestCondition::CreateURLMatcherCondition(
232 URLMatcherConditionFactory* url_matcher_condition_factory,
233 const std::string& condition_attribute_name,
234 const base::Value* value,
235 std::string* error) {
236 std::string str_value;
237 if (!value->GetAsString(&str_value)) {
238 *error = base::StringPrintf(kConditionExpectedString,
239 condition_attribute_name.c_str());
240 return URLMatcherCondition();
242 return g_url_matcher_condition_factory_methods.Get().Call(
243 url_matcher_condition_factory, condition_attribute_name, str_value);
248 // WebRequestConditionSet
251 WebRequestConditionSet::WebRequestConditionSet(
252 const std::vector<linked_ptr<WebRequestCondition> >& conditions)
253 : conditions_(conditions) {
254 for (Conditions::iterator i = conditions_.begin(); i != conditions_.end();
255 ++i) {
256 URLMatcherConditionSet::ID trigger_id =
257 (*i)->url_matcher_condition_set_id();
258 match_triggers_[trigger_id] = i->get();
262 WebRequestConditionSet::~WebRequestConditionSet() {}
264 bool WebRequestConditionSet::IsFulfilled(
265 URLMatcherConditionSet::ID url_match,
266 net::URLRequest* request,
267 RequestStages request_stage) const {
268 MatchTriggers::const_iterator trigger = match_triggers_.find(url_match);
269 DCHECK(trigger != match_triggers_.end());
270 DCHECK_EQ(url_match, trigger->second->url_matcher_condition_set_id());
271 return trigger->second->IsFulfilled(request, request_stage);
274 void WebRequestConditionSet::GetURLMatcherConditionSets(
275 std::vector<URLMatcherConditionSet>* condition_sets) const {
276 for (Conditions::const_iterator i = conditions_.begin();
277 i != conditions_.end(); ++i) {
278 condition_sets->push_back((*i)->url_matcher_condition_set());
282 // static
283 scoped_ptr<WebRequestConditionSet> WebRequestConditionSet::Create(
284 URLMatcherConditionFactory* url_matcher_condition_factory,
285 const AnyVector& conditions,
286 std::string* error) {
287 std::vector<linked_ptr<WebRequestCondition> > result;
289 for (AnyVector::const_iterator i = conditions.begin();
290 i != conditions.end(); ++i) {
291 CHECK(i->get());
292 scoped_ptr<WebRequestCondition> condition =
293 WebRequestCondition::Create(url_matcher_condition_factory,
294 (*i)->value(), error);
295 if (!error->empty())
296 return scoped_ptr<WebRequestConditionSet>(NULL);
297 result.push_back(make_linked_ptr(condition.release()));
300 return scoped_ptr<WebRequestConditionSet>(new WebRequestConditionSet(result));
303 } // namespace extensions