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