Index: extensions/browser/api/declarative/rules_registry.cc |
diff --git a/extensions/browser/api/declarative/rules_registry.cc b/extensions/browser/api/declarative/rules_registry.cc |
index dfd9c35260ace0ea706aa383d78d355c8177e57b..5ae4c776de443723851c42f43418f9e257771b2a 100644 |
--- a/extensions/browser/api/declarative/rules_registry.cc |
+++ b/extensions/browser/api/declarative/rules_registry.cc |
@@ -22,23 +22,28 @@ |
#include "extensions/browser/extension_system.h" |
#include "extensions/browser/state_store.h" |
#include "extensions/common/extension.h" |
+#include "extensions/common/manifest_constants.h" |
+ |
+namespace extensions { |
namespace { |
const char kSuccess[] = ""; |
const char kDuplicateRuleId[] = "Duplicate rule ID: %s"; |
+const char kErrorCannotRemoveManifestRules[] = |
+ "Rules declared in the 'event_rules' manifest field cannot be removed"; |
scoped_ptr<base::Value> RulesToValue( |
- const std::vector<linked_ptr<extensions::RulesRegistry::Rule> >& rules) { |
+ const std::vector<linked_ptr<RulesRegistry::Rule>>& rules) { |
scoped_ptr<base::ListValue> list(new base::ListValue()); |
for (size_t i = 0; i < rules.size(); ++i) |
list->Append(rules[i]->ToValue().release()); |
return list.Pass(); |
} |
-std::vector<linked_ptr<extensions::RulesRegistry::Rule> > RulesFromValue( |
+std::vector<linked_ptr<RulesRegistry::Rule>> RulesFromValue( |
const base::Value* value) { |
- std::vector<linked_ptr<extensions::RulesRegistry::Rule> > rules; |
+ std::vector<linked_ptr<RulesRegistry::Rule>> rules; |
const base::ListValue* list = NULL; |
if (!value || !value->GetAsList(&list)) |
@@ -49,15 +54,95 @@ std::vector<linked_ptr<extensions::RulesRegistry::Rule> > RulesFromValue( |
const base::DictionaryValue* dict = NULL; |
if (!list->GetDictionary(i, &dict)) |
continue; |
- linked_ptr<extensions::RulesRegistry::Rule> rule( |
- new extensions::RulesRegistry::Rule()); |
- if (extensions::RulesRegistry::Rule::Populate(*dict, rule.get())) |
+ linked_ptr<RulesRegistry::Rule> rule(new RulesRegistry::Rule()); |
+ if (RulesRegistry::Rule::Populate(*dict, rule.get())) |
rules.push_back(rule); |
} |
return rules; |
} |
+// Converts a rule defined in the manifest into a JSON internal format. The |
+// difference is that actions and conditions use a "type" key to define the |
+// type of rule/condition, while the internal format uses a "instanceType" key |
+// for this. This function walks through all the conditions and rules to swap |
+// the manifest key for the internal key. |
+bool ConvertManifestRule(const linked_ptr<RulesRegistry::Rule>& rule) { |
+ auto convert_list = [](std::vector<linked_ptr<base::Value>>& list) { |
+ for (const linked_ptr<base::Value>& value : list) { |
+ base::DictionaryValue* dictionary = nullptr; |
+ if (!value->GetAsDictionary(&dictionary)) |
+ return false; |
+ std::string type; |
+ if (!dictionary->GetString("type", &type)) |
+ return false; |
+ dictionary->Remove("type", nullptr); |
+ dictionary->SetString("instanceType", type); |
+ } |
+ return true; |
+ }; |
+ return convert_list(rule->actions) && convert_list(rule->conditions); |
+} |
+ |
+std::vector<linked_ptr<RulesRegistry::Rule>> RulesFromManifest( |
+ const base::Value* value, |
+ const std::string& event_name) { |
+ std::vector<linked_ptr<RulesRegistry::Rule>> rules; |
+ |
+ // The following is an example of how an event programmatic rule definition |
Mike Wittman
2015/06/05 23:15:58
You'll need to add something like this to the mani
|
+ // translates to a manifest definition. |
+ // |
+ // From javascript: |
+ // |
+ // chrome.declarativeContent.onPageChanged.addRules([{ |
+ // actions: [ |
+ // new chrome.declarativeContent.ShowPageAction() |
+ // ], |
+ // conditions: [ |
+ // new chrome.declarativeContent.PageStateMatcher({css: ["video"]}) |
+ // ] |
+ // }]); |
+ // |
+ // In manifest: |
+ // |
+ // "event_rules": [{ |
+ // "event" : "declarativeContent.onPageChanged", |
+ // "actions" : [{ |
+ // "type": "declarativeContent.ShowPageAction" |
+ // }], |
+ // "conditions" : [{ |
+ // "css": ["video"], |
+ // "type" : "declarativeContent.PageStateMatcher" |
+ // }] |
+ // }] |
+ // |
+ // The javascript objects get translated into JSON objects with a "type" |
+ // field to indicate the instance type. Instead of adding rules to a |
+ // specific event list, each rule has an "event" field to indicate which |
+ // event it applies to. |
+ // |
+ const base::ListValue* list = nullptr; |
+ if (!value->GetAsList(&list)) |
+ return rules; |
+ |
+ for (size_t i = 0; i < list->GetSize(); ++i) { |
+ const base::DictionaryValue* dict = nullptr; |
+ if (!list->GetDictionary(i, &dict)) |
+ continue; |
+ std::string event; |
+ if (!dict->GetString("event", &event) || event_name != event) { |
+ continue; |
+ } |
+ linked_ptr<RulesRegistry::Rule> rule(new RulesRegistry::Rule()); |
+ if (RulesRegistry::Rule::Populate(*dict, rule.get()) && |
+ ConvertManifestRule(rule)) { |
+ rules.push_back(rule); |
+ } |
+ } |
+ |
+ return rules; |
+} |
+ |
std::string ToId(int identifier) { |
return base::StringPrintf("_%d_", identifier); |
} |
@@ -65,8 +150,6 @@ std::string ToId(int identifier) { |
} // namespace |
-namespace extensions { |
- |
// RulesRegistry |
RulesRegistry::RulesRegistry(content::BrowserContext* browser_context, |
@@ -90,7 +173,8 @@ RulesRegistry::RulesRegistry(content::BrowserContext* browser_context, |
std::string RulesRegistry::AddRulesNoFill( |
const std::string& extension_id, |
- const std::vector<linked_ptr<Rule> >& rules) { |
+ const std::vector<linked_ptr<Rule>>& rules, |
+ RulesDictionary& out) { |
DCHECK_CURRENTLY_ON(owner_thread()); |
// Verify that all rule IDs are new. |
@@ -100,7 +184,8 @@ std::string RulesRegistry::AddRulesNoFill( |
// Every rule should have a priority assigned. |
DCHECK((*i)->priority); |
RulesDictionaryKey key(extension_id, rule_id); |
- if (rules_.find(key) != rules_.end()) |
+ if (rules_.find(key) != rules_.end() || |
+ manifest_rules_.find(key) != manifest_rules_.end()) |
return base::StringPrintf(kDuplicateRuleId, rule_id.c_str()); |
} |
@@ -114,7 +199,7 @@ std::string RulesRegistry::AddRulesNoFill( |
rules.begin(); i != rules.end(); ++i) { |
const RuleId& rule_id = *((*i)->id); |
RulesDictionaryKey key(extension_id, rule_id); |
- rules_[key] = *i; |
+ out[key] = *i; |
} |
MaybeProcessChangedRules(extension_id); |
@@ -123,7 +208,14 @@ std::string RulesRegistry::AddRulesNoFill( |
std::string RulesRegistry::AddRules( |
const std::string& extension_id, |
- const std::vector<linked_ptr<Rule> >& rules) { |
+ const std::vector<linked_ptr<Rule>>& rules) { |
+ return AddRulesInternal(extension_id, rules, rules_); |
+} |
+ |
+std::string RulesRegistry::AddRulesInternal( |
+ const std::string& extension_id, |
+ const std::vector<linked_ptr<Rule>>& rules, |
+ RulesDictionary& out) { |
DCHECK_CURRENTLY_ON(owner_thread()); |
std::string error = CheckAndFillInOptionalRules(extension_id, rules); |
@@ -131,7 +223,7 @@ std::string RulesRegistry::AddRules( |
return error; |
FillInOptionalPriorities(rules); |
- return AddRulesNoFill(extension_id, rules); |
+ return AddRulesNoFill(extension_id, rules, out); |
} |
std::string RulesRegistry::RemoveRules( |
@@ -139,6 +231,14 @@ std::string RulesRegistry::RemoveRules( |
const std::vector<std::string>& rule_identifiers) { |
DCHECK_CURRENTLY_ON(owner_thread()); |
+ // Check if any of the rules are non-removable. |
+ for (RuleId rule_id : rule_identifiers) { |
+ RulesDictionaryKey lookup_key(extension_id, rule_id); |
+ RulesDictionary::iterator itr = manifest_rules_.find(lookup_key); |
+ if (itr != manifest_rules_.end()) |
+ return kErrorCannotRemoveManifestRules; |
+ } |
+ |
std::string error = RemoveRulesImpl(extension_id, rule_identifiers); |
if (!error.empty()) |
@@ -157,13 +257,15 @@ std::string RulesRegistry::RemoveRules( |
} |
std::string RulesRegistry::RemoveAllRules(const std::string& extension_id) { |
- std::string result = RulesRegistry::RemoveAllRulesNoStoreUpdate(extension_id); |
+ std::string result = |
+ RulesRegistry::RemoveAllRulesNoStoreUpdate(extension_id, false); |
MaybeProcessChangedRules(extension_id); // Now update the prefs and store. |
return result; |
} |
std::string RulesRegistry::RemoveAllRulesNoStoreUpdate( |
- const std::string& extension_id) { |
+ const std::string& extension_id, |
+ bool uninstall) { |
DCHECK_CURRENTLY_ON(owner_thread()); |
std::string error = RemoveAllRulesImpl(extension_id); |
@@ -171,13 +273,17 @@ std::string RulesRegistry::RemoveAllRulesNoStoreUpdate( |
if (!error.empty()) |
return error; |
- for (RulesDictionary::const_iterator i = rules_.begin(); |
- i != rules_.end();) { |
- const RulesDictionaryKey& key = i->first; |
- ++i; |
- if (key.first == extension_id) |
- rules_.erase(key); |
- } |
+ auto remove_rules = [&extension_id](RulesDictionary& dictionary) { |
+ for (auto it = dictionary.begin(); it != dictionary.end();) { |
+ if (it->first.first == extension_id) |
+ dictionary.erase(it++); |
+ else |
+ ++it; |
+ } |
+ }; |
+ remove_rules(rules_); |
+ if (uninstall) |
+ remove_rules(manifest_rules_); |
RemoveAllUsedRuleIdentifiers(extension_id); |
return kSuccess; |
@@ -188,45 +294,61 @@ void RulesRegistry::GetRules(const std::string& extension_id, |
std::vector<linked_ptr<Rule> >* out) { |
DCHECK_CURRENTLY_ON(owner_thread()); |
- for (std::vector<std::string>::const_iterator i = rule_identifiers.begin(); |
- i != rule_identifiers.end(); ++i) { |
- RulesDictionaryKey lookup_key(extension_id, *i); |
+ for (const auto& i : rule_identifiers) { |
+ RulesDictionaryKey lookup_key(extension_id, i); |
RulesDictionary::iterator entry = rules_.find(lookup_key); |
+ if (entry == rules_.end()) |
+ entry = manifest_rules_.find(lookup_key); |
if (entry != rules_.end()) |
out->push_back(entry->second); |
} |
} |
+void RulesRegistry::GetRules( |
+ const std::string& extension_id, |
+ RulesDictionary& rules, |
+ std::vector<linked_ptr<RulesRegistry::Rule>>* out) { |
+ for (const auto& i : rules) { |
+ const RulesDictionaryKey& key = i.first; |
+ if (key.first == extension_id) |
+ out->push_back(i.second); |
+ } |
+} |
+ |
void RulesRegistry::GetAllRules(const std::string& extension_id, |
std::vector<linked_ptr<Rule> >* out) { |
DCHECK_CURRENTLY_ON(owner_thread()); |
- for (RulesDictionary::const_iterator i = rules_.begin(); |
- i != rules_.end(); ++i) { |
- const RulesDictionaryKey& key = i->first; |
- if (key.first == extension_id) |
- out->push_back(i->second); |
- } |
+ GetRules(extension_id, manifest_rules_, out); |
+ GetRules(extension_id, rules_, out); |
} |
-void RulesRegistry::OnExtensionUnloaded(const std::string& extension_id) { |
+void RulesRegistry::OnExtensionUnloaded(const Extension* extension) { |
DCHECK_CURRENTLY_ON(owner_thread()); |
- std::string error = RemoveAllRulesImpl(extension_id); |
+ std::string error = RemoveAllRulesImpl(extension->id()); |
if (!error.empty()) |
LOG(ERROR) << error; |
} |
-void RulesRegistry::OnExtensionUninstalled(const std::string& extension_id) { |
+void RulesRegistry::OnExtensionUninstalled(const Extension* extension) { |
DCHECK_CURRENTLY_ON(owner_thread()); |
- std::string error = RemoveAllRulesNoStoreUpdate(extension_id); |
+ std::string error = RemoveAllRulesNoStoreUpdate(extension->id(), true); |
if (!error.empty()) |
LOG(ERROR) << error; |
} |
-void RulesRegistry::OnExtensionLoaded(const std::string& extension_id) { |
+void RulesRegistry::OnExtensionLoaded(const Extension* extension) { |
DCHECK_CURRENTLY_ON(owner_thread()); |
- std::vector<linked_ptr<Rule> > rules; |
- GetAllRules(extension_id, &rules); |
- std::string error = AddRulesImpl(extension_id, rules); |
+ std::vector<linked_ptr<Rule>> rules; |
+ GetAllRules(extension->id(), &rules); |
+ const base::ListValue* value = NULL; |
+ if (extension->manifest()->GetList(manifest_keys::kEventRules, &value)) { |
+ std::string error = |
+ AddRulesInternal(extension->id(), RulesFromManifest(value, event_name_), |
+ manifest_rules_); |
+ if (!error.empty()) |
+ LOG(ERROR) << error; |
+ } |
+ std::string error = AddRulesImpl(extension->id(), rules); |
if (!error.empty()) |
LOG(ERROR) << error; |
} |
@@ -249,7 +371,7 @@ void RulesRegistry::DeserializeAndAddRules( |
scoped_ptr<base::Value> rules) { |
DCHECK_CURRENTLY_ON(owner_thread()); |
- AddRulesNoFill(extension_id, RulesFromValue(rules.get())); |
+ AddRulesNoFill(extension_id, RulesFromValue(rules.get()), rules_); |
} |
RulesRegistry::~RulesRegistry() { |
@@ -273,14 +395,11 @@ void RulesRegistry::ProcessChangedRules(const std::string& extension_id) { |
process_changed_rules_requested_[extension_id] = NOT_SCHEDULED_FOR_PROCESSING; |
std::vector<linked_ptr<Rule> > new_rules; |
- GetAllRules(extension_id, &new_rules); |
+ GetRules(extension_id, rules_, &new_rules); |
content::BrowserThread::PostTask( |
- content::BrowserThread::UI, |
- FROM_HERE, |
- base::Bind(&RulesCacheDelegate::WriteToStorage, |
- cache_delegate_, |
- extension_id, |
- base::Passed(RulesToValue(new_rules)))); |
+ content::BrowserThread::UI, FROM_HERE, |
+ base::Bind(&RulesCacheDelegate::WriteToStorage, cache_delegate_, |
+ extension_id, base::Passed(RulesToValue(new_rules)))); |
} |
void RulesRegistry::MaybeProcessChangedRules(const std::string& extension_id) { |