event_filter.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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/common/event_filter.h"
6
7#include "extensions/common/matcher/url_matcher_factory.h"
8#include "ipc/ipc_message.h"
9
10namespace extensions {
11
12EventFilter::EventMatcherEntry::EventMatcherEntry(
13    scoped_ptr<EventMatcher> event_matcher,
14    URLMatcher* url_matcher,
15    const URLMatcherConditionSet::Vector& condition_sets)
16    : event_matcher_(event_matcher.Pass()),
17      url_matcher_(url_matcher) {
18  for (URLMatcherConditionSet::Vector::const_iterator it =
19       condition_sets.begin(); it != condition_sets.end(); it++)
20    condition_set_ids_.push_back((*it)->id());
21  url_matcher_->AddConditionSets(condition_sets);
22}
23
24EventFilter::EventMatcherEntry::~EventMatcherEntry() {
25  url_matcher_->RemoveConditionSets(condition_set_ids_);
26}
27
28void EventFilter::EventMatcherEntry::DontRemoveConditionSetsInDestructor() {
29  condition_set_ids_.clear();
30}
31
32EventFilter::EventFilter()
33    : next_id_(0),
34      next_condition_set_id_(0) {
35}
36
37EventFilter::~EventFilter() {
38  // Normally when an event matcher entry is removed from event_matchers_ it
39  // will remove its condition sets from url_matcher_, but as url_matcher_ is
40  // being destroyed anyway there is no need to do that step here.
41  for (EventMatcherMultiMap::iterator it = event_matchers_.begin();
42       it != event_matchers_.end(); it++) {
43    for (EventMatcherMap::iterator it2 = it->second.begin();
44         it2 != it->second.end(); it2++) {
45      it2->second->DontRemoveConditionSetsInDestructor();
46    }
47  }
48}
49
50EventFilter::MatcherID
51EventFilter::AddEventMatcher(const std::string& event_name,
52                             scoped_ptr<EventMatcher> matcher) {
53  MatcherID id = next_id_++;
54  URLMatcherConditionSet::Vector condition_sets;
55  if (!CreateConditionSets(id, matcher.get(), &condition_sets))
56    return -1;
57
58  for (URLMatcherConditionSet::Vector::iterator it = condition_sets.begin();
59       it != condition_sets.end(); it++) {
60    condition_set_id_to_event_matcher_id_.insert(
61        std::make_pair((*it)->id(), id));
62  }
63  id_to_event_name_[id] = event_name;
64  event_matchers_[event_name][id] = linked_ptr<EventMatcherEntry>(
65      new EventMatcherEntry(matcher.Pass(), &url_matcher_, condition_sets));
66  return id;
67}
68
69EventMatcher* EventFilter::GetEventMatcher(MatcherID id) {
70  DCHECK(id_to_event_name_.find(id) != id_to_event_name_.end());
71  const std::string& event_name = id_to_event_name_[id];
72  return event_matchers_[event_name][id]->event_matcher();
73}
74
75const std::string& EventFilter::GetEventName(MatcherID id) {
76  DCHECK(id_to_event_name_.find(id) != id_to_event_name_.end());
77  return id_to_event_name_[id];
78}
79
80bool EventFilter::CreateConditionSets(
81    MatcherID id,
82    EventMatcher* matcher,
83    URLMatcherConditionSet::Vector* condition_sets) {
84  if (matcher->GetURLFilterCount() == 0) {
85    // If there are no URL filters then we want to match all events, so create a
86    // URLFilter from an empty dictionary.
87    base::DictionaryValue empty_dict;
88    return AddDictionaryAsConditionSet(&empty_dict, condition_sets);
89  }
90  for (int i = 0; i < matcher->GetURLFilterCount(); i++) {
91    base::DictionaryValue* url_filter;
92    if (!matcher->GetURLFilter(i, &url_filter))
93      return false;
94    if (!AddDictionaryAsConditionSet(url_filter, condition_sets))
95      return false;
96  }
97  return true;
98}
99
100bool EventFilter::AddDictionaryAsConditionSet(
101    base::DictionaryValue* url_filter,
102    URLMatcherConditionSet::Vector* condition_sets) {
103  std::string error;
104  URLMatcherConditionSet::ID condition_set_id = next_condition_set_id_++;
105  condition_sets->push_back(URLMatcherFactory::CreateFromURLFilterDictionary(
106      url_matcher_.condition_factory(),
107      url_filter,
108      condition_set_id,
109      &error));
110  if (!error.empty()) {
111    LOG(ERROR) << "CreateFromURLFilterDictionary failed: " << error;
112    url_matcher_.ClearUnusedConditionSets();
113    condition_sets->clear();
114    return false;
115  }
116  return true;
117}
118
119std::string EventFilter::RemoveEventMatcher(MatcherID id) {
120  std::map<MatcherID, std::string>::iterator it = id_to_event_name_.find(id);
121  std::string event_name = it->second;
122  // EventMatcherEntry's destructor causes the condition set ids to be removed
123  // from url_matcher_.
124  event_matchers_[event_name].erase(id);
125  id_to_event_name_.erase(it);
126  return event_name;
127}
128
129std::set<EventFilter::MatcherID> EventFilter::MatchEvent(
130    const std::string& event_name, const EventFilteringInfo& event_info,
131    int routing_id) {
132  std::set<MatcherID> matchers;
133
134  EventMatcherMultiMap::iterator it = event_matchers_.find(event_name);
135  if (it == event_matchers_.end())
136    return matchers;
137
138  EventMatcherMap& matcher_map = it->second;
139  GURL url_to_match_against = event_info.has_url() ? event_info.url() : GURL();
140  std::set<URLMatcherConditionSet::ID> matching_condition_set_ids =
141      url_matcher_.MatchURL(url_to_match_against);
142  for (std::set<URLMatcherConditionSet::ID>::iterator it =
143       matching_condition_set_ids.begin();
144       it != matching_condition_set_ids.end(); it++) {
145    std::map<URLMatcherConditionSet::ID, MatcherID>::iterator matcher_id =
146        condition_set_id_to_event_matcher_id_.find(*it);
147    if (matcher_id == condition_set_id_to_event_matcher_id_.end()) {
148      NOTREACHED() << "id not found in condition set map (" << (*it) << ")";
149      continue;
150    }
151    MatcherID id = matcher_id->second;
152    EventMatcherMap::iterator matcher_entry = matcher_map.find(id);
153    if (matcher_entry == matcher_map.end()) {
154      // Matcher must be for a different event.
155      continue;
156    }
157    const EventMatcher* event_matcher = matcher_entry->second->event_matcher();
158    // The context that installed the event listener should be the same context
159    // as the one where the event listener is called.
160    if ((routing_id != MSG_ROUTING_NONE) &&
161        (event_matcher->GetRoutingID() != routing_id)) {
162      continue;
163    }
164    if (event_matcher->MatchNonURLCriteria(event_info)) {
165      CHECK(!event_matcher->HasURLFilters() || event_info.has_url());
166      matchers.insert(id);
167    }
168  }
169
170  return matchers;
171}
172
173int EventFilter::GetMatcherCountForEvent(const std::string& name) {
174  EventMatcherMultiMap::const_iterator it = event_matchers_.find(name);
175  if (it == event_matchers_.end())
176    return 0;
177
178  return it->second.size();
179}
180
181}  // namespace extensions
182