Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / extensions / browser / api / declarative / rules_registry.cc
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 "extensions/browser/api/declarative/rules_registry.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/metrics/histogram.h"
13 #include "base/stl_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/time/time.h"
16 #include "base/values.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/notification_details.h"
19 #include "content/public/browser/notification_source.h"
20 #include "extensions/browser/api/declarative/rules_cache_delegate.h"
21 #include "extensions/browser/extension_prefs.h"
22 #include "extensions/browser/extension_system.h"
23 #include "extensions/browser/state_store.h"
24 #include "extensions/common/extension.h"
25
26 namespace {
27
28 const char kSuccess[] = "";
29 const char kDuplicateRuleId[] = "Duplicate rule ID: %s";
30
31 scoped_ptr<base::Value> RulesToValue(
32     const std::vector<linked_ptr<extensions::RulesRegistry::Rule> >& rules) {
33   scoped_ptr<base::ListValue> list(new base::ListValue());
34   for (size_t i = 0; i < rules.size(); ++i)
35     list->Append(rules[i]->ToValue().release());
36   return list.PassAs<base::Value>();
37 }
38
39 std::vector<linked_ptr<extensions::RulesRegistry::Rule> > RulesFromValue(
40     const base::Value* value) {
41   std::vector<linked_ptr<extensions::RulesRegistry::Rule> > rules;
42
43   const base::ListValue* list = NULL;
44   if (!value || !value->GetAsList(&list))
45     return rules;
46
47   rules.reserve(list->GetSize());
48   for (size_t i = 0; i < list->GetSize(); ++i) {
49     const base::DictionaryValue* dict = NULL;
50     if (!list->GetDictionary(i, &dict))
51       continue;
52     linked_ptr<extensions::RulesRegistry::Rule> rule(
53         new extensions::RulesRegistry::Rule());
54     if (extensions::RulesRegistry::Rule::Populate(*dict, rule.get()))
55       rules.push_back(rule);
56   }
57
58   return rules;
59 }
60
61 std::string ToId(int identifier) {
62   return base::StringPrintf("_%d_", identifier);
63 }
64
65 }  // namespace
66
67
68 namespace extensions {
69
70 // RulesRegistry
71
72 RulesRegistry::RulesRegistry(content::BrowserContext* browser_context,
73                              const std::string& event_name,
74                              content::BrowserThread::ID owner_thread,
75                              RulesCacheDelegate* cache_delegate,
76                              const WebViewKey& webview_key)
77     : browser_context_(browser_context),
78       owner_thread_(owner_thread),
79       event_name_(event_name),
80       webview_key_(webview_key),
81       ready_(/*signaled=*/!cache_delegate),  // Immediately ready if no cache
82                                              // delegate to wait for.
83       weak_ptr_factory_(browser_context_ ? this : NULL),
84       last_generated_rule_identifier_id_(0) {
85   if (cache_delegate) {
86     cache_delegate_ = cache_delegate->GetWeakPtr();
87     cache_delegate->Init(this);
88   }
89 }
90
91 std::string RulesRegistry::AddRulesNoFill(
92     const std::string& extension_id,
93     const std::vector<linked_ptr<Rule> >& rules) {
94   DCHECK_CURRENTLY_ON(owner_thread());
95
96   // Verify that all rule IDs are new.
97   for (std::vector<linked_ptr<Rule> >::const_iterator i =
98       rules.begin(); i != rules.end(); ++i) {
99     const RuleId& rule_id = *((*i)->id);
100     // Every rule should have a priority assigned.
101     DCHECK((*i)->priority);
102     RulesDictionaryKey key(extension_id, rule_id);
103     if (rules_.find(key) != rules_.end())
104       return base::StringPrintf(kDuplicateRuleId, rule_id.c_str());
105   }
106
107   std::string error = AddRulesImpl(extension_id, rules);
108
109   if (!error.empty())
110     return error;
111
112   // Commit all rules into |rules_| on success.
113   for (std::vector<linked_ptr<Rule> >::const_iterator i =
114       rules.begin(); i != rules.end(); ++i) {
115     const RuleId& rule_id = *((*i)->id);
116     RulesDictionaryKey key(extension_id, rule_id);
117     rules_[key] = *i;
118   }
119
120   MaybeProcessChangedRules(extension_id);
121   return kSuccess;
122 }
123
124 std::string RulesRegistry::AddRules(
125     const std::string& extension_id,
126     const std::vector<linked_ptr<Rule> >& rules) {
127   DCHECK_CURRENTLY_ON(owner_thread());
128
129   std::string error = CheckAndFillInOptionalRules(extension_id, rules);
130   if (!error.empty())
131     return error;
132   FillInOptionalPriorities(rules);
133
134   return AddRulesNoFill(extension_id, rules);
135 }
136
137 std::string RulesRegistry::RemoveRules(
138     const std::string& extension_id,
139     const std::vector<std::string>& rule_identifiers) {
140   DCHECK_CURRENTLY_ON(owner_thread());
141
142   std::string error = RemoveRulesImpl(extension_id, rule_identifiers);
143
144   if (!error.empty())
145     return error;
146
147   for (std::vector<std::string>::const_iterator i = rule_identifiers.begin();
148        i != rule_identifiers.end();
149        ++i) {
150     RulesDictionaryKey lookup_key(extension_id, *i);
151     rules_.erase(lookup_key);
152   }
153
154   MaybeProcessChangedRules(extension_id);
155   RemoveUsedRuleIdentifiers(extension_id, rule_identifiers);
156   return kSuccess;
157 }
158
159 std::string RulesRegistry::RemoveAllRules(const std::string& extension_id) {
160   std::string result = RulesRegistry::RemoveAllRulesNoStoreUpdate(extension_id);
161   MaybeProcessChangedRules(extension_id);  // Now update the prefs and store.
162   return result;
163 }
164
165 std::string RulesRegistry::RemoveAllRulesNoStoreUpdate(
166     const std::string& extension_id) {
167   DCHECK_CURRENTLY_ON(owner_thread());
168
169   std::string error = RemoveAllRulesImpl(extension_id);
170
171   if (!error.empty())
172     return error;
173
174   for (RulesDictionary::const_iterator i = rules_.begin();
175       i != rules_.end();) {
176     const RulesDictionaryKey& key = i->first;
177     ++i;
178     if (key.first == extension_id)
179       rules_.erase(key);
180   }
181
182   RemoveAllUsedRuleIdentifiers(extension_id);
183   return kSuccess;
184 }
185
186 void RulesRegistry::GetRules(const std::string& extension_id,
187                              const std::vector<std::string>& rule_identifiers,
188                              std::vector<linked_ptr<Rule> >* out) {
189   DCHECK_CURRENTLY_ON(owner_thread());
190
191   for (std::vector<std::string>::const_iterator i = rule_identifiers.begin();
192       i != rule_identifiers.end(); ++i) {
193     RulesDictionaryKey lookup_key(extension_id, *i);
194     RulesDictionary::iterator entry = rules_.find(lookup_key);
195     if (entry != rules_.end())
196       out->push_back(entry->second);
197   }
198 }
199
200 void RulesRegistry::GetAllRules(const std::string& extension_id,
201                                 std::vector<linked_ptr<Rule> >* out) {
202   DCHECK_CURRENTLY_ON(owner_thread());
203
204   for (RulesDictionary::const_iterator i = rules_.begin();
205       i != rules_.end(); ++i) {
206     const RulesDictionaryKey& key = i->first;
207     if (key.first == extension_id)
208       out->push_back(i->second);
209   }
210 }
211
212 void RulesRegistry::OnExtensionUnloaded(const std::string& extension_id) {
213   DCHECK_CURRENTLY_ON(owner_thread());
214   std::string error = RemoveAllRulesImpl(extension_id);
215   if (!error.empty())
216     LOG(ERROR) << error;
217 }
218
219 void RulesRegistry::OnExtensionUninstalled(const std::string& extension_id) {
220   DCHECK_CURRENTLY_ON(owner_thread());
221   std::string error = RemoveAllRulesNoStoreUpdate(extension_id);
222   if (!error.empty())
223     LOG(ERROR) << error;
224 }
225
226 void RulesRegistry::OnExtensionLoaded(const std::string& extension_id) {
227   DCHECK_CURRENTLY_ON(owner_thread());
228   std::vector<linked_ptr<Rule> > rules;
229   GetAllRules(extension_id, &rules);
230   std::string error = AddRulesImpl(extension_id, rules);
231   if (!error.empty())
232     LOG(ERROR) << error;
233 }
234
235 size_t RulesRegistry::GetNumberOfUsedRuleIdentifiersForTesting() const {
236   size_t entry_count = 0u;
237   for (RuleIdentifiersMap::const_iterator extension =
238            used_rule_identifiers_.begin();
239        extension != used_rule_identifiers_.end();
240        ++extension) {
241     // Each extension is counted as 1 just for being there. Otherwise we miss
242     // keys with empty values.
243     entry_count += 1u + extension->second.size();
244   }
245   return entry_count;
246 }
247
248 void RulesRegistry::DeserializeAndAddRules(
249     const std::string& extension_id,
250     scoped_ptr<base::Value> rules) {
251   DCHECK_CURRENTLY_ON(owner_thread());
252
253   AddRulesNoFill(extension_id, RulesFromValue(rules.get()));
254 }
255
256 RulesRegistry::~RulesRegistry() {
257 }
258
259 void RulesRegistry::MarkReady(base::Time storage_init_time) {
260   DCHECK_CURRENTLY_ON(owner_thread());
261
262   if (!storage_init_time.is_null()) {
263     UMA_HISTOGRAM_TIMES("Extensions.DeclarativeRulesStorageInitialization",
264                         base::Time::Now() - storage_init_time);
265   }
266
267   ready_.Signal();
268 }
269
270 void RulesRegistry::ProcessChangedRules(const std::string& extension_id) {
271   DCHECK_CURRENTLY_ON(owner_thread());
272
273   DCHECK(ContainsKey(process_changed_rules_requested_, extension_id));
274   process_changed_rules_requested_[extension_id] = NOT_SCHEDULED_FOR_PROCESSING;
275
276   std::vector<linked_ptr<Rule> > new_rules;
277   GetAllRules(extension_id, &new_rules);
278   content::BrowserThread::PostTask(
279       content::BrowserThread::UI,
280       FROM_HERE,
281       base::Bind(&RulesCacheDelegate::WriteToStorage,
282                  cache_delegate_,
283                  extension_id,
284                  base::Passed(RulesToValue(new_rules))));
285 }
286
287 void RulesRegistry::MaybeProcessChangedRules(const std::string& extension_id) {
288   // Read and initialize |process_changed_rules_requested_[extension_id]| if
289   // necessary. (Note that the insertion below will not overwrite
290   // |process_changed_rules_requested_[extension_id]| if that already exists.
291   std::pair<ProcessStateMap::iterator, bool> insertion =
292       process_changed_rules_requested_.insert(std::make_pair(
293           extension_id,
294           browser_context_ ? NOT_SCHEDULED_FOR_PROCESSING : NEVER_PROCESS));
295   if (insertion.first->second != NOT_SCHEDULED_FOR_PROCESSING)
296     return;
297
298   process_changed_rules_requested_[extension_id] = SCHEDULED_FOR_PROCESSING;
299   ready_.Post(FROM_HERE,
300               base::Bind(&RulesRegistry::ProcessChangedRules,
301                          weak_ptr_factory_.GetWeakPtr(),
302                          extension_id));
303 }
304
305 bool RulesRegistry::IsUniqueId(const std::string& extension_id,
306                                const std::string& rule_id) const {
307   RuleIdentifiersMap::const_iterator identifiers =
308       used_rule_identifiers_.find(extension_id);
309   if (identifiers == used_rule_identifiers_.end())
310     return true;
311   return identifiers->second.find(rule_id) == identifiers->second.end();
312 }
313
314 std::string RulesRegistry::GenerateUniqueId(const std::string& extension_id) {
315   while (!IsUniqueId(extension_id, ToId(last_generated_rule_identifier_id_)))
316     ++last_generated_rule_identifier_id_;
317   return ToId(last_generated_rule_identifier_id_);
318 }
319
320 std::string RulesRegistry::CheckAndFillInOptionalRules(
321     const std::string& extension_id,
322     const std::vector<linked_ptr<Rule> >& rules) {
323   // IDs we have inserted, in case we need to rollback this operation.
324   std::vector<std::string> rollback_log;
325
326   // First we insert all rules with existing identifier, so that generated
327   // identifiers cannot collide with identifiers passed by the caller.
328   for (std::vector<linked_ptr<Rule> >::const_iterator i = rules.begin();
329        i != rules.end();
330        ++i) {
331     Rule* rule = i->get();
332     if (rule->id.get()) {
333       std::string id = *(rule->id);
334       if (!IsUniqueId(extension_id, id)) {
335         RemoveUsedRuleIdentifiers(extension_id, rollback_log);
336         return "Id " + id + " was used multiple times.";
337       }
338       used_rule_identifiers_[extension_id].insert(id);
339     }
340   }
341   // Now we generate IDs in case they were not specified in the rules. This
342   // cannot fail so we do not need to keep track of a rollback log.
343   for (std::vector<linked_ptr<Rule> >::const_iterator i = rules.begin();
344        i != rules.end();
345        ++i) {
346     Rule* rule = i->get();
347     if (!rule->id.get()) {
348       rule->id.reset(new std::string(GenerateUniqueId(extension_id)));
349       used_rule_identifiers_[extension_id].insert(*(rule->id));
350     }
351   }
352   return std::string();
353 }
354
355 void RulesRegistry::FillInOptionalPriorities(
356     const std::vector<linked_ptr<Rule> >& rules) {
357   std::vector<linked_ptr<Rule> >::const_iterator i;
358   for (i = rules.begin(); i != rules.end(); ++i) {
359     if (!(*i)->priority.get())
360       (*i)->priority.reset(new int(DEFAULT_PRIORITY));
361   }
362 }
363
364 void RulesRegistry::RemoveUsedRuleIdentifiers(
365     const std::string& extension_id,
366     const std::vector<std::string>& identifiers) {
367   std::vector<std::string>::const_iterator i;
368   for (i = identifiers.begin(); i != identifiers.end(); ++i)
369     used_rule_identifiers_[extension_id].erase(*i);
370 }
371
372 void RulesRegistry::RemoveAllUsedRuleIdentifiers(
373     const std::string& extension_id) {
374   used_rule_identifiers_.erase(extension_id);
375 }
376
377 }  // namespace extensions