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 // DeclarativeRule<>, DeclarativeConditionSet<>, and DeclarativeActionSet<> | |
6 // templates usable with multiple different declarativeFoo systems. These are | |
7 // templated on the Condition and Action types that define the behavior of a | |
8 // particular declarative event. | |
9 | |
10 #ifndef CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_DECLARATIVE_RULE_H__ | |
11 #define CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_DECLARATIVE_RULE_H__ | |
12 | |
13 #include <limits> | |
14 | |
15 #include "base/memory/linked_ptr.h" | |
16 #include "base/memory/scoped_vector.h" | |
17 #include "base/time.h" | |
18 #include "chrome/common/extensions/api/events.h" | |
19 #include "chrome/common/extensions/matcher/url_matcher.h" | |
20 | |
21 namespace base { | |
22 class Time; | |
23 } | |
24 | |
25 namespace extensions { | |
26 | |
27 // This class stores a set of conditions that may be part of a DeclarativeRule. | |
28 // If any condition is fulfilled, the Actions of the DeclarativeRule can be | |
29 // triggered. | |
30 template<typename ConditionT> | |
Matt Perry
2012/12/13 20:27:48
Did you consider defining Condition and Action int
Jeffrey Yasskin
2012/12/14 00:38:20
Yes. It would be more verbose to implement, and bo
Matt Perry
2012/12/14 19:49:32
Fair enough :)
| |
31 class DeclarativeConditionSet { | |
32 public: | |
33 typedef std::vector<linked_ptr<json_schema_compiler::any::Any> > AnyVector; | |
34 typedef std::vector<linked_ptr<ConditionT> > Conditions; | |
35 typedef typename Conditions::const_iterator const_iterator; | |
36 | |
37 explicit DeclarativeConditionSet(const Conditions& conditions); | |
38 | |
39 // Factory method that creates an WebRequestConditionSet according to the JSON | |
40 // array |conditions| passed by the extension API. | |
41 // Sets |error| and returns NULL in case of an error. | |
42 static scoped_ptr<DeclarativeConditionSet> Create( | |
43 URLMatcherConditionFactory* url_matcher_condition_factory, | |
44 const AnyVector& conditions, | |
45 std::string* error); | |
46 | |
47 const Conditions& conditions() const { | |
48 return conditions_; | |
49 } | |
50 | |
51 const_iterator begin() const { return conditions_.begin(); } | |
52 const_iterator end() const { return conditions_.end(); } | |
53 | |
54 // Returns whether any condition in the condition set is fulfilled | |
55 // based on a match |url_match| and the value of |request_data.request|. | |
56 // This function should be called for each URLMatcherConditionSet::ID | |
57 // that was found by the URLMatcher to ensure that the each trigger in | |
58 // |match_triggers_| is found. | |
59 bool IsFulfilled( | |
60 URLMatcherConditionSet::ID url_match, | |
61 const typename ConditionT::MatchData& match_data) const; | |
62 | |
63 // Appends the URLMatcherConditionSet from all conditions to |condition_sets|. | |
64 void GetURLMatcherConditionSets( | |
65 URLMatcherConditionSet::Vector* condition_sets) const; | |
66 | |
67 private: | |
68 Conditions conditions_; | |
69 | |
70 typedef std::map<URLMatcherConditionSet::ID, ConditionT*> | |
71 MatchTriggers; | |
72 MatchTriggers match_triggers_; | |
73 | |
74 DISALLOW_COPY_AND_ASSIGN(DeclarativeConditionSet); | |
75 }; | |
76 | |
77 // Immutable container for multiple actions. | |
78 // | |
79 // TODO(battre): As DeclarativeActionSet can become the single owner of all | |
80 // actions, we can optimize here by making some of them singletons (e.g. Cancel | |
81 // actions). | |
82 template<typename ActionT> | |
83 class DeclarativeActionSet { | |
84 public: | |
85 typedef std::vector<linked_ptr<json_schema_compiler::any::Any> > AnyVector; | |
86 typedef std::vector<linked_ptr<ActionT> > Actions; | |
87 | |
88 explicit DeclarativeActionSet(const Actions& actions); | |
89 | |
90 // Factory method that instantiates a DeclarativeActionSet according to | |
91 // |actions| which represents the array of actions received from the | |
92 // extension API. | |
93 static scoped_ptr<DeclarativeActionSet> Create(const AnyVector& actions, | |
94 std::string* error, | |
95 bool* bad_message); | |
96 | |
97 // Rules call this method when their conditions are fulfilled. | |
98 void Apply(const std::string& extension_id, | |
99 const base::Time& extension_install_time, | |
100 const typename ActionT::ApplyInfo& apply_info) const; | |
101 | |
102 // Rules call this method when they have stateful conditions, and those | |
103 // conditions stop being fulfilled. Rules with event-based conditions (e.g. a | |
104 // network request happened) will never Revert() an action. | |
105 void Revert(const std::string& extension_id, | |
106 const base::Time& extension_install_time, | |
107 const typename ActionT::ApplyInfo& apply_info) const; | |
108 | |
109 // Returns the minimum priority of rules that may be evaluated after | |
110 // this rule. Defaults to MIN_INT. | |
111 int GetMinimumPriority() const; | |
112 | |
113 const Actions& actions() const { return actions_; } | |
114 | |
115 private: | |
116 Actions actions_; | |
117 | |
118 DISALLOW_COPY_AND_ASSIGN(DeclarativeActionSet); | |
119 }; | |
120 | |
121 template<typename ConditionT, typename ActionT> | |
122 class DeclarativeRule { | |
123 public: | |
124 typedef std::string ExtensionId; | |
125 typedef std::string RuleId; | |
126 typedef std::pair<ExtensionId, RuleId> GlobalRuleId; | |
127 typedef int Priority; | |
128 typedef DeclarativeConditionSet<ConditionT> ConditionSet; | |
129 typedef DeclarativeActionSet<ActionT> ActionSet; | |
130 typedef extensions::api::events::Rule JsonRule; | |
131 | |
132 // Checks whether the set of |conditions| and |actions| are consistent. | |
133 // Returns true in case of consistency and MUST set |error| otherwise. | |
134 typedef bool (*ConsistencyChecker)(ConditionSet* conditions, | |
135 ActionSet* actions, | |
136 std::string* error); | |
137 | |
138 DeclarativeRule(const GlobalRuleId& id, | |
139 base::Time extension_installation_time, | |
140 scoped_ptr<ConditionSet> conditions, | |
141 scoped_ptr<ActionSet> actions, | |
142 Priority priority); | |
143 | |
144 // Calls check_consistency(conditions, actions, error) and returns | |
145 // NULL if it fails. Pass NULL if no consistency check is needed. | |
146 // If |error| is empty, the translation was successful and the | |
147 // returned rule is internally consistent. | |
148 static scoped_ptr<DeclarativeRule> Create( | |
149 URLMatcherConditionFactory* url_matcher_condition_factory, | |
150 const std::string& extension_id, | |
151 base::Time extension_installation_time, | |
152 linked_ptr<JsonRule> rule, | |
153 ConsistencyChecker check_consistency, | |
154 std::string* error); | |
155 | |
156 const GlobalRuleId& id() const { return id_; } | |
157 const std::string& extension_id() const { return id_.first; } | |
158 const ConditionSet& conditions() const { return *conditions_; } | |
159 const ActionSet& actions() const { return *actions_; } | |
160 Priority priority() const { return priority_; } | |
161 | |
162 // Creates all deltas resulting from the ActionSet and fills them into | |
163 // apply_info.deltas. This function should only be called when the conditions_ | |
164 // are fulfilled (from a semantic point of view; no harm is done if this | |
165 // function is called at other times for testing purposes). | |
166 // | |
167 // If |extension| is set, deltas are suppressed if the |extension| does not | |
168 // have have sufficient permissions to modify the request. The returned list | |
169 // may be empty in this case. | |
170 void Apply(const typename ActionT::ApplyInfo& apply_info) const; | |
171 | |
172 // Returns the minimum priority of rules that may be evaluated after | |
173 // this rule. Defaults to MAX_INT. Only valid if the conditions of this rule | |
174 // are fulfilled. | |
175 Priority GetMinimumPriority() const; | |
176 | |
177 private: | |
178 GlobalRuleId id_; | |
179 base::Time extension_installation_time_; // For precedences of rules. | |
180 scoped_ptr<ConditionSet> conditions_; | |
181 scoped_ptr<ActionSet> actions_; | |
182 Priority priority_; | |
183 | |
184 DISALLOW_COPY_AND_ASSIGN(DeclarativeRule); | |
185 }; | |
186 | |
187 // Implementation details below here. | |
188 | |
189 // | |
190 // DeclarativeConditionSet | |
191 // | |
192 | |
193 template<typename ConditionT> | |
194 DeclarativeConditionSet<ConditionT>::DeclarativeConditionSet( | |
195 const DeclarativeConditionSet::Conditions& conditions) | |
196 : conditions_(conditions) { | |
197 for (typename Conditions::iterator i = conditions_.begin(); | |
198 i != conditions_.end(); ++i) { | |
199 URLMatcherConditionSet::ID trigger_id = | |
200 (*i)->url_matcher_condition_set_id(); | |
201 match_triggers_[trigger_id] = i->get(); | |
202 } | |
203 } | |
204 | |
205 template<typename ConditionT> | |
206 bool DeclarativeConditionSet<ConditionT>::IsFulfilled( | |
207 URLMatcherConditionSet::ID url_match, | |
208 const typename ConditionT::MatchData& match_data) const { | |
209 typename MatchTriggers::const_iterator trigger = | |
210 match_triggers_.find(url_match); | |
211 DCHECK(trigger != match_triggers_.end()); | |
212 DCHECK_EQ(url_match, trigger->second->url_matcher_condition_set_id()); | |
213 return trigger->second->IsFulfilled(match_data); | |
214 } | |
215 | |
216 template<typename ConditionT> | |
217 void DeclarativeConditionSet<ConditionT>::GetURLMatcherConditionSets( | |
218 URLMatcherConditionSet::Vector* condition_sets) const { | |
219 for (typename Conditions::const_iterator i = conditions_.begin(); | |
220 i != conditions_.end(); ++i) { | |
221 condition_sets->push_back((*i)->url_matcher_condition_set()); | |
222 } | |
223 } | |
224 | |
225 // static | |
226 template<typename ConditionT> | |
227 scoped_ptr<DeclarativeConditionSet<ConditionT> > | |
228 DeclarativeConditionSet<ConditionT>::Create( | |
229 URLMatcherConditionFactory* url_matcher_condition_factory, | |
230 const AnyVector& conditions, | |
231 std::string* error) { | |
232 DeclarativeConditionSet::Conditions result; | |
233 | |
234 for (AnyVector::const_iterator i = conditions.begin(); | |
235 i != conditions.end(); ++i) { | |
236 CHECK(i->get()); | |
237 scoped_ptr<ConditionT> condition = | |
238 ConditionT::Create(url_matcher_condition_factory, | |
239 (*i)->value(), error); | |
240 if (!error->empty()) | |
241 return scoped_ptr<DeclarativeConditionSet>(NULL); | |
242 result.push_back(make_linked_ptr(condition.release())); | |
243 } | |
244 | |
245 return make_scoped_ptr(new DeclarativeConditionSet(result)); | |
246 } | |
247 | |
248 // | |
249 // DeclarativeActionSet | |
250 // | |
251 | |
252 template<typename ActionT> | |
253 DeclarativeActionSet<ActionT>::DeclarativeActionSet(const Actions& actions) | |
254 : actions_(actions) {} | |
255 | |
256 // static | |
257 template<typename ActionT> | |
258 scoped_ptr<DeclarativeActionSet<ActionT> > | |
259 DeclarativeActionSet<ActionT>::Create( | |
260 const AnyVector& actions, | |
261 std::string* error, | |
262 bool* bad_message) { | |
263 *error = ""; | |
264 *bad_message = false; | |
265 Actions result; | |
266 | |
267 for (AnyVector::const_iterator i = actions.begin(); | |
268 i != actions.end(); ++i) { | |
269 CHECK(i->get()); | |
270 scoped_ptr<ActionT> action = | |
271 ActionT::Create((*i)->value(), error, bad_message); | |
272 if (!error->empty() || *bad_message) | |
273 return scoped_ptr<DeclarativeActionSet>(NULL); | |
274 result.push_back(make_linked_ptr(action.release())); | |
275 } | |
276 | |
277 return scoped_ptr<DeclarativeActionSet>(new DeclarativeActionSet(result)); | |
278 } | |
279 | |
280 template<typename ActionT> | |
281 void DeclarativeActionSet<ActionT>::Apply( | |
282 const std::string& extension_id, | |
283 const base::Time& extension_install_time, | |
284 const typename ActionT::ApplyInfo& apply_info) const { | |
285 for (typename Actions::const_iterator i = actions_.begin(); | |
286 i != actions_.end(); ++i) | |
287 (*i)->Apply(extension_id, extension_install_time, apply_info); | |
288 } | |
289 | |
290 template<typename ActionT> | |
291 void DeclarativeActionSet<ActionT>::Revert( | |
292 const std::string& extension_id, | |
293 const base::Time& extension_install_time, | |
294 const typename ActionT::ApplyInfo& apply_info) const { | |
295 for (typename Actions::const_iterator i = actions_.begin(); | |
296 i != actions_.end(); ++i) | |
297 (*i)->Revert(extension_id, extension_install_time, apply_info); | |
298 } | |
299 | |
300 template<typename ActionT> | |
301 int DeclarativeActionSet<ActionT>::GetMinimumPriority() const { | |
302 int minimum_priority = std::numeric_limits<int>::min(); | |
303 for (typename Actions::const_iterator i = actions_.begin(); | |
304 i != actions_.end(); ++i) { | |
305 minimum_priority = std::max(minimum_priority, (*i)->GetMinimumPriority()); | |
306 } | |
307 return minimum_priority; | |
308 } | |
309 | |
310 // | |
311 // DeclarativeRule | |
312 // | |
313 | |
314 template<typename ConditionT, typename ActionT> | |
315 DeclarativeRule<ConditionT, ActionT>::DeclarativeRule( | |
316 const GlobalRuleId& id, | |
317 base::Time extension_installation_time, | |
318 scoped_ptr<ConditionSet> conditions, | |
319 scoped_ptr<ActionSet> actions, | |
320 Priority priority) | |
321 : id_(id), | |
322 extension_installation_time_(extension_installation_time), | |
323 conditions_(conditions.release()), | |
324 actions_(actions.release()), | |
325 priority_(priority) { | |
326 CHECK(conditions_.get()); | |
327 CHECK(actions_.get()); | |
328 } | |
329 | |
330 // static | |
331 template<typename ConditionT, typename ActionT> | |
332 scoped_ptr<DeclarativeRule<ConditionT, ActionT> > | |
333 DeclarativeRule<ConditionT, ActionT>::Create( | |
334 URLMatcherConditionFactory* url_matcher_condition_factory, | |
335 const std::string& extension_id, | |
336 base::Time extension_installation_time, | |
337 linked_ptr<JsonRule> rule, | |
338 ConsistencyChecker check_consistency, | |
339 std::string* error) { | |
340 scoped_ptr<DeclarativeRule> error_result; | |
341 | |
342 scoped_ptr<ConditionSet> conditions = ConditionSet::Create( | |
343 url_matcher_condition_factory, rule->conditions, error); | |
344 if (!error->empty()) | |
345 return error_result.Pass(); | |
346 CHECK(conditions.get()); | |
347 | |
348 bool bad_message = false; | |
349 scoped_ptr<ActionSet> actions = | |
350 ActionSet::Create(rule->actions, error, &bad_message); | |
351 if (bad_message) { | |
352 // TODO(battre) Export concept of bad_message to caller, the extension | |
353 // should be killed in case it is true. | |
354 *error = "An action of a rule set had an invalid " | |
355 "structure that should have been caught by the JSON validator."; | |
356 return error_result.Pass(); | |
357 } | |
358 if (!error->empty() || bad_message) | |
359 return error_result.Pass(); | |
360 CHECK(actions.get()); | |
361 | |
362 if (check_consistency && | |
363 !check_consistency(conditions.get(), actions.get(), error)) { | |
364 DCHECK(!error->empty()); | |
365 return error_result.Pass(); | |
366 } | |
367 | |
368 CHECK(rule->priority.get()); | |
369 int priority = *(rule->priority); | |
370 | |
371 GlobalRuleId rule_id(extension_id, *(rule->id)); | |
372 return scoped_ptr<DeclarativeRule>( | |
373 new DeclarativeRule(rule_id, extension_installation_time, | |
374 conditions.Pass(), actions.Pass(), priority)); | |
375 } | |
376 | |
377 template<typename ConditionT, typename ActionT> | |
378 void DeclarativeRule<ConditionT, ActionT>::Apply( | |
379 const typename ActionT::ApplyInfo& apply_info) const { | |
380 return actions_->Apply(extension_id(), | |
381 extension_installation_time_, | |
382 apply_info); | |
383 } | |
384 | |
385 template<typename ConditionT, typename ActionT> | |
386 int DeclarativeRule<ConditionT, ActionT>::GetMinimumPriority() const { | |
387 return actions_->GetMinimumPriority(); | |
388 } | |
389 | |
390 } // namespace extensions | |
391 | |
392 #endif // CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_DECLARATIVE_RULE_H__ | |
OLD | NEW |