| OLD | NEW |
| 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" | |
| 26 #include "extensions/common/value_counter.h" | 25 #include "extensions/common/value_counter.h" |
| 27 #include "extensions/renderer/extension_frame_helper.h" | 26 #include "extensions/renderer/extension_frame_helper.h" |
| 28 #include "extensions/renderer/script_context.h" | 27 #include "extensions/renderer/script_context.h" |
| 29 #include "extensions/renderer/service_worker_request_sender.h" | 28 #include "extensions/renderer/service_worker_request_sender.h" |
| 30 #include "extensions/renderer/worker_thread_dispatcher.h" | 29 #include "extensions/renderer/worker_thread_dispatcher.h" |
| 31 #include "gin/converter.h" | 30 #include "gin/converter.h" |
| 32 #include "url/gurl.h" | 31 #include "url/gurl.h" |
| 33 | 32 |
| 34 namespace extensions { | 33 namespace extensions { |
| 35 | 34 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 } | 81 } |
| 83 | 82 |
| 84 // Decrements the number of event-listeners for the given |event_name| and | 83 // Decrements the number of event-listeners for the given |event_name| and |
| 85 // ScriptContext. Returns the count after the increment. | 84 // ScriptContext. Returns the count after the increment. |
| 86 int DecrementEventListenerCount(ScriptContext* script_context, | 85 int DecrementEventListenerCount(ScriptContext* script_context, |
| 87 const std::string& event_name) { | 86 const std::string& event_name) { |
| 88 return --g_listener_counts | 87 return --g_listener_counts |
| 89 .Get()[GetKeyForScriptContext(script_context)][event_name]; | 88 .Get()[GetKeyForScriptContext(script_context)][event_name]; |
| 90 } | 89 } |
| 91 | 90 |
| 91 EventFilteringInfo ParseFromObject(v8::Local<v8::Object> object, |
| 92 v8::Isolate* isolate) { |
| 93 EventFilteringInfo info; |
| 94 v8::Local<v8::String> url(v8::String::NewFromUtf8(isolate, "url")); |
| 95 if (object->Has(url)) { |
| 96 v8::Local<v8::Value> url_value(object->Get(url)); |
| 97 info.SetURL(GURL(*v8::String::Utf8Value(url_value))); |
| 98 } |
| 99 v8::Local<v8::String> instance_id( |
| 100 v8::String::NewFromUtf8(isolate, "instanceId")); |
| 101 if (object->Has(instance_id)) { |
| 102 v8::Local<v8::Value> instance_id_value(object->Get(instance_id)); |
| 103 info.SetInstanceID(instance_id_value->IntegerValue()); |
| 104 } |
| 105 v8::Local<v8::String> service_type( |
| 106 v8::String::NewFromUtf8(isolate, "serviceType")); |
| 107 if (object->Has(service_type)) { |
| 108 v8::Local<v8::Value> service_type_value(object->Get(service_type)); |
| 109 info.SetServiceType(*v8::String::Utf8Value(service_type_value)); |
| 110 } |
| 111 v8::Local<v8::String> window_types( |
| 112 v8::String::NewFromUtf8(isolate, "windowType")); |
| 113 if (object->Has(window_types)) { |
| 114 v8::Local<v8::Value> window_types_value(object->Get(window_types)); |
| 115 info.SetWindowType(*v8::String::Utf8Value(window_types_value)); |
| 116 } |
| 117 |
| 118 v8::Local<v8::String> window_exposed( |
| 119 v8::String::NewFromUtf8(isolate, "windowExposedByDefault")); |
| 120 if (object->Has(window_exposed)) { |
| 121 v8::Local<v8::Value> window_exposed_value(object->Get(window_exposed)); |
| 122 info.SetWindowExposedByDefault( |
| 123 window_exposed_value.As<v8::Boolean>()->Value()); |
| 124 } |
| 125 |
| 126 return info; |
| 127 } |
| 128 |
| 92 // Add a filter to |event_name| in |extension_id|, returning true if it | 129 // Add a filter to |event_name| in |extension_id|, returning true if it |
| 93 // was the first filter for that event in that extension. | 130 // was the first filter for that event in that extension. |
| 94 bool AddFilter(const std::string& event_name, | 131 bool AddFilter(const std::string& event_name, |
| 95 const std::string& extension_id, | 132 const std::string& extension_id, |
| 96 const base::DictionaryValue& filter) { | 133 const base::DictionaryValue& filter) { |
| 97 FilteredEventListenerKey key(extension_id, event_name); | 134 FilteredEventListenerKey key(extension_id, event_name); |
| 98 FilteredEventListenerCounts& all_counts = g_filtered_listener_counts.Get(); | 135 FilteredEventListenerCounts& all_counts = g_filtered_listener_counts.Get(); |
| 99 FilteredEventListenerCounts::const_iterator counts = all_counts.find(key); | 136 FilteredEventListenerCounts::const_iterator counts = all_counts.find(key); |
| 100 if (counts == all_counts.end()) { | 137 if (counts == all_counts.end()) { |
| 101 counts = | 138 counts = |
| (...skipping 17 matching lines...) Expand all Loading... |
| 119 // |filter|. If there are more equivalent filters, or if there weren't any in | 156 // |filter|. If there are more equivalent filters, or if there weren't any in |
| 120 // the first place, it returns false. | 157 // the first place, it returns false. |
| 121 if (counts->second->Remove(*filter)) { | 158 if (counts->second->Remove(*filter)) { |
| 122 if (counts->second->is_empty()) | 159 if (counts->second->is_empty()) |
| 123 all_counts.erase(counts); // Clean up if there are no more filters. | 160 all_counts.erase(counts); // Clean up if there are no more filters. |
| 124 return true; | 161 return true; |
| 125 } | 162 } |
| 126 return false; | 163 return false; |
| 127 } | 164 } |
| 128 | 165 |
| 129 // Returns a v8::Array containing the ids of the listeners that match the given | |
| 130 // |event_filter_dict| in the given |script_context|. | |
| 131 v8::Local<v8::Array> GetMatchingListeners( | |
| 132 ScriptContext* script_context, | |
| 133 const std::string& event_name, | |
| 134 const base::DictionaryValue& event_filter_dict) { | |
| 135 const EventFilter& event_filter = g_event_filter.Get(); | |
| 136 EventFilteringInfo info(event_filter_dict); | |
| 137 v8::Isolate* isolate = script_context->isolate(); | |
| 138 v8::Local<v8::Context> context = script_context->v8_context(); | |
| 139 | |
| 140 // Only match events routed to this context's RenderFrame or ones that don't | |
| 141 // have a routingId in their filter. | |
| 142 std::set<EventFilter::MatcherID> matched_event_filters = | |
| 143 event_filter.MatchEvent(event_name, info, | |
| 144 script_context->GetRenderFrame()->GetRoutingID()); | |
| 145 v8::Local<v8::Array> array( | |
| 146 v8::Array::New(isolate, matched_event_filters.size())); | |
| 147 int i = 0; | |
| 148 for (EventFilter::MatcherID id : matched_event_filters) { | |
| 149 CHECK(array->CreateDataProperty(context, i++, v8::Integer::New(isolate, id)) | |
| 150 .ToChecked()); | |
| 151 } | |
| 152 | |
| 153 return array; | |
| 154 } | |
| 155 | |
| 156 } // namespace | 166 } // namespace |
| 157 | 167 |
| 158 EventBindings::EventBindings(ScriptContext* context) | 168 EventBindings::EventBindings(ScriptContext* context) |
| 159 : ObjectBackedNativeHandler(context) { | 169 : ObjectBackedNativeHandler(context) { |
| 160 RouteFunction("AttachEvent", base::Bind(&EventBindings::AttachEventHandler, | 170 RouteFunction("AttachEvent", base::Bind(&EventBindings::AttachEventHandler, |
| 161 base::Unretained(this))); | 171 base::Unretained(this))); |
| 162 RouteFunction("DetachEvent", base::Bind(&EventBindings::DetachEventHandler, | 172 RouteFunction("DetachEvent", base::Bind(&EventBindings::DetachEventHandler, |
| 163 base::Unretained(this))); | 173 base::Unretained(this))); |
| 164 RouteFunction( | 174 RouteFunction( |
| 165 "AttachFilteredEvent", | 175 "AttachFilteredEvent", |
| 166 base::Bind(&EventBindings::AttachFilteredEvent, base::Unretained(this))); | 176 base::Bind(&EventBindings::AttachFilteredEvent, base::Unretained(this))); |
| 167 RouteFunction("DetachFilteredEvent", | 177 RouteFunction("DetachFilteredEvent", |
| 168 base::Bind(&EventBindings::DetachFilteredEventHandler, | 178 base::Bind(&EventBindings::DetachFilteredEventHandler, |
| 169 base::Unretained(this))); | 179 base::Unretained(this))); |
| 180 RouteFunction("MatchAgainstEventFilter", |
| 181 base::Bind(&EventBindings::MatchAgainstEventFilter, |
| 182 base::Unretained(this))); |
| 170 RouteFunction( | 183 RouteFunction( |
| 171 "AttachUnmanagedEvent", | 184 "AttachUnmanagedEvent", |
| 172 base::Bind(&EventBindings::AttachUnmanagedEvent, base::Unretained(this))); | 185 base::Bind(&EventBindings::AttachUnmanagedEvent, base::Unretained(this))); |
| 173 RouteFunction( | 186 RouteFunction( |
| 174 "DetachUnmanagedEvent", | 187 "DetachUnmanagedEvent", |
| 175 base::Bind(&EventBindings::DetachUnmanagedEvent, base::Unretained(this))); | 188 base::Bind(&EventBindings::DetachUnmanagedEvent, base::Unretained(this))); |
| 176 | 189 |
| 177 // It's safe to use base::Unretained here because |context| will always | 190 // It's safe to use base::Unretained here because |context| will always |
| 178 // outlive us. | 191 // outlive us. |
| 179 context->AddInvalidationObserver( | 192 context->AddInvalidationObserver( |
| (...skipping 16 matching lines...) Expand all Loading... |
| 196 if (managed_iter != managed_listeners.end()) { | 209 if (managed_iter != managed_listeners.end()) { |
| 197 auto event_iter = managed_iter->second.find(event_name); | 210 auto event_iter = managed_iter->second.find(event_name); |
| 198 if (event_iter != managed_iter->second.end() && event_iter->second > 0) { | 211 if (event_iter != managed_iter->second.end() && event_iter->second > 0) { |
| 199 return true; | 212 return true; |
| 200 } | 213 } |
| 201 } | 214 } |
| 202 | 215 |
| 203 return false; | 216 return false; |
| 204 } | 217 } |
| 205 | 218 |
| 206 // static | |
| 207 void EventBindings::DispatchEventInContext( | |
| 208 const std::string& event_name, | |
| 209 const base::ListValue* event_args, | |
| 210 const base::DictionaryValue* filtering_info, | |
| 211 ScriptContext* context) { | |
| 212 v8::HandleScope handle_scope(context->isolate()); | |
| 213 v8::Context::Scope context_scope(context->v8_context()); | |
| 214 | |
| 215 v8::Local<v8::Array> listener_ids; | |
| 216 if (filtering_info && !filtering_info->empty()) | |
| 217 listener_ids = GetMatchingListeners(context, event_name, *filtering_info); | |
| 218 else | |
| 219 listener_ids = v8::Array::New(context->isolate()); | |
| 220 | |
| 221 std::unique_ptr<content::V8ValueConverter> converter( | |
| 222 content::V8ValueConverter::create()); | |
| 223 v8::Local<v8::Value> v8_args[] = { | |
| 224 gin::StringToSymbol(context->isolate(), event_name), | |
| 225 converter->ToV8Value(event_args, context->v8_context()), listener_ids, | |
| 226 }; | |
| 227 | |
| 228 context->module_system()->CallModuleMethodSafe( | |
| 229 kEventBindings, "dispatchEvent", arraysize(v8_args), v8_args); | |
| 230 } | |
| 231 | |
| 232 void EventBindings::AttachEventHandler( | 219 void EventBindings::AttachEventHandler( |
| 233 const v8::FunctionCallbackInfo<v8::Value>& args) { | 220 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 234 CHECK_EQ(1, args.Length()); | 221 CHECK_EQ(1, args.Length()); |
| 235 CHECK(args[0]->IsString()); | 222 CHECK(args[0]->IsString()); |
| 236 AttachEvent(*v8::String::Utf8Value(args[0])); | 223 AttachEvent(*v8::String::Utf8Value(args[0])); |
| 237 } | 224 } |
| 238 | 225 |
| 239 void EventBindings::AttachEvent(const std::string& event_name) { | 226 void EventBindings::AttachEvent(const std::string& event_name) { |
| 240 if (!context()->HasAccessOrThrowError(event_name)) | 227 if (!context()->HasAccessOrThrowError(event_name)) |
| 241 return; | 228 return; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 301 if (is_lazy_context) { | 288 if (is_lazy_context) { |
| 302 sender->Send(new ExtensionHostMsg_RemoveLazyListener( | 289 sender->Send(new ExtensionHostMsg_RemoveLazyListener( |
| 303 extension_id, event_name, worker_thread_id)); | 290 extension_id, event_name, worker_thread_id)); |
| 304 } | 291 } |
| 305 } | 292 } |
| 306 } | 293 } |
| 307 | 294 |
| 308 // MatcherID AttachFilteredEvent(string event_name, object filter) | 295 // MatcherID AttachFilteredEvent(string event_name, object filter) |
| 309 // event_name - Name of the event to attach. | 296 // event_name - Name of the event to attach. |
| 310 // filter - Which instances of the named event are we interested in. | 297 // filter - Which instances of the named event are we interested in. |
| 311 // returns the id assigned to the listener, which will be provided to calls to | 298 // returns the id assigned to the listener, which will be returned from calls |
| 312 // dispatchEvent(). | 299 // to MatchAgainstEventFilter where this listener matches. |
| 313 void EventBindings::AttachFilteredEvent( | 300 void EventBindings::AttachFilteredEvent( |
| 314 const v8::FunctionCallbackInfo<v8::Value>& args) { | 301 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 315 CHECK_EQ(2, args.Length()); | 302 CHECK_EQ(2, args.Length()); |
| 316 CHECK(args[0]->IsString()); | 303 CHECK(args[0]->IsString()); |
| 317 CHECK(args[1]->IsObject()); | 304 CHECK(args[1]->IsObject()); |
| 318 | 305 |
| 319 std::string event_name = *v8::String::Utf8Value(args[0]); | 306 std::string event_name = *v8::String::Utf8Value(args[0]); |
| 320 if (!context()->HasAccessOrThrowError(event_name)) | 307 if (!context()->HasAccessOrThrowError(event_name)) |
| 321 return; | 308 return; |
| 322 | 309 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 376 is_manual && ExtensionFrameHelper::IsContextForEventPage(context()); | 363 is_manual && ExtensionFrameHelper::IsContextForEventPage(context()); |
| 377 content::RenderThread::Get()->Send( | 364 content::RenderThread::Get()->Send( |
| 378 new ExtensionHostMsg_RemoveFilteredListener( | 365 new ExtensionHostMsg_RemoveFilteredListener( |
| 379 extension_id, event_name, *event_matcher->value(), remove_lazy)); | 366 extension_id, event_name, *event_matcher->value(), remove_lazy)); |
| 380 } | 367 } |
| 381 | 368 |
| 382 event_filter.RemoveEventMatcher(matcher_id); | 369 event_filter.RemoveEventMatcher(matcher_id); |
| 383 attached_matcher_ids_.erase(matcher_id); | 370 attached_matcher_ids_.erase(matcher_id); |
| 384 } | 371 } |
| 385 | 372 |
| 373 void EventBindings::MatchAgainstEventFilter( |
| 374 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 375 v8::Isolate* isolate = args.GetIsolate(); |
| 376 typedef std::set<EventFilter::MatcherID> MatcherIDs; |
| 377 EventFilter& event_filter = g_event_filter.Get(); |
| 378 std::string event_name = *v8::String::Utf8Value(args[0]); |
| 379 EventFilteringInfo info = |
| 380 ParseFromObject(args[1]->ToObject(isolate), isolate); |
| 381 // Only match events routed to this context's RenderFrame or ones that don't |
| 382 // have a routingId in their filter. |
| 383 MatcherIDs matched_event_filters = event_filter.MatchEvent( |
| 384 event_name, info, context()->GetRenderFrame()->GetRoutingID()); |
| 385 v8::Local<v8::Array> array( |
| 386 v8::Array::New(isolate, matched_event_filters.size())); |
| 387 int i = 0; |
| 388 for (MatcherIDs::iterator it = matched_event_filters.begin(); |
| 389 it != matched_event_filters.end(); |
| 390 ++it) { |
| 391 array->Set(v8::Integer::New(isolate, i++), v8::Integer::New(isolate, *it)); |
| 392 } |
| 393 args.GetReturnValue().Set(array); |
| 394 } |
| 395 |
| 386 void EventBindings::AttachUnmanagedEvent( | 396 void EventBindings::AttachUnmanagedEvent( |
| 387 const v8::FunctionCallbackInfo<v8::Value>& args) { | 397 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 388 v8::Isolate* isolate = args.GetIsolate(); | 398 v8::Isolate* isolate = args.GetIsolate(); |
| 389 v8::HandleScope handle_scope(isolate); | 399 v8::HandleScope handle_scope(isolate); |
| 390 CHECK_EQ(1, args.Length()); | 400 CHECK_EQ(1, args.Length()); |
| 391 CHECK(args[0]->IsString()); | 401 CHECK(args[0]->IsString()); |
| 392 std::string event_name = gin::V8ToString(args[0]); | 402 std::string event_name = gin::V8ToString(args[0]); |
| 393 g_unmanaged_listeners.Get()[context()].insert(event_name); | 403 g_unmanaged_listeners.Get()[context()].insert(event_name); |
| 394 } | 404 } |
| 395 | 405 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 434 for (int matcher_id : attached_matcher_ids_safe) { | 444 for (int matcher_id : attached_matcher_ids_safe) { |
| 435 DetachFilteredEvent(matcher_id, false /* is_manual */); | 445 DetachFilteredEvent(matcher_id, false /* is_manual */); |
| 436 } | 446 } |
| 437 DCHECK(attached_matcher_ids_.empty()) | 447 DCHECK(attached_matcher_ids_.empty()) |
| 438 << "Filtered events cannot be attached during invalidation"; | 448 << "Filtered events cannot be attached during invalidation"; |
| 439 | 449 |
| 440 g_unmanaged_listeners.Get().erase(context()); | 450 g_unmanaged_listeners.Get().erase(context()); |
| 441 } | 451 } |
| 442 | 452 |
| 443 } // namespace extensions | 453 } // namespace extensions |
| OLD | NEW |