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 "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
     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
     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 
     39 EventListener::~EventListener() {}
     40 
     41 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 
     52 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 
     60 bool EventListener::IsLazy() const {
     61   return !process_;
     62 }
     63 
     64 void EventListener::MakeLazy() {
     65   process_ = NULL;
     66 }
     67 
     68 content::BrowserContext* EventListener::GetBrowserContext() const {
     69   return process_ ? process_->GetBrowserContext() : NULL;
     70 }
     71 
     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 
     85 EventListenerMap::EventListenerMap(Delegate* delegate)
     86     : delegate_(delegate) {
     87 }
     88 
     89 EventListenerMap::~EventListenerMap() {}
     90 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    275 bool EventListenerMap::IsFilteredEvent(const Event& event) const {
    276   return filtered_events_.count(event.event_name) > 0u;
    277 }
    278 
    279 }  // namespace extensions
    280