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/initializing_rules_registry.h" 6 7 #include "base/logging.h" 8 #include "base/strings/stringprintf.h" 9 #include "base/values.h" 10 11 namespace { 12 std::string ToId(int identifier) { 13 return base::StringPrintf("_%d_", identifier); 14 } 15 } // namespace 16 17 namespace extensions { 18 19 InitializingRulesRegistry::InitializingRulesRegistry( 20 scoped_refptr<RulesRegistry> delegate) 21 : RulesRegistry(delegate->owner_thread(), delegate->event_name()), 22 delegate_(delegate), 23 last_generated_rule_identifier_id_(0) {} 24 25 std::string InitializingRulesRegistry::AddRules( 26 const std::string& extension_id, 27 const std::vector<linked_ptr<RulesRegistry::Rule> >& rules) { 28 std::string error = CheckAndFillInOptionalRules(extension_id, rules); 29 if (!error.empty()) 30 return error; 31 FillInOptionalPriorities(rules); 32 return delegate_->AddRules(extension_id, rules); 33 } 34 35 std::string InitializingRulesRegistry::RemoveRules( 36 const std::string& extension_id, 37 const std::vector<std::string>& rule_identifiers) { 38 std::string error = delegate_->RemoveRules(extension_id, rule_identifiers); 39 if (!error.empty()) 40 return error; 41 RemoveUsedRuleIdentifiers(extension_id, rule_identifiers); 42 return std::string(); 43 } 44 45 std::string InitializingRulesRegistry::RemoveAllRules( 46 const std::string& extension_id) { 47 std::string error = delegate_->RemoveAllRules(extension_id); 48 if (!error.empty()) 49 return error; 50 RemoveAllUsedRuleIdentifiers(extension_id); 51 return std::string(); 52 } 53 54 std::string InitializingRulesRegistry::GetRules( 55 const std::string& extension_id, 56 const std::vector<std::string>& rule_identifiers, 57 std::vector<linked_ptr<RulesRegistry::Rule> >* out) { 58 return delegate_->GetRules(extension_id, rule_identifiers, out); 59 } 60 61 std::string InitializingRulesRegistry::GetAllRules( 62 const std::string& extension_id, 63 std::vector<linked_ptr<RulesRegistry::Rule> >* out) { 64 return delegate_->GetAllRules(extension_id, out); 65 } 66 67 void InitializingRulesRegistry::OnExtensionUnloaded( 68 const std::string& extension_id) { 69 delegate_->OnExtensionUnloaded(extension_id); 70 used_rule_identifiers_.erase(extension_id); 71 } 72 73 size_t 74 InitializingRulesRegistry::GetNumberOfUsedRuleIdentifiersForTesting() const { 75 size_t entry_count = 0u; 76 for (RuleIdentifiersMap::const_iterator extension = 77 used_rule_identifiers_.begin(); 78 extension != used_rule_identifiers_.end(); 79 ++extension) { 80 // Each extension is counted as 1 just for being there. Otherwise we miss 81 // keys with empty values. 82 entry_count += 1u + extension->second.size(); 83 } 84 return entry_count; 85 } 86 87 InitializingRulesRegistry::~InitializingRulesRegistry() {} 88 89 bool InitializingRulesRegistry::IsUniqueId( 90 const std::string& extension_id, 91 const std::string& rule_id) const { 92 RuleIdentifiersMap::const_iterator identifiers = 93 used_rule_identifiers_.find(extension_id); 94 if (identifiers == used_rule_identifiers_.end()) 95 return true; 96 return identifiers->second.find(rule_id) == identifiers->second.end(); 97 } 98 99 std::string InitializingRulesRegistry::GenerateUniqueId( 100 const std::string& extension_id) { 101 while (!IsUniqueId(extension_id, ToId(last_generated_rule_identifier_id_))) 102 ++last_generated_rule_identifier_id_; 103 return ToId(last_generated_rule_identifier_id_); 104 } 105 106 std::string InitializingRulesRegistry::CheckAndFillInOptionalRules( 107 const std::string& extension_id, 108 const std::vector<linked_ptr<RulesRegistry::Rule> >& rules) { 109 // IDs we have inserted, in case we need to rollback this operation. 110 std::vector<std::string> rollback_log; 111 112 // First we insert all rules with existing identifier, so that generated 113 // identifiers cannot collide with identifiers passed by the caller. 114 for (std::vector<linked_ptr<RulesRegistry::Rule> >::const_iterator i = 115 rules.begin(); i != rules.end(); ++i) { 116 RulesRegistry::Rule* rule = i->get(); 117 if (rule->id.get()) { 118 std::string id = *(rule->id); 119 if (!IsUniqueId(extension_id, id)) { 120 RemoveUsedRuleIdentifiers(extension_id, rollback_log); 121 return "Id " + id + " was used multiple times."; 122 } 123 used_rule_identifiers_[extension_id].insert(id); 124 } 125 } 126 // Now we generate IDs in case they were not specificed in the rules. This 127 // cannot fail so we do not need to keep track of a rollback log. 128 for (std::vector<linked_ptr<RulesRegistry::Rule> >::const_iterator i = 129 rules.begin(); i != rules.end(); ++i) { 130 RulesRegistry::Rule* rule = i->get(); 131 if (!rule->id.get()) { 132 rule->id.reset(new std::string(GenerateUniqueId(extension_id))); 133 used_rule_identifiers_[extension_id].insert(*(rule->id)); 134 } 135 } 136 return std::string(); 137 } 138 139 void InitializingRulesRegistry::FillInOptionalPriorities( 140 const std::vector<linked_ptr<RulesRegistry::Rule> >& rules) { 141 std::vector<linked_ptr<RulesRegistry::Rule> >::const_iterator i; 142 for (i = rules.begin(); i != rules.end(); ++i) { 143 if (!(*i)->priority.get()) 144 (*i)->priority.reset(new int(DEFAULT_PRIORITY)); 145 } 146 } 147 148 void InitializingRulesRegistry::RemoveUsedRuleIdentifiers( 149 const std::string& extension_id, 150 const std::vector<std::string>& identifiers) { 151 std::vector<std::string>::const_iterator i; 152 for (i = identifiers.begin(); i != identifiers.end(); ++i) 153 used_rule_identifiers_[extension_id].erase(*i); 154 } 155 156 void InitializingRulesRegistry::RemoveAllUsedRuleIdentifiers( 157 const std::string& extension_id) { 158 used_rule_identifiers_.erase(extension_id); 159 } 160 161 } // namespace extensions 162