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