File: event_listener_map.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (282 lines) | stat: -rw-r--r-- 11,282 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef EXTENSIONS_BROWSER_EVENT_LISTENER_MAP_H_
#define EXTENSIONS_BROWSER_EVENT_LISTENER_MAP_H_

#include <map>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <vector>

#include "base/containers/flat_map.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/values.h"
#include "extensions/common/event_filter.h"
#include "extensions/common/extension_id.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_database.mojom-forward.h"
#include "url/gurl.h"

namespace content {
class BrowserContext;
class RenderProcessHost;
}

namespace extensions {
struct Event;
struct WorkerId;

// A listener for an extension event. A listener is essentially an endpoint
// that an event can be dispatched to.
//
// This is a lazy listener if `IsLazy` is returns true, and a filtered listener
// if `filter` is defined.
//
// A lazy listener is added to an event to indicate that a lazy background page
// is listening to the event. It is associated with no process, so to dispatch
// an event to a lazy listener one must start a process running the associated
// extension and dispatch the event to that.
class EventListener {
 public:
  // Constructs EventListeners for either an Extension or a URL.
  //
  // `filter` represents a generic filter structure that EventFilter knows how
  // to filter events with. A typical filter instance will look like
  //
  // {
  //   url: [{hostSuffix: 'google.com'}],
  //   tabId: 5
  // }
  static std::unique_ptr<EventListener> ForExtension(
      const std::string& event_name,
      const ExtensionId& extension_id,
      content::RenderProcessHost* process,
      std::optional<base::Value::Dict> filter);
  static std::unique_ptr<EventListener> ForURL(
      const std::string& event_name,
      const GURL& listener_url,
      content::RenderProcessHost* process,
      std::optional<base::Value::Dict> filter);
  // Constructs EventListener for an Extension service worker.
  // Similar to ForExtension above with the only difference that
  // `worker_thread_id_` contains a valid worker thread, as opposed to
  // kMainThreadId and `service_worker_version_id` contains a valid service
  // worker version id instead of kInvalidServiceWorkerVersionId.
  static std::unique_ptr<EventListener> ForExtensionServiceWorker(
      const std::string& event_name,
      const ExtensionId& extension_id,
      content::RenderProcessHost* process,
      content::BrowserContext* browser_context,
      const GURL& service_worker_scope,
      int64_t service_worker_version_id,
      int worker_thread_id,
      std::optional<base::Value::Dict> filter);
  // Constructs a lazy listener, for an extension service worker or event page.
  // A lazy listener has these properties:
  // `process_` = nullptr
  // `service_worker_version_id_` = blink::mojom::kInvalidServiceWorkerVersionId
  // `worker_thread_id_` = kMainThreadId
  static std::unique_ptr<EventListener> CreateLazyListener(
      const std::string& event_name,
      const ExtensionId& extension_id,
      content::BrowserContext* browser_context,
      bool is_for_service_worker,
      const GURL& service_worker_scope,
      std::optional<base::Value::Dict> filter);

  EventListener(const EventListener&) = delete;
  EventListener& operator=(const EventListener&) = delete;

  ~EventListener();

  bool Equals(const EventListener* other) const;

  std::unique_ptr<EventListener> Copy() const;

  // Returns true if the listener is for a lazy context: e.g. a background page
  // or an extension service worker. This listener does not have `process_`.
  bool IsLazy() const;

  // Returns true if this listener (lazy or not) was registered for an extension
  // service worker.
  bool is_for_service_worker() const { return is_for_service_worker_; }

  // Modifies this listener to be a lazy listener, clearing process references.
  void MakeLazy();

  const std::string& event_name() const { return event_name_; }
  const ExtensionId& extension_id() const { return extension_id_; }
  const GURL& listener_url() const { return listener_url_; }
  content::RenderProcessHost* process() const { return process_; }
  content::BrowserContext* browser_context() const { return browser_context_; }
  const base::Value::Dict* filter() const {
    return filter_.has_value() ? &*filter_ : nullptr;
  }
  EventFilter::MatcherID matcher_id() const { return matcher_id_; }
  void set_matcher_id(EventFilter::MatcherID id) { matcher_id_ = id; }
  int64_t service_worker_version_id() const {
    return service_worker_version_id_;
  }
  int worker_thread_id() const { return worker_thread_id_; }

 private:
  EventListener(const std::string& event_name,
                const ExtensionId& extension_id,
                const GURL& listener_url,
                content::RenderProcessHost* process,
                content::BrowserContext* browser_context,
                bool is_for_service_worker,
                int64_t service_worker_version_id,
                int worker_thread_id,
                std::optional<base::Value::Dict> filter);

  const std::string event_name_;
  const ExtensionId extension_id_;
  const GURL listener_url_;
  raw_ptr<content::RenderProcessHost, DanglingUntriaged> process_ = nullptr;
  raw_ptr<content::BrowserContext, DanglingUntriaged> browser_context_ =
      nullptr;

  const bool is_for_service_worker_ = false;

  int64_t service_worker_version_id_ =
      blink::mojom::kInvalidServiceWorkerVersionId;

  // If this listener is for a service worker (i.e.
  // is_for_service_worker_ = true) and the worker is in running state, then
  // this is the worker's thread id in the worker `process_`. For lazy service
  // worker events, this will be kMainThreadId.
  int worker_thread_id_;

  std::optional<base::Value::Dict> filter_;
  EventFilter::MatcherID matcher_id_ = -1;
};

// Holds listeners for extension events and can answer questions about which
// listeners are interested in what events.
class EventListenerMap {
 public:
  using ListenerList = std::vector<std::unique_ptr<EventListener>>;
  // The key here is an event name.
  using ListenerMap = base::flat_map<std::string, ListenerList>;

  class Delegate {
   public:
    virtual ~Delegate() {}
    virtual void OnListenerAdded(const EventListener* listener) = 0;
    virtual void OnListenerRemoved(const EventListener* listener) = 0;
  };

  explicit EventListenerMap(Delegate* delegate);

  EventListenerMap(const EventListenerMap&) = delete;
  EventListenerMap& operator=(const EventListenerMap&) = delete;

  ~EventListenerMap();

  // Add a listener for a particular event. GetEventListeners() will include a
  // weak pointer to `listener` in its results if passed a relevant
  // extensions::Event.
  // Returns true if the listener was added (in the case that it has never been
  // seen before).
  bool AddListener(std::unique_ptr<EventListener> listener);

  // Remove a listener that .Equals() `listener`.
  // Returns true if the listener was removed .
  bool RemoveListener(const EventListener* listener);

  // Get the map of all EventListeners.
  const ListenerMap& listeners() const { return listeners_; }

  // Returns the set of listeners that want to be notified of `event`.
  std::set<const EventListener*> GetEventListeners(const Event& event);

  const ListenerList& GetEventListenersByName(const std::string& event_name) {
    return listeners_[event_name];
  }

  // Removes all listeners with process equal to `process`.
  void RemoveListenersForProcess(const content::RenderProcessHost* process);

  // Returns true if there are any listeners on the event named `event_name`.
  bool HasListenerForEvent(const std::string& event_name) const;

  // Returns true if there are any listeners on `event_name` from
  // `extension_id`.
  bool HasListenerForExtension(const ExtensionId& extension_id,
                               const std::string& event_name) const;

  // Returns true if there are any listeners on `event_name` from `url`.
  bool HasListenerForURL(const GURL& url, const std::string& event_name) const;

  // Returns true if this map contains an EventListener that .Equals()
  // `listener`.
  bool HasListener(const EventListener* listener) const;

  // Returns true if there is a listener for `extension_id` in `process`.
  // `worker_thread_id` is the thread id of the service worker the listener is
  // for, or kMainThreadId if the listener is not for a service worker.
  bool HasProcessListener(content::RenderProcessHost* process,
                          int worker_thread_id,
                          const ExtensionId& extension_id) const;
  // As above, but checks for a specific event.
  bool HasProcessListenerForEvent(content::RenderProcessHost* process,
                                  int worker_thread_id,
                                  const ExtensionId& extension_id,
                                  const std::string& event_name) const;

  // Removes all listeners that `extension_id` has added, both lazy and active.
  void RemoveListenersForExtension(const ExtensionId& extension_id);

  // Removes any active listeners that `extension_id` has added.
  void RemoveActiveServiceWorkerListenersForExtension(
      const WorkerId& worker_id);

  // Adds unfiltered lazy listeners as described their serialised descriptions.
  // `event_names` the names of the lazy events.
  // Note that we can only load lazy listeners in this fashion, because there
  // is no way to serialise a RenderProcessHost*.
  void LoadUnfilteredLazyListeners(content::BrowserContext* browser_context,
                                   const ExtensionId& extension_id,
                                   bool is_for_service_worker,
                                   const std::set<std::string>& event_names);

  // Adds filtered lazy listeners as described their serialised descriptions.
  // `filtered` contains a map from event names to filters, each pairing
  // defining a lazy filtered listener.
  void LoadFilteredLazyListeners(content::BrowserContext* browser_context,
                                 const ExtensionId& extension_id,
                                 bool is_for_service_worker,
                                 const base::Value::Dict& filtered);

 private:
  // Removes all listeners for `extension_id` where `removal_predicate` is true.
  void RemoveListenersForExtensionImpl(
      const ExtensionId& extension_id,
      base::RepeatingCallback<bool(const ExtensionId&, EventListener*)>
          removal_predicate);

  void CleanupListener(EventListener* listener);
  bool IsFilteredEvent(const Event& event) const;
  std::unique_ptr<EventMatcher> ParseEventMatcher(
      const base::Value::Dict& filter_dict);

  // Listens for removals from this map.
  const raw_ptr<Delegate> delegate_;

  std::set<std::string> filtered_events_;
  ListenerMap listeners_;

  std::map<EventFilter::MatcherID, raw_ptr<EventListener, CtnExperimental>>
      listeners_by_matcher_id_;

  EventFilter event_filter_;
};

}  // namespace extensions

#endif  // EXTENSIONS_BROWSER_EVENT_LISTENER_MAP_H_