OLD | NEW |
---|---|
(Empty) | |
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. | |
4 | |
5 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condit ion.h" | |
6 | |
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_condit ion_attribute.h" | |
14 #include "net/url_request/url_request.h" | |
15 | |
16 namespace { | |
17 static extensions::URLMatcherConditionSet::ID g_next_id = 0; | |
18 | |
19 // TODO(battre): improve error messaging to give more meaningful messages | |
20 // to the extension developer. | |
21 // Error messages: | |
22 const char kExpectedDictionary[] = "A condition has to be a dictionary."; | |
23 const char kConditionWithoutInstanceType[] = "A condition had no instanceType"; | |
24 const char kExpectedOtherConditionType[] = "Expected a condition of type " | |
25 "experimental.webRequest.RequestMatcher"; | |
26 const char kUnknownConditionAttribute[] = "UnKnown condition attribute '%s'"; | |
27 const char kConditionExpectedString[] = | |
28 "Condition '%s' expected a string value"; | |
29 | |
30 // String literals from the JavaScript API: | |
31 const char kRequestMatcher[] = "experimental.webRequest.RequestMatcher"; | |
32 const char kInstanceType[] = "instanceType"; | |
33 | |
34 const char kHostContainsKey[] = "host_contains"; | |
35 const char kHostEqualsKey[] = "host_equals"; | |
36 const char kHostPrefixKey[] = "host_prefix"; | |
37 const char kHostSuffixKey[] = "host_suffix"; | |
38 const char kHostSuffixPathPrefixKey[] = "host_suffix_path_prefix"; | |
39 const char kPathContainsKey[] = "path_contains"; | |
40 const char kPathEqualsKey[] = "path_equals"; | |
41 const char kPathPrefixKey[] = "path_prefix"; | |
42 const char kPathSuffixKey[] = "path_suffix"; | |
43 const char kQueryContainsKey[] = "query_contains"; | |
44 const char kQueryEqualsKey[] = "query_equals"; | |
45 const char kQueryPrefixKey[] = "query_prefix"; | |
46 const char kQuerySuffixKey[] = "query_suffix"; | |
47 const char kURLContainsKey[] = "url_contains"; | |
48 const char kURLEqualsKey[] = "url_equals"; | |
49 const char kURLPrefixKey[] = "url_prefix"; | |
50 const char kURLSuffixKey[] = "url_suffix"; | |
51 | |
52 // Registry for all factory methods of extensions::URLMatcherConditionFactory | |
53 // that allows translating string literals from the extension API into | |
54 // the corresponding factory method to be called. | |
55 class URLMatcherConditionFactoryMethods { | |
56 public: | |
57 URLMatcherConditionFactoryMethods() { | |
58 typedef extensions::URLMatcherConditionFactory F; | |
59 factory_methods_[kHostContainsKey] = &F::CreateHostContainsCondition; | |
60 factory_methods_[kHostEqualsKey] = &F::CreateHostEqualsCondition; | |
61 factory_methods_[kHostPrefixKey] = &F::CreateHostPrefixCondition; | |
62 factory_methods_[kHostSuffixKey] = &F::CreateHostSuffixCondition; | |
63 factory_methods_[kPathContainsKey] = &F::CreatePathContainsCondition; | |
64 factory_methods_[kPathEqualsKey] = &F::CreatePathEqualsCondition; | |
65 factory_methods_[kPathPrefixKey] = &F::CreatePathPrefixCondition; | |
66 factory_methods_[kPathSuffixKey] = &F::CreatePathSuffixCondition; | |
67 factory_methods_[kQueryContainsKey] = &F::CreateQueryContainsCondition; | |
68 factory_methods_[kQueryEqualsKey] = &F::CreateQueryEqualsCondition; | |
69 factory_methods_[kQueryPrefixKey] = &F::CreateQueryPrefixCondition; | |
70 factory_methods_[kQuerySuffixKey] = &F::CreateQuerySuffixCondition; | |
71 factory_methods_[kURLContainsKey] = &F::CreateURLContainsCondition; | |
72 factory_methods_[kURLEqualsKey] = &F::CreateURLEqualsCondition; | |
73 factory_methods_[kURLPrefixKey] = &F::CreateURLPrefixCondition; | |
74 factory_methods_[kURLSuffixKey] = &F::CreateURLSuffixCondition; | |
75 } | |
76 | |
77 // Returns whether a factory method for the specified |pattern_type| (e.g. | |
78 // "host_suffix") is known. | |
79 bool Contains(const std::string& pattern_type) const { | |
80 return factory_methods_.find(pattern_type) != factory_methods_.end(); | |
81 } | |
82 | |
83 // Creates a URLMatcherCondition instance from |url_matcher_condition_factory| | |
84 // of the given |pattern_type| (e.g. "host_suffix") for the given | |
85 // |pattern_value| (e.g. "example.com"). | |
86 // The |pattern_type| needs to be known to this class (see Contains()) or | |
87 // a CHECK is triggered. | |
88 extensions::URLMatcherCondition Call( | |
89 extensions::URLMatcherConditionFactory* url_matcher_condition_factory, | |
90 const std::string& pattern_type, | |
91 const std::string& pattern_value) const { | |
92 FactoryMethods::const_iterator i = factory_methods_.find(pattern_type); | |
93 CHECK(i != factory_methods_.end()); | |
94 const FactoryMethod& method = i->second; | |
95 return base::Bind(method, | |
96 base::Unretained(url_matcher_condition_factory)).Run(pattern_value); | |
Matt Perry
2012/03/26 20:21:20
You don't need to use Bind to invoke here. The syn
battre
2012/03/26 20:38:10
Done.
| |
97 } | |
98 | |
99 private: | |
100 typedef extensions::URLMatcherCondition | |
101 (extensions::URLMatcherConditionFactory::* FactoryMethod) | |
102 (const std::string& prefix); | |
103 typedef std::map<std::string, FactoryMethod> FactoryMethods; | |
104 | |
105 FactoryMethods factory_methods_; | |
106 | |
107 DISALLOW_COPY_AND_ASSIGN(URLMatcherConditionFactoryMethods); | |
108 }; | |
109 | |
110 static base::LazyInstance<URLMatcherConditionFactoryMethods> | |
111 g_url_matcher_condition_factory_methods = LAZY_INSTANCE_INITIALIZER; | |
112 | |
113 } // namespace | |
114 | |
115 namespace extensions { | |
116 | |
117 // | |
118 // WebRequestCondition | |
119 // | |
120 | |
121 WebRequestCondition::WebRequestCondition( | |
122 const URLMatcherConditionSet& url_matcher_conditions, | |
123 const WebRequestConditionAttributes& condition_attributes) | |
124 : url_matcher_conditions_(url_matcher_conditions), | |
125 condition_attributes_(condition_attributes) {} | |
126 | |
127 WebRequestCondition::~WebRequestCondition() {} | |
128 | |
129 bool WebRequestCondition::IsFulfilled(net::URLRequest* request) const { | |
130 // All condition attributes must be fulfilled for a fulfilled condition. | |
131 for (WebRequestConditionAttributes::const_iterator i = | |
132 condition_attributes_.begin(); i != condition_attributes_.end(); ++i) { | |
133 if (!(*i)->IsFulfilled(request)) | |
134 return false; | |
135 } | |
136 return true; | |
137 } | |
138 | |
139 // static | |
140 scoped_ptr<WebRequestCondition> WebRequestCondition::Create( | |
141 URLMatcherConditionFactory* url_matcher_condition_factory, | |
142 const base::Value& condition, | |
143 std::string* error) { | |
144 const base::DictionaryValue* condition_dict = NULL; | |
145 if (!condition.GetAsDictionary(&condition_dict)) { | |
146 *error = kExpectedDictionary; | |
147 return scoped_ptr<WebRequestCondition>(NULL); | |
148 } | |
149 | |
150 // Verify that we are dealing with a Condition whose type we understand. | |
151 std::string instance_type; | |
152 if (!condition_dict->GetString(kInstanceType, &instance_type)) { | |
153 *error = kConditionWithoutInstanceType; | |
154 return scoped_ptr<WebRequestCondition>(NULL); | |
155 } | |
156 if (instance_type != kRequestMatcher) { | |
157 *error = kExpectedOtherConditionType; | |
158 return scoped_ptr<WebRequestCondition>(NULL); | |
159 } | |
160 | |
161 WebRequestConditionAttributes attributes; | |
162 URLMatcherConditionSet::Conditions url_matcher_conditions; | |
163 | |
164 for (base::DictionaryValue::Iterator iter(*condition_dict); | |
165 iter.HasNext(); iter.Advance()) { | |
166 const std::string& condition_attribute_name = iter.key(); | |
167 const Value& condition_attribute_value = iter.value(); | |
168 if (condition_attribute_name == kInstanceType) { | |
169 // Skip this. | |
170 } else if (IsURLMatcherConditionAttribute(condition_attribute_name)) { | |
171 URLMatcherCondition url_matcher_condition = | |
172 CreateURLMatcherCondition( | |
173 url_matcher_condition_factory, | |
174 condition_attribute_name, | |
175 &condition_attribute_value, | |
176 error); | |
177 if (!error->empty()) | |
178 return scoped_ptr<WebRequestCondition>(NULL); | |
179 url_matcher_conditions.insert(url_matcher_condition); | |
180 } else if (WebRequestConditionAttribute::IsKnownType( | |
181 condition_attribute_name)) { | |
182 scoped_ptr<WebRequestConditionAttribute> attribute = | |
183 WebRequestConditionAttribute::Create( | |
184 condition_attribute_name, | |
185 &condition_attribute_value, | |
186 error); | |
187 if (!error->empty()) | |
188 return scoped_ptr<WebRequestCondition>(NULL); | |
189 attributes.push_back(make_linked_ptr(attribute.release())); | |
190 } else { | |
191 *error = base::StringPrintf(kUnknownConditionAttribute, | |
192 condition_attribute_name.c_str()); | |
193 return scoped_ptr<WebRequestCondition>(NULL); | |
194 } | |
195 } | |
196 | |
197 // As the URL is the preliminary matching criterion that triggers the tests | |
198 // for the remaining condition attributes, we insert an empty URL match if | |
199 // no other url match conditions were specified. Such an empty URL is always | |
200 // matched. | |
201 if (url_matcher_conditions.empty()) { | |
202 url_matcher_conditions.insert( | |
203 url_matcher_condition_factory->CreateHostPrefixCondition("")); | |
204 } | |
205 | |
206 URLMatcherConditionSet url_matcher_condition_set(++g_next_id, | |
207 url_matcher_conditions); | |
208 return scoped_ptr<WebRequestCondition>( | |
209 new WebRequestCondition(url_matcher_condition_set, attributes)); | |
210 } | |
211 | |
212 // static | |
213 bool WebRequestCondition::IsURLMatcherConditionAttribute( | |
214 const std::string& condition_attribute_name) { | |
215 return g_url_matcher_condition_factory_methods.Get().Contains( | |
216 condition_attribute_name); | |
217 } | |
218 | |
219 // static | |
220 URLMatcherCondition WebRequestCondition::CreateURLMatcherCondition( | |
221 URLMatcherConditionFactory* url_matcher_condition_factory, | |
222 const std::string& condition_attribute_name, | |
223 const base::Value* value, | |
224 std::string* error) { | |
225 std::string str_value; | |
226 if (!value->GetAsString(&str_value)) { | |
227 *error = base::StringPrintf(kConditionExpectedString, | |
228 condition_attribute_name.c_str()); | |
229 return URLMatcherCondition(); | |
230 } | |
231 return g_url_matcher_condition_factory_methods.Get().Call( | |
232 url_matcher_condition_factory, condition_attribute_name, str_value); | |
233 } | |
234 | |
235 | |
236 // | |
237 // WebRequestConditionCollection | |
238 // | |
239 | |
240 WebRequestConditionCollection::WebRequestConditionCollection( | |
241 const std::vector<linked_ptr<WebRequestCondition> >& conditions) | |
242 : conditions_(conditions) { | |
243 for (Collection::iterator i = conditions_.begin(); i != conditions_.end(); | |
244 ++i) { | |
245 URLMatcherConditionSet::ID trigger_id = | |
246 (*i)->url_matcher_condition_set_id(); | |
247 match_triggers_[trigger_id] = i->get(); | |
248 } | |
249 } | |
250 | |
251 WebRequestConditionCollection::~WebRequestConditionCollection() {} | |
252 | |
253 bool WebRequestConditionCollection::IsFulfilled( | |
254 URLMatcherConditionSet::ID url_match, | |
255 net::URLRequest* request) const { | |
256 MatchTriggers::const_iterator trigger = match_triggers_.find(url_match); | |
257 if (trigger == match_triggers_.end()) | |
Matt Perry
2012/03/26 20:21:20
Should this be an error (DCHECK)? The caller knows
battre
2012/03/26 20:38:10
Done.
| |
258 return false; | |
259 DCHECK_EQ(url_match, trigger->second->url_matcher_condition_set_id()); | |
260 if (trigger->second->IsFulfilled(request)) | |
Matt Perry
2012/03/26 20:21:20
nit: return trigger->second->IsFulfilled(request)
battre
2012/03/26 20:38:10
Done.
| |
261 return true; | |
262 return false; | |
263 } | |
264 | |
265 void WebRequestConditionCollection::AppendURLMatcherConditionSets( | |
266 std::vector<URLMatcherConditionSet>* condition_sets) const { | |
267 for (Collection::const_iterator i = conditions_.begin(); | |
268 i != conditions_.end(); ++i) { | |
269 condition_sets->push_back((*i)->url_matcher_condition_set()); | |
270 } | |
271 } | |
272 | |
273 // static | |
274 scoped_ptr<WebRequestConditionCollection> | |
275 WebRequestConditionCollection::Create( | |
276 URLMatcherConditionFactory* url_matcher_condition_factory, | |
277 const AnyVector& conditions, | |
278 std::string* error) { | |
279 std::vector<linked_ptr<WebRequestCondition> > result; | |
280 | |
281 for (AnyVector::const_iterator i = conditions.begin(); | |
282 i != conditions.end(); ++i) { | |
283 CHECK(i->get()); | |
284 scoped_ptr<WebRequestCondition> condition = | |
285 WebRequestCondition::Create(url_matcher_condition_factory, | |
286 (*i)->value(), error); | |
287 if (!error->empty()) | |
288 return scoped_ptr<WebRequestConditionCollection>(NULL); | |
289 result.push_back(make_linked_ptr(condition.release())); | |
290 } | |
291 | |
292 return scoped_ptr<WebRequestConditionCollection>( | |
293 new WebRequestConditionCollection(result)); | |
294 } | |
295 | |
296 } // namespace extensions | |
OLD | NEW |