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 378