Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(82)

Side by Side Diff: extensions/renderer/event_bindings.cc

Issue 2924683002: [Extensions Bindings] Avoid passing the event filter to JS (Closed)
Patch Set: remove extra '.' Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "extensions/renderer/event_bindings.h" 5 #include "extensions/renderer/event_bindings.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include <map> 9 #include <map>
10 #include <memory> 10 #include <memory>
11 #include <utility> 11 #include <utility>
12 12
13 #include "base/bind.h" 13 #include "base/bind.h"
14 #include "base/lazy_instance.h" 14 #include "base/lazy_instance.h"
15 #include "base/memory/ptr_util.h" 15 #include "base/memory/ptr_util.h"
16 #include "components/crx_file/id_util.h" 16 #include "components/crx_file/id_util.h"
17 #include "content/public/child/v8_value_converter.h" 17 #include "content/public/child/v8_value_converter.h"
18 #include "content/public/renderer/render_frame.h" 18 #include "content/public/renderer/render_frame.h"
19 #include "content/public/renderer/render_thread.h" 19 #include "content/public/renderer/render_thread.h"
20 #include "content/public/renderer/render_view.h" 20 #include "content/public/renderer/render_view.h"
21 #include "extensions/common/constants.h" 21 #include "extensions/common/constants.h"
22 #include "extensions/common/event_filter.h" 22 #include "extensions/common/event_filter.h"
23 #include "extensions/common/extension.h" 23 #include "extensions/common/extension.h"
24 #include "extensions/common/extension_messages.h" 24 #include "extensions/common/extension_messages.h"
25 #include "extensions/common/extension_urls.h"
25 #include "extensions/common/value_counter.h" 26 #include "extensions/common/value_counter.h"
26 #include "extensions/renderer/extension_frame_helper.h" 27 #include "extensions/renderer/extension_frame_helper.h"
27 #include "extensions/renderer/script_context.h" 28 #include "extensions/renderer/script_context.h"
28 #include "extensions/renderer/service_worker_request_sender.h" 29 #include "extensions/renderer/service_worker_request_sender.h"
29 #include "extensions/renderer/worker_thread_dispatcher.h" 30 #include "extensions/renderer/worker_thread_dispatcher.h"
31 #include "gin/converter.h"
30 #include "url/gurl.h" 32 #include "url/gurl.h"
31 33
32 namespace extensions { 34 namespace extensions {
33 35
34 namespace { 36 namespace {
35 37
36 // A map of event names to the number of contexts listening to that event. 38 // A map of event names to the number of contexts listening to that event.
37 // We notify the browser about event listeners when we transition between 0 39 // We notify the browser about event listeners when we transition between 0
38 // and 1. 40 // and 1.
39 typedef std::map<std::string, int> EventListenerCounts; 41 typedef std::map<std::string, int> EventListenerCounts;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
75 } 77 }
76 78
77 // Decrements the number of event-listeners for the given |event_name| and 79 // Decrements the number of event-listeners for the given |event_name| and
78 // ScriptContext. Returns the count after the increment. 80 // ScriptContext. Returns the count after the increment.
79 int DecrementEventListenerCount(ScriptContext* script_context, 81 int DecrementEventListenerCount(ScriptContext* script_context,
80 const std::string& event_name) { 82 const std::string& event_name) {
81 return --g_listener_counts 83 return --g_listener_counts
82 .Get()[GetKeyForScriptContext(script_context)][event_name]; 84 .Get()[GetKeyForScriptContext(script_context)][event_name];
83 } 85 }
84 86
85 EventFilteringInfo ParseFromObject(v8::Local<v8::Object> object,
86 v8::Isolate* isolate) {
87 EventFilteringInfo info;
88 v8::Local<v8::String> url(v8::String::NewFromUtf8(isolate, "url"));
89 if (object->Has(url)) {
90 v8::Local<v8::Value> url_value(object->Get(url));
91 info.SetURL(GURL(*v8::String::Utf8Value(url_value)));
92 }
93 v8::Local<v8::String> instance_id(
94 v8::String::NewFromUtf8(isolate, "instanceId"));
95 if (object->Has(instance_id)) {
96 v8::Local<v8::Value> instance_id_value(object->Get(instance_id));
97 info.SetInstanceID(instance_id_value->IntegerValue());
98 }
99 v8::Local<v8::String> service_type(
100 v8::String::NewFromUtf8(isolate, "serviceType"));
101 if (object->Has(service_type)) {
102 v8::Local<v8::Value> service_type_value(object->Get(service_type));
103 info.SetServiceType(*v8::String::Utf8Value(service_type_value));
104 }
105 v8::Local<v8::String> window_types(
106 v8::String::NewFromUtf8(isolate, "windowType"));
107 if (object->Has(window_types)) {
108 v8::Local<v8::Value> window_types_value(object->Get(window_types));
109 info.SetWindowType(*v8::String::Utf8Value(window_types_value));
110 }
111
112 v8::Local<v8::String> window_exposed(
113 v8::String::NewFromUtf8(isolate, "windowExposedByDefault"));
114 if (object->Has(window_exposed)) {
115 v8::Local<v8::Value> window_exposed_value(object->Get(window_exposed));
116 info.SetWindowExposedByDefault(
117 window_exposed_value.As<v8::Boolean>()->Value());
118 }
119
120 return info;
121 }
122
123 // Add a filter to |event_name| in |extension_id|, returning true if it 87 // Add a filter to |event_name| in |extension_id|, returning true if it
124 // was the first filter for that event in that extension. 88 // was the first filter for that event in that extension.
125 bool AddFilter(const std::string& event_name, 89 bool AddFilter(const std::string& event_name,
126 const std::string& extension_id, 90 const std::string& extension_id,
127 const base::DictionaryValue& filter) { 91 const base::DictionaryValue& filter) {
128 FilteredEventListenerKey key(extension_id, event_name); 92 FilteredEventListenerKey key(extension_id, event_name);
129 FilteredEventListenerCounts& all_counts = g_filtered_listener_counts.Get(); 93 FilteredEventListenerCounts& all_counts = g_filtered_listener_counts.Get();
130 FilteredEventListenerCounts::const_iterator counts = all_counts.find(key); 94 FilteredEventListenerCounts::const_iterator counts = all_counts.find(key);
131 if (counts == all_counts.end()) { 95 if (counts == all_counts.end()) {
132 counts = 96 counts =
(...skipping 17 matching lines...) Expand all
150 // |filter|. If there are more equivalent filters, or if there weren't any in 114 // |filter|. If there are more equivalent filters, or if there weren't any in
151 // the first place, it returns false. 115 // the first place, it returns false.
152 if (counts->second->Remove(*filter)) { 116 if (counts->second->Remove(*filter)) {
153 if (counts->second->is_empty()) 117 if (counts->second->is_empty())
154 all_counts.erase(counts); // Clean up if there are no more filters. 118 all_counts.erase(counts); // Clean up if there are no more filters.
155 return true; 119 return true;
156 } 120 }
157 return false; 121 return false;
158 } 122 }
159 123
124 // Returns a v8::Array containing the ids of the listeners that match the given
125 // |event_filter_dict| in the given |script_context|.
126 v8::Local<v8::Array> GetMatchingListeners(
127 ScriptContext* script_context,
128 const std::string& event_name,
129 const base::DictionaryValue& event_filter_dict) {
130 EventFilter& event_filter = g_event_filter.Get();
jbroman 2017/06/12 15:48:51 nit: const&? (use of a singleton across threads li
Devlin 2017/06/12 17:01:54 Done.
131 EventFilteringInfo info(event_filter_dict);
132 v8::Isolate* isolate = script_context->isolate();
133 v8::Local<v8::Context> context = script_context->v8_context();
134
135 // Only match events routed to this context's RenderFrame or ones that don't
136 // have a routingId in their filter.
137 std::set<EventFilter::MatcherID> matched_event_filters =
138 event_filter.MatchEvent(event_name, info,
139 script_context->GetRenderFrame()->GetRoutingID());
140 v8::Local<v8::Array> array(
141 v8::Array::New(isolate, matched_event_filters.size()));
142 int i = 0;
143 for (EventFilter::MatcherID id : matched_event_filters) {
144 CHECK(array->CreateDataProperty(context, i++, v8::Integer::New(isolate, id))
lazyboy 2017/06/10 00:22:08 I'll defer to Jeremy for this one.
jbroman 2017/06/12 15:48:51 This looks good to me.
145 .ToChecked());
146 }
147
148 return array;
149 }
150
160 } // namespace 151 } // namespace
161 152
162 EventBindings::EventBindings(ScriptContext* context) 153 EventBindings::EventBindings(ScriptContext* context)
163 : ObjectBackedNativeHandler(context) { 154 : ObjectBackedNativeHandler(context) {
164 RouteFunction("AttachEvent", base::Bind(&EventBindings::AttachEventHandler, 155 RouteFunction("AttachEvent", base::Bind(&EventBindings::AttachEventHandler,
165 base::Unretained(this))); 156 base::Unretained(this)));
166 RouteFunction("DetachEvent", base::Bind(&EventBindings::DetachEventHandler, 157 RouteFunction("DetachEvent", base::Bind(&EventBindings::DetachEventHandler,
167 base::Unretained(this))); 158 base::Unretained(this)));
168 RouteFunction( 159 RouteFunction(
169 "AttachFilteredEvent", 160 "AttachFilteredEvent",
170 base::Bind(&EventBindings::AttachFilteredEvent, base::Unretained(this))); 161 base::Bind(&EventBindings::AttachFilteredEvent, base::Unretained(this)));
171 RouteFunction("DetachFilteredEvent", 162 RouteFunction("DetachFilteredEvent",
172 base::Bind(&EventBindings::DetachFilteredEventHandler, 163 base::Bind(&EventBindings::DetachFilteredEventHandler,
173 base::Unretained(this))); 164 base::Unretained(this)));
174 RouteFunction("MatchAgainstEventFilter",
175 base::Bind(&EventBindings::MatchAgainstEventFilter,
176 base::Unretained(this)));
177 165
178 // It's safe to use base::Unretained here because |context| will always 166 // It's safe to use base::Unretained here because |context| will always
179 // outlive us. 167 // outlive us.
180 context->AddInvalidationObserver( 168 context->AddInvalidationObserver(
181 base::Bind(&EventBindings::OnInvalidated, base::Unretained(this))); 169 base::Bind(&EventBindings::OnInvalidated, base::Unretained(this)));
182 } 170 }
183 171
184 EventBindings::~EventBindings() {} 172 EventBindings::~EventBindings() {}
185 173
174 void EventBindings::DispatchEventInContext(
175 const std::string& event_name,
176 const base::ListValue* event_args,
177 const base::DictionaryValue* filtering_info,
178 ScriptContext* context) {
179 v8::HandleScope handle_scope(context->isolate());
180 v8::Context::Scope context_scope(context->v8_context());
181
182 std::vector<v8::Local<v8::Value>> arguments;
jbroman 2017/06/12 15:48:51 super-nit: could at least reserve the buffer here,
Devlin 2017/06/12 17:01:54 sgtm. Little more complicated since we have to pu
183 arguments.push_back(gin::StringToSymbol(context->isolate(), event_name));
184
185 {
186 std::unique_ptr<content::V8ValueConverter> converter(
187 content::V8ValueConverter::create());
188 arguments.push_back(
189 converter->ToV8Value(event_args, context->v8_context()));
190 }
191
192 v8::Local<v8::Array> listener_ids;
193 if (filtering_info && !filtering_info->empty())
194 listener_ids = GetMatchingListeners(context, event_name, *filtering_info);
195 else
196 listener_ids = v8::Array::New(context->isolate());
197
198 arguments.push_back(listener_ids);
199
200 context->module_system()->CallModuleMethodSafe(
201 kEventBindings, "dispatchEvent", arguments.size(), arguments.data());
202 }
203
186 void EventBindings::AttachEventHandler( 204 void EventBindings::AttachEventHandler(
187 const v8::FunctionCallbackInfo<v8::Value>& args) { 205 const v8::FunctionCallbackInfo<v8::Value>& args) {
188 CHECK_EQ(1, args.Length()); 206 CHECK_EQ(1, args.Length());
189 CHECK(args[0]->IsString()); 207 CHECK(args[0]->IsString());
190 AttachEvent(*v8::String::Utf8Value(args[0])); 208 AttachEvent(*v8::String::Utf8Value(args[0]));
191 } 209 }
192 210
193 void EventBindings::AttachEvent(const std::string& event_name) { 211 void EventBindings::AttachEvent(const std::string& event_name) {
194 if (!context()->HasAccessOrThrowError(event_name)) 212 if (!context()->HasAccessOrThrowError(event_name))
195 return; 213 return;
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 if (is_lazy_context) { 273 if (is_lazy_context) {
256 sender->Send(new ExtensionHostMsg_RemoveLazyListener( 274 sender->Send(new ExtensionHostMsg_RemoveLazyListener(
257 extension_id, event_name, worker_thread_id)); 275 extension_id, event_name, worker_thread_id));
258 } 276 }
259 } 277 }
260 } 278 }
261 279
262 // MatcherID AttachFilteredEvent(string event_name, object filter) 280 // MatcherID AttachFilteredEvent(string event_name, object filter)
263 // event_name - Name of the event to attach. 281 // event_name - Name of the event to attach.
264 // filter - Which instances of the named event are we interested in. 282 // filter - Which instances of the named event are we interested in.
265 // returns the id assigned to the listener, which will be returned from calls 283 // returns the id assigned to the listener, which will be provided to calls to
266 // to MatchAgainstEventFilter where this listener matches. 284 // dispatchEvent().
267 void EventBindings::AttachFilteredEvent( 285 void EventBindings::AttachFilteredEvent(
268 const v8::FunctionCallbackInfo<v8::Value>& args) { 286 const v8::FunctionCallbackInfo<v8::Value>& args) {
269 CHECK_EQ(2, args.Length()); 287 CHECK_EQ(2, args.Length());
270 CHECK(args[0]->IsString()); 288 CHECK(args[0]->IsString());
271 CHECK(args[1]->IsObject()); 289 CHECK(args[1]->IsObject());
272 290
273 std::string event_name = *v8::String::Utf8Value(args[0]); 291 std::string event_name = *v8::String::Utf8Value(args[0]);
274 if (!context()->HasAccessOrThrowError(event_name)) 292 if (!context()->HasAccessOrThrowError(event_name))
275 return; 293 return;
276 294
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 is_manual && ExtensionFrameHelper::IsContextForEventPage(context()); 348 is_manual && ExtensionFrameHelper::IsContextForEventPage(context());
331 content::RenderThread::Get()->Send( 349 content::RenderThread::Get()->Send(
332 new ExtensionHostMsg_RemoveFilteredListener( 350 new ExtensionHostMsg_RemoveFilteredListener(
333 extension_id, event_name, *event_matcher->value(), remove_lazy)); 351 extension_id, event_name, *event_matcher->value(), remove_lazy));
334 } 352 }
335 353
336 event_filter.RemoveEventMatcher(matcher_id); 354 event_filter.RemoveEventMatcher(matcher_id);
337 attached_matcher_ids_.erase(matcher_id); 355 attached_matcher_ids_.erase(matcher_id);
338 } 356 }
339 357
340 void EventBindings::MatchAgainstEventFilter(
341 const v8::FunctionCallbackInfo<v8::Value>& args) {
342 v8::Isolate* isolate = args.GetIsolate();
343 typedef std::set<EventFilter::MatcherID> MatcherIDs;
344 EventFilter& event_filter = g_event_filter.Get();
345 std::string event_name = *v8::String::Utf8Value(args[0]);
346 EventFilteringInfo info =
347 ParseFromObject(args[1]->ToObject(isolate), isolate);
348 // Only match events routed to this context's RenderFrame or ones that don't
349 // have a routingId in their filter.
350 MatcherIDs matched_event_filters = event_filter.MatchEvent(
351 event_name, info, context()->GetRenderFrame()->GetRoutingID());
352 v8::Local<v8::Array> array(
353 v8::Array::New(isolate, matched_event_filters.size()));
354 int i = 0;
355 for (MatcherIDs::iterator it = matched_event_filters.begin();
356 it != matched_event_filters.end();
357 ++it) {
358 array->Set(v8::Integer::New(isolate, i++), v8::Integer::New(isolate, *it));
359 }
360 args.GetReturnValue().Set(array);
361 }
362
363 std::unique_ptr<EventMatcher> EventBindings::ParseEventMatcher( 358 std::unique_ptr<EventMatcher> EventBindings::ParseEventMatcher(
364 std::unique_ptr<base::DictionaryValue> filter) { 359 std::unique_ptr<base::DictionaryValue> filter) {
365 return base::MakeUnique<EventMatcher>( 360 return base::MakeUnique<EventMatcher>(
366 std::move(filter), context()->GetRenderFrame()->GetRoutingID()); 361 std::move(filter), context()->GetRenderFrame()->GetRoutingID());
367 } 362 }
368 363
369 IPC::Sender* EventBindings::GetIPCSender() { 364 IPC::Sender* EventBindings::GetIPCSender() {
370 const bool is_service_worker_context = 365 const bool is_service_worker_context =
371 context()->context_type() == Feature::SERVICE_WORKER_CONTEXT; 366 context()->context_type() == Feature::SERVICE_WORKER_CONTEXT;
372 DCHECK_EQ(is_service_worker_context, 367 DCHECK_EQ(is_service_worker_context,
(...skipping 16 matching lines...) Expand all
389 // Same for filtered events. 384 // Same for filtered events.
390 std::set<int> attached_matcher_ids_safe = attached_matcher_ids_; 385 std::set<int> attached_matcher_ids_safe = attached_matcher_ids_;
391 for (int matcher_id : attached_matcher_ids_safe) { 386 for (int matcher_id : attached_matcher_ids_safe) {
392 DetachFilteredEvent(matcher_id, false /* is_manual */); 387 DetachFilteredEvent(matcher_id, false /* is_manual */);
393 } 388 }
394 DCHECK(attached_matcher_ids_.empty()) 389 DCHECK(attached_matcher_ids_.empty())
395 << "Filtered events cannot be attached during invalidation"; 390 << "Filtered events cannot be attached during invalidation";
396 } 391 }
397 392
398 } // namespace extensions 393 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698