// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include "extensions/common/event_filter.h" #include "components/url_matcher/url_matcher_factory.h" #include "ipc/ipc_message.h" using url_matcher::URLMatcher; using url_matcher::URLMatcherConditionSet; using url_matcher::URLMatcherFactory; namespace extensions { EventFilter::EventMatcherEntry::EventMatcherEntry( scoped_ptr event_matcher, URLMatcher* url_matcher, const URLMatcherConditionSet::Vector& condition_sets) : event_matcher_(event_matcher.Pass()), url_matcher_(url_matcher) { for (URLMatcherConditionSet::Vector::const_iterator it = condition_sets.begin(); it != condition_sets.end(); it++) condition_set_ids_.push_back((*it)->id()); url_matcher_->AddConditionSets(condition_sets); } EventFilter::EventMatcherEntry::~EventMatcherEntry() { url_matcher_->RemoveConditionSets(condition_set_ids_); } void EventFilter::EventMatcherEntry::DontRemoveConditionSetsInDestructor() { condition_set_ids_.clear(); } EventFilter::EventFilter() : next_id_(0), next_condition_set_id_(0) { } EventFilter::~EventFilter() { // Normally when an event matcher entry is removed from event_matchers_ it // will remove its condition sets from url_matcher_, but as url_matcher_ is // being destroyed anyway there is no need to do that step here. for (EventMatcherMultiMap::iterator it = event_matchers_.begin(); it != event_matchers_.end(); it++) { for (EventMatcherMap::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++) { it2->second->DontRemoveConditionSetsInDestructor(); } } } EventFilter::MatcherID EventFilter::AddEventMatcher(const std::string& event_name, scoped_ptr matcher) { MatcherID id = next_id_++; URLMatcherConditionSet::Vector condition_sets; if (!CreateConditionSets(id, matcher.get(), &condition_sets)) return -1; for (URLMatcherConditionSet::Vector::iterator it = condition_sets.begin(); it != condition_sets.end(); it++) { condition_set_id_to_event_matcher_id_.insert( std::make_pair((*it)->id(), id)); } id_to_event_name_[id] = event_name; event_matchers_[event_name][id] = linked_ptr( new EventMatcherEntry(matcher.Pass(), &url_matcher_, condition_sets)); return id; } EventMatcher* EventFilter::GetEventMatcher(MatcherID id) { DCHECK(id_to_event_name_.find(id) != id_to_event_name_.end()); const std::string& event_name = id_to_event_name_[id]; return event_matchers_[event_name][id]->event_matcher(); } const std::string& EventFilter::GetEventName(MatcherID id) { DCHECK(id_to_event_name_.find(id) != id_to_event_name_.end()); return id_to_event_name_[id]; } bool EventFilter::CreateConditionSets( MatcherID id, EventMatcher* matcher, URLMatcherConditionSet::Vector* condition_sets) { if (matcher->GetURLFilterCount() == 0) { // If there are no URL filters then we want to match all events, so create a // URLFilter from an empty dictionary. base::DictionaryValue empty_dict; return AddDictionaryAsConditionSet(&empty_dict, condition_sets); } for (int i = 0; i < matcher->GetURLFilterCount(); i++) { base::DictionaryValue* url_filter; if (!matcher->GetURLFilter(i, &url_filter)) return false; if (!AddDictionaryAsConditionSet(url_filter, condition_sets)) return false; } return true; } bool EventFilter::AddDictionaryAsConditionSet( base::DictionaryValue* url_filter, URLMatcherConditionSet::Vector* condition_sets) { std::string error; URLMatcherConditionSet::ID condition_set_id = next_condition_set_id_++; condition_sets->push_back(URLMatcherFactory::CreateFromURLFilterDictionary( url_matcher_.condition_factory(), url_filter, condition_set_id, &error)); if (!error.empty()) { LOG(ERROR) << "CreateFromURLFilterDictionary failed: " << error; url_matcher_.ClearUnusedConditionSets(); condition_sets->clear(); return false; } return true; } std::string EventFilter::RemoveEventMatcher(MatcherID id) { std::map::iterator it = id_to_event_name_.find(id); std::string event_name = it->second; // EventMatcherEntry's destructor causes the condition set ids to be removed // from url_matcher_. event_matchers_[event_name].erase(id); id_to_event_name_.erase(it); return event_name; } std::set EventFilter::MatchEvent( const std::string& event_name, const EventFilteringInfo& event_info, int routing_id) { std::set matchers; EventMatcherMultiMap::iterator it = event_matchers_.find(event_name); if (it == event_matchers_.end()) return matchers; EventMatcherMap& matcher_map = it->second; GURL url_to_match_against = event_info.has_url() ? event_info.url() : GURL(); std::set matching_condition_set_ids = url_matcher_.MatchURL(url_to_match_against); for (std::set::iterator it = matching_condition_set_ids.begin(); it != matching_condition_set_ids.end(); it++) { std::map::iterator matcher_id = condition_set_id_to_event_matcher_id_.find(*it); if (matcher_id == condition_set_id_to_event_matcher_id_.end()) { NOTREACHED() << "id not found in condition set map (" << (*it) << ")"; continue; } MatcherID id = matcher_id->second; EventMatcherMap::iterator matcher_entry = matcher_map.find(id); if (matcher_entry == matcher_map.end()) { // Matcher must be for a different event. continue; } const EventMatcher* event_matcher = matcher_entry->second->event_matcher(); // The context that installed the event listener should be the same context // as the one where the event listener is called. if ((routing_id != MSG_ROUTING_NONE) && (event_matcher->GetRoutingID() != routing_id)) { continue; } if (event_matcher->MatchNonURLCriteria(event_info)) { CHECK(!event_matcher->HasURLFilters() || event_info.has_url()); matchers.insert(id); } } return matchers; } int EventFilter::GetMatcherCountForEvent(const std::string& name) { EventMatcherMultiMap::const_iterator it = event_matchers_.find(name); if (it == event_matchers_.end()) return 0; return it->second.size(); } } // namespace extensions