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#ifndef EXTENSIONS_BROWSER_EVENT_LISTENER_MAP_H_
6#define EXTENSIONS_BROWSER_EVENT_LISTENER_MAP_H_
7
8#include <map>
9#include <set>
10#include <string>
11#include <vector>
12
13#include "base/memory/scoped_ptr.h"
14#include "extensions/common/event_filter.h"
15#include "url/gurl.h"
16
17namespace base {
18class DictionaryValue;
19}
20
21namespace content {
22class BrowserContext;
23class RenderProcessHost;
24}
25
26class ListenerRemovalListener;
27
28namespace extensions {
29struct Event;
30
31// A listener for an extension event. A listener is essentially an endpoint
32// that an event can be dispatched to.
33//
34// This is a lazy listener if |IsLazy| is returns true, and a filtered listener
35// if |filter| is defined.
36//
37// A lazy listener is added to an event to indicate that a lazy background page
38// is listening to the event. It is associated with no process, so to dispatch
39// an event to a lazy listener one must start a process running the associated
40// extension and dispatch the event to that.
41class EventListener {
42 public:
43  // Constructs EventListeners for either an Extension or a URL.
44  //
45  // |filter| represents a generic filter structure that EventFilter knows how
46  // to filter events with. A typical filter instance will look like
47  //
48  // {
49  //   url: [{hostSuffix: 'google.com'}],
50  //   tabId: 5
51  // }
52  static scoped_ptr<EventListener> ForExtension(
53      const std::string& event_name,
54      const std::string& extension_id,
55      content::RenderProcessHost* process,
56      scoped_ptr<base::DictionaryValue> filter);
57  static scoped_ptr<EventListener> ForURL(
58      const std::string& event_name,
59      const GURL& listener_url,
60      content::RenderProcessHost* process,
61      scoped_ptr<base::DictionaryValue> filter);
62
63  ~EventListener();
64
65  bool Equals(const EventListener* other) const;
66
67  scoped_ptr<EventListener> Copy() const;
68
69  // Returns true in the case of a lazy background page, and thus no process.
70  bool IsLazy() const;
71
72  // Modifies this listener to be a lazy listener, clearing process references.
73  void MakeLazy();
74
75  // Returns the browser context associated with the listener, or NULL if
76  // IsLazy.
77  content::BrowserContext* GetBrowserContext() const;
78
79  const std::string& event_name() const { return event_name_; }
80  const std::string& extension_id() const { return extension_id_; }
81  const GURL& listener_url() const { return listener_url_; }
82  content::RenderProcessHost* process() const { return process_; }
83  base::DictionaryValue* filter() const { return filter_.get(); }
84  EventFilter::MatcherID matcher_id() const { return matcher_id_; }
85  void set_matcher_id(EventFilter::MatcherID id) { matcher_id_ = id; }
86
87 private:
88  EventListener(const std::string& event_name,
89                const std::string& extension_id,
90                const GURL& listener_url,
91                content::RenderProcessHost* process,
92                scoped_ptr<base::DictionaryValue> filter);
93
94  const std::string event_name_;
95  const std::string extension_id_;
96  const GURL listener_url_;
97  content::RenderProcessHost* process_;
98  scoped_ptr<base::DictionaryValue> filter_;
99  EventFilter::MatcherID matcher_id_;  // -1 if unset.
100
101  DISALLOW_COPY_AND_ASSIGN(EventListener);
102};
103
104// Holds listeners for extension events and can answer questions about which
105// listeners are interested in what events.
106class EventListenerMap {
107 public:
108  typedef std::vector<linked_ptr<EventListener> > ListenerList;
109
110  class Delegate {
111   public:
112    virtual ~Delegate() {}
113    virtual void OnListenerAdded(const EventListener* listener) = 0;
114    virtual void OnListenerRemoved(const EventListener* listener) = 0;
115  };
116
117  explicit EventListenerMap(Delegate* delegate);
118  ~EventListenerMap();
119
120  // Add a listener for a particular event. GetEventListeners() will include a
121  // weak pointer to |listener| in its results if passed a relevant
122  // extensions::Event.
123  // Returns true if the listener was added (in the case that it has never been
124  // seen before).
125  bool AddListener(scoped_ptr<EventListener> listener);
126
127  // Remove a listener that .Equals() |listener|.
128  // Returns true if the listener was removed .
129  bool RemoveListener(const EventListener* listener);
130
131  // Returns the set of listeners that want to be notified of |event|.
132  std::set<const EventListener*> GetEventListeners(const Event& event);
133
134  const ListenerList& GetEventListenersByName(const std::string& event_name) {
135    return listeners_[event_name];
136  }
137
138  // Removes all listeners with process equal to |process|.
139  void RemoveListenersForProcess(const content::RenderProcessHost* process);
140
141  // Returns true if there are any listeners on the event named |event_name|.
142  bool HasListenerForEvent(const std::string& event_name);
143
144  // Returns true if there are any listeners on |event_name| from
145  // |extension_id|.
146  bool HasListenerForExtension(const std::string& extension_id,
147                               const std::string& event_name);
148
149  // Returns true if this map contains an EventListener that .Equals()
150  // |listener|.
151  bool HasListener(const EventListener* listener);
152
153  // Returns true if there is a listener for |extension_id| in |process|.
154  bool HasProcessListener(content::RenderProcessHost* process,
155                          const std::string& extension_id);
156
157  // Removes any lazy listeners that |extension_id| has added.
158  void RemoveLazyListenersForExtension(const std::string& extension_id);
159
160  // Adds unfiltered lazy listeners as described their serialised descriptions.
161  // |event_names| the names of the lazy events.
162  // Note that we can only load lazy listeners in this fashion, because there
163  // is no way to serialise a RenderProcessHost*.
164  void LoadUnfilteredLazyListeners(const std::string& extension_id,
165                                   const std::set<std::string>& event_names);
166
167  // Adds filtered lazy listeners as described their serialised descriptions.
168  // |filtered| contains a map from event names to filters, each pairing
169  // defining a lazy filtered listener.
170  void LoadFilteredLazyListeners(
171      const std::string& extension_id,
172      const base::DictionaryValue& filtered);
173
174 private:
175  // The key here is an event name.
176  typedef std::map<std::string, ListenerList> ListenerMap;
177
178  void CleanupListener(EventListener* listener);
179  bool IsFilteredEvent(const Event& event) const;
180  scoped_ptr<EventMatcher> ParseEventMatcher(
181      base::DictionaryValue* filter_dict);
182
183  // Listens for removals from this map.
184  Delegate* delegate_;
185
186  std::set<std::string> filtered_events_;
187  ListenerMap listeners_;
188
189  std::map<EventFilter::MatcherID, EventListener*> listeners_by_matcher_id_;
190
191  EventFilter event_filter_;
192
193  DISALLOW_COPY_AND_ASSIGN(EventListenerMap);
194};
195
196}  // namespace extensions
197
198#endif  // EXTENSIONS_BROWSER_EVENT_LISTENER_MAP_H_
199