• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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/event_listener_map.h"
6 
7 #include "base/values.h"
8 #include "content/public/browser/render_process_host.h"
9 #include "extensions/browser/event_router.h"
10 #include "ipc/ipc_message.h"
11 #include "url/gurl.h"
12 
13 using base::DictionaryValue;
14 
15 namespace extensions {
16 
17 typedef EventFilter::MatcherID MatcherID;
18 
19 // static
ForExtension(const std::string & event_name,const std::string & extension_id,content::RenderProcessHost * process,scoped_ptr<base::DictionaryValue> filter)20 scoped_ptr<EventListener> EventListener::ForExtension(
21     const std::string& event_name,
22     const std::string& extension_id,
23     content::RenderProcessHost* process,
24     scoped_ptr<base::DictionaryValue> filter) {
25   return make_scoped_ptr(new EventListener(
26       event_name, extension_id, GURL(), process, filter.Pass()));
27 }
28 
29 // static
ForURL(const std::string & event_name,const GURL & listener_url,content::RenderProcessHost * process,scoped_ptr<base::DictionaryValue> filter)30 scoped_ptr<EventListener> EventListener::ForURL(
31     const std::string& event_name,
32     const GURL& listener_url,
33     content::RenderProcessHost* process,
34     scoped_ptr<base::DictionaryValue> filter) {
35   return make_scoped_ptr(
36       new EventListener(event_name, "", listener_url, process, filter.Pass()));
37 }
38 
~EventListener()39 EventListener::~EventListener() {}
40 
Equals(const EventListener * other) const41 bool EventListener::Equals(const EventListener* other) const {
42   // We don't check matcher_id equality because we want a listener with a
43   // filter that hasn't been added to EventFilter to match one that is
44   // equivalent but has.
45   return event_name_ == other->event_name_ &&
46          extension_id_ == other->extension_id_ &&
47          listener_url_ == other->listener_url_ && process_ == other->process_ &&
48          ((!!filter_.get()) == (!!other->filter_.get())) &&
49          (!filter_.get() || filter_->Equals(other->filter_.get()));
50 }
51 
Copy() const52 scoped_ptr<EventListener> EventListener::Copy() const {
53   scoped_ptr<DictionaryValue> filter_copy;
54   if (filter_)
55     filter_copy.reset(filter_->DeepCopy());
56   return scoped_ptr<EventListener>(new EventListener(
57       event_name_, extension_id_, listener_url_, process_, filter_copy.Pass()));
58 }
59 
IsLazy() const60 bool EventListener::IsLazy() const {
61   return !process_;
62 }
63 
MakeLazy()64 void EventListener::MakeLazy() {
65   process_ = NULL;
66 }
67 
GetBrowserContext() const68 content::BrowserContext* EventListener::GetBrowserContext() const {
69   return process_ ? process_->GetBrowserContext() : NULL;
70 }
71 
EventListener(const std::string & event_name,const std::string & extension_id,const GURL & listener_url,content::RenderProcessHost * process,scoped_ptr<DictionaryValue> filter)72 EventListener::EventListener(const std::string& event_name,
73                              const std::string& extension_id,
74                              const GURL& listener_url,
75                              content::RenderProcessHost* process,
76                              scoped_ptr<DictionaryValue> filter)
77     : event_name_(event_name),
78       extension_id_(extension_id),
79       listener_url_(listener_url),
80       process_(process),
81       filter_(filter.Pass()),
82       matcher_id_(-1) {
83 }
84 
EventListenerMap(Delegate * delegate)85 EventListenerMap::EventListenerMap(Delegate* delegate)
86     : delegate_(delegate) {
87 }
88 
~EventListenerMap()89 EventListenerMap::~EventListenerMap() {}
90 
AddListener(scoped_ptr<EventListener> listener)91 bool EventListenerMap::AddListener(scoped_ptr<EventListener> listener) {
92   if (HasListener(listener.get()))
93     return false;
94   if (listener->filter()) {
95     scoped_ptr<EventMatcher> matcher(ParseEventMatcher(listener->filter()));
96     MatcherID id =
97         event_filter_.AddEventMatcher(listener->event_name(), matcher.Pass());
98     listener->set_matcher_id(id);
99     listeners_by_matcher_id_[id] = listener.get();
100     filtered_events_.insert(listener->event_name());
101   }
102   linked_ptr<EventListener> listener_ptr(listener.release());
103   listeners_[listener_ptr->event_name()].push_back(listener_ptr);
104 
105   delegate_->OnListenerAdded(listener_ptr.get());
106 
107   return true;
108 }
109 
ParseEventMatcher(DictionaryValue * filter_dict)110 scoped_ptr<EventMatcher> EventListenerMap::ParseEventMatcher(
111     DictionaryValue* filter_dict) {
112   return scoped_ptr<EventMatcher>(new EventMatcher(
113       make_scoped_ptr(filter_dict->DeepCopy()), MSG_ROUTING_NONE));
114 }
115 
RemoveListener(const EventListener * listener)116 bool EventListenerMap::RemoveListener(const EventListener* listener) {
117   ListenerList& listeners = listeners_[listener->event_name()];
118   for (ListenerList::iterator it = listeners.begin(); it != listeners.end();
119        it++) {
120     if ((*it)->Equals(listener)) {
121       CleanupListener(it->get());
122       // Popping from the back should be cheaper than erase(it).
123       std::swap(*it, listeners.back());
124       listeners.pop_back();
125       delegate_->OnListenerRemoved(listener);
126       return true;
127     }
128   }
129   return false;
130 }
131 
HasListenerForEvent(const std::string & event_name)132 bool EventListenerMap::HasListenerForEvent(const std::string& event_name) {
133   ListenerMap::iterator it = listeners_.find(event_name);
134   return it != listeners_.end() && !it->second.empty();
135 }
136 
HasListenerForExtension(const std::string & extension_id,const std::string & event_name)137 bool EventListenerMap::HasListenerForExtension(
138     const std::string& extension_id,
139     const std::string& event_name) {
140   ListenerMap::iterator it = listeners_.find(event_name);
141   if (it == listeners_.end())
142     return false;
143 
144   for (ListenerList::iterator it2 = it->second.begin();
145        it2 != it->second.end(); it2++) {
146     if ((*it2)->extension_id() == extension_id)
147       return true;
148   }
149   return false;
150 }
151 
HasListener(const EventListener * listener)152 bool EventListenerMap::HasListener(const EventListener* listener) {
153   ListenerMap::iterator it = listeners_.find(listener->event_name());
154   if (it == listeners_.end())
155     return false;
156   for (ListenerList::iterator it2 = it->second.begin();
157        it2 != it->second.end(); it2++) {
158     if ((*it2)->Equals(listener)) {
159       return true;
160     }
161   }
162   return false;
163 }
164 
HasProcessListener(content::RenderProcessHost * process,const std::string & extension_id)165 bool EventListenerMap::HasProcessListener(content::RenderProcessHost* process,
166                                           const std::string& extension_id) {
167   for (ListenerMap::iterator it = listeners_.begin(); it != listeners_.end();
168        it++) {
169     for (ListenerList::iterator it2 = it->second.begin();
170          it2 != it->second.end(); it2++) {
171       if ((*it2)->process() == process &&
172           (*it2)->extension_id() == extension_id)
173         return true;
174     }
175   }
176   return false;
177 }
178 
RemoveLazyListenersForExtension(const std::string & extension_id)179 void EventListenerMap::RemoveLazyListenersForExtension(
180     const std::string& extension_id) {
181   for (ListenerMap::iterator it = listeners_.begin(); it != listeners_.end();
182        it++) {
183     for (ListenerList::iterator it2 = it->second.begin();
184          it2 != it->second.end();) {
185       if ((*it2)->IsLazy() && (*it2)->extension_id() == extension_id) {
186         CleanupListener(it2->get());
187         it2 = it->second.erase(it2);
188       } else {
189         it2++;
190       }
191     }
192   }
193 }
194 
LoadUnfilteredLazyListeners(const std::string & extension_id,const std::set<std::string> & event_names)195 void EventListenerMap::LoadUnfilteredLazyListeners(
196     const std::string& extension_id,
197     const std::set<std::string>& event_names) {
198   for (std::set<std::string>::const_iterator it = event_names.begin();
199        it != event_names.end(); ++it) {
200     AddListener(EventListener::ForExtension(
201         *it, extension_id, NULL, scoped_ptr<DictionaryValue>()));
202   }
203 }
204 
LoadFilteredLazyListeners(const std::string & extension_id,const DictionaryValue & filtered)205 void EventListenerMap::LoadFilteredLazyListeners(
206     const std::string& extension_id,
207     const DictionaryValue& filtered) {
208   for (DictionaryValue::Iterator it(filtered); !it.IsAtEnd(); it.Advance()) {
209     // We skip entries if they are malformed.
210     const base::ListValue* filter_list = NULL;
211     if (!it.value().GetAsList(&filter_list))
212       continue;
213     for (size_t i = 0; i < filter_list->GetSize(); i++) {
214       const DictionaryValue* filter = NULL;
215       if (!filter_list->GetDictionary(i, &filter))
216         continue;
217       AddListener(EventListener::ForExtension(
218           it.key(), extension_id, NULL, make_scoped_ptr(filter->DeepCopy())));
219     }
220   }
221 }
222 
GetEventListeners(const Event & event)223 std::set<const EventListener*> EventListenerMap::GetEventListeners(
224     const Event& event) {
225   std::set<const EventListener*> interested_listeners;
226   if (IsFilteredEvent(event)) {
227     // Look up the interested listeners via the EventFilter.
228     std::set<MatcherID> ids =
229         event_filter_.MatchEvent(event.event_name, event.filter_info,
230             MSG_ROUTING_NONE);
231     for (std::set<MatcherID>::iterator id = ids.begin(); id != ids.end();
232          id++) {
233       EventListener* listener = listeners_by_matcher_id_[*id];
234       CHECK(listener);
235       interested_listeners.insert(listener);
236     }
237   } else {
238     ListenerList& listeners = listeners_[event.event_name];
239     for (ListenerList::const_iterator it = listeners.begin();
240          it != listeners.end(); it++) {
241       interested_listeners.insert(it->get());
242     }
243   }
244 
245   return interested_listeners;
246 }
247 
RemoveListenersForProcess(const content::RenderProcessHost * process)248 void EventListenerMap::RemoveListenersForProcess(
249     const content::RenderProcessHost* process) {
250   CHECK(process);
251   for (ListenerMap::iterator it = listeners_.begin(); it != listeners_.end();
252        it++) {
253     for (ListenerList::iterator it2 = it->second.begin();
254          it2 != it->second.end();) {
255       if ((*it2)->process() == process) {
256         linked_ptr<EventListener> listener(*it2);
257         CleanupListener(it2->get());
258         it2 = it->second.erase(it2);
259         delegate_->OnListenerRemoved(listener.get());
260       } else {
261         it2++;
262       }
263     }
264   }
265 }
266 
CleanupListener(EventListener * listener)267 void EventListenerMap::CleanupListener(EventListener* listener) {
268   // If the listener doesn't have a filter then we have nothing to clean up.
269   if (listener->matcher_id() == -1)
270     return;
271   event_filter_.RemoveEventMatcher(listener->matcher_id());
272   CHECK_EQ(1u, listeners_by_matcher_id_.erase(listener->matcher_id()));
273 }
274 
IsFilteredEvent(const Event & event) const275 bool EventListenerMap::IsFilteredEvent(const Event& event) const {
276   return filtered_events_.count(event.event_name) > 0u;
277 }
278 
279 }  // namespace extensions
280