| 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" |
| 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" |
| 30 #include "gin/converter.h" | 31 #include "gin/converter.h" |
| 31 #include "url/gurl.h" | 32 #include "url/gurl.h" |
| 32 | 33 |
| 33 namespace extensions { | 34 namespace extensions { |
| 34 | 35 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 81 } | 82 } |
| 82 | 83 |
| 83 // Decrements the number of event-listeners for the given |event_name| and | 84 // Decrements the number of event-listeners for the given |event_name| and |
| 84 // ScriptContext. Returns the count after the increment. | 85 // ScriptContext. Returns the count after the increment. |
| 85 int DecrementEventListenerCount(ScriptContext* script_context, | 86 int DecrementEventListenerCount(ScriptContext* script_context, |
| 86 const std::string& event_name) { | 87 const std::string& event_name) { |
| 87 return --g_listener_counts | 88 return --g_listener_counts |
| 88 .Get()[GetKeyForScriptContext(script_context)][event_name]; | 89 .Get()[GetKeyForScriptContext(script_context)][event_name]; |
| 89 } | 90 } |
| 90 | 91 |
| 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 | |
| 129 // Add a filter to |event_name| in |extension_id|, returning true if it | 92 // Add a filter to |event_name| in |extension_id|, returning true if it |
| 130 // was the first filter for that event in that extension. | 93 // was the first filter for that event in that extension. |
| 131 bool AddFilter(const std::string& event_name, | 94 bool AddFilter(const std::string& event_name, |
| 132 const std::string& extension_id, | 95 const std::string& extension_id, |
| 133 const base::DictionaryValue& filter) { | 96 const base::DictionaryValue& filter) { |
| 134 FilteredEventListenerKey key(extension_id, event_name); | 97 FilteredEventListenerKey key(extension_id, event_name); |
| 135 FilteredEventListenerCounts& all_counts = g_filtered_listener_counts.Get(); | 98 FilteredEventListenerCounts& all_counts = g_filtered_listener_counts.Get(); |
| 136 FilteredEventListenerCounts::const_iterator counts = all_counts.find(key); | 99 FilteredEventListenerCounts::const_iterator counts = all_counts.find(key); |
| 137 if (counts == all_counts.end()) { | 100 if (counts == all_counts.end()) { |
| 138 counts = | 101 counts = |
| (...skipping 17 matching lines...) Expand all Loading... |
| 156 // |filter|. If there are more equivalent filters, or if there weren't any in | 119 // |filter|. If there are more equivalent filters, or if there weren't any in |
| 157 // the first place, it returns false. | 120 // the first place, it returns false. |
| 158 if (counts->second->Remove(*filter)) { | 121 if (counts->second->Remove(*filter)) { |
| 159 if (counts->second->is_empty()) | 122 if (counts->second->is_empty()) |
| 160 all_counts.erase(counts); // Clean up if there are no more filters. | 123 all_counts.erase(counts); // Clean up if there are no more filters. |
| 161 return true; | 124 return true; |
| 162 } | 125 } |
| 163 return false; | 126 return false; |
| 164 } | 127 } |
| 165 | 128 |
| 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 |
| 166 } // namespace | 156 } // namespace |
| 167 | 157 |
| 168 EventBindings::EventBindings(ScriptContext* context) | 158 EventBindings::EventBindings(ScriptContext* context) |
| 169 : ObjectBackedNativeHandler(context) { | 159 : ObjectBackedNativeHandler(context) { |
| 170 RouteFunction("AttachEvent", base::Bind(&EventBindings::AttachEventHandler, | 160 RouteFunction("AttachEvent", base::Bind(&EventBindings::AttachEventHandler, |
| 171 base::Unretained(this))); | 161 base::Unretained(this))); |
| 172 RouteFunction("DetachEvent", base::Bind(&EventBindings::DetachEventHandler, | 162 RouteFunction("DetachEvent", base::Bind(&EventBindings::DetachEventHandler, |
| 173 base::Unretained(this))); | 163 base::Unretained(this))); |
| 174 RouteFunction( | 164 RouteFunction( |
| 175 "AttachFilteredEvent", | 165 "AttachFilteredEvent", |
| 176 base::Bind(&EventBindings::AttachFilteredEvent, base::Unretained(this))); | 166 base::Bind(&EventBindings::AttachFilteredEvent, base::Unretained(this))); |
| 177 RouteFunction("DetachFilteredEvent", | 167 RouteFunction("DetachFilteredEvent", |
| 178 base::Bind(&EventBindings::DetachFilteredEventHandler, | 168 base::Bind(&EventBindings::DetachFilteredEventHandler, |
| 179 base::Unretained(this))); | 169 base::Unretained(this))); |
| 180 RouteFunction("MatchAgainstEventFilter", | |
| 181 base::Bind(&EventBindings::MatchAgainstEventFilter, | |
| 182 base::Unretained(this))); | |
| 183 RouteFunction( | 170 RouteFunction( |
| 184 "AttachUnmanagedEvent", | 171 "AttachUnmanagedEvent", |
| 185 base::Bind(&EventBindings::AttachUnmanagedEvent, base::Unretained(this))); | 172 base::Bind(&EventBindings::AttachUnmanagedEvent, base::Unretained(this))); |
| 186 RouteFunction( | 173 RouteFunction( |
| 187 "DetachUnmanagedEvent", | 174 "DetachUnmanagedEvent", |
| 188 base::Bind(&EventBindings::DetachUnmanagedEvent, base::Unretained(this))); | 175 base::Bind(&EventBindings::DetachUnmanagedEvent, base::Unretained(this))); |
| 189 | 176 |
| 190 // It's safe to use base::Unretained here because |context| will always | 177 // It's safe to use base::Unretained here because |context| will always |
| 191 // outlive us. | 178 // outlive us. |
| 192 context->AddInvalidationObserver( | 179 context->AddInvalidationObserver( |
| (...skipping 16 matching lines...) Expand all Loading... |
| 209 if (managed_iter != managed_listeners.end()) { | 196 if (managed_iter != managed_listeners.end()) { |
| 210 auto event_iter = managed_iter->second.find(event_name); | 197 auto event_iter = managed_iter->second.find(event_name); |
| 211 if (event_iter != managed_iter->second.end() && event_iter->second > 0) { | 198 if (event_iter != managed_iter->second.end() && event_iter->second > 0) { |
| 212 return true; | 199 return true; |
| 213 } | 200 } |
| 214 } | 201 } |
| 215 | 202 |
| 216 return false; | 203 return false; |
| 217 } | 204 } |
| 218 | 205 |
| 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 |
| 219 void EventBindings::AttachEventHandler( | 232 void EventBindings::AttachEventHandler( |
| 220 const v8::FunctionCallbackInfo<v8::Value>& args) { | 233 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 221 CHECK_EQ(1, args.Length()); | 234 CHECK_EQ(1, args.Length()); |
| 222 CHECK(args[0]->IsString()); | 235 CHECK(args[0]->IsString()); |
| 223 AttachEvent(*v8::String::Utf8Value(args[0])); | 236 AttachEvent(*v8::String::Utf8Value(args[0])); |
| 224 } | 237 } |
| 225 | 238 |
| 226 void EventBindings::AttachEvent(const std::string& event_name) { | 239 void EventBindings::AttachEvent(const std::string& event_name) { |
| 227 if (!context()->HasAccessOrThrowError(event_name)) | 240 if (!context()->HasAccessOrThrowError(event_name)) |
| 228 return; | 241 return; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 if (is_lazy_context) { | 301 if (is_lazy_context) { |
| 289 sender->Send(new ExtensionHostMsg_RemoveLazyListener( | 302 sender->Send(new ExtensionHostMsg_RemoveLazyListener( |
| 290 extension_id, event_name, worker_thread_id)); | 303 extension_id, event_name, worker_thread_id)); |
| 291 } | 304 } |
| 292 } | 305 } |
| 293 } | 306 } |
| 294 | 307 |
| 295 // MatcherID AttachFilteredEvent(string event_name, object filter) | 308 // MatcherID AttachFilteredEvent(string event_name, object filter) |
| 296 // event_name - Name of the event to attach. | 309 // event_name - Name of the event to attach. |
| 297 // filter - Which instances of the named event are we interested in. | 310 // filter - Which instances of the named event are we interested in. |
| 298 // returns the id assigned to the listener, which will be returned from calls | 311 // returns the id assigned to the listener, which will be provided to calls to |
| 299 // to MatchAgainstEventFilter where this listener matches. | 312 // dispatchEvent(). |
| 300 void EventBindings::AttachFilteredEvent( | 313 void EventBindings::AttachFilteredEvent( |
| 301 const v8::FunctionCallbackInfo<v8::Value>& args) { | 314 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 302 CHECK_EQ(2, args.Length()); | 315 CHECK_EQ(2, args.Length()); |
| 303 CHECK(args[0]->IsString()); | 316 CHECK(args[0]->IsString()); |
| 304 CHECK(args[1]->IsObject()); | 317 CHECK(args[1]->IsObject()); |
| 305 | 318 |
| 306 std::string event_name = *v8::String::Utf8Value(args[0]); | 319 std::string event_name = *v8::String::Utf8Value(args[0]); |
| 307 if (!context()->HasAccessOrThrowError(event_name)) | 320 if (!context()->HasAccessOrThrowError(event_name)) |
| 308 return; | 321 return; |
| 309 | 322 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 is_manual && ExtensionFrameHelper::IsContextForEventPage(context()); | 376 is_manual && ExtensionFrameHelper::IsContextForEventPage(context()); |
| 364 content::RenderThread::Get()->Send( | 377 content::RenderThread::Get()->Send( |
| 365 new ExtensionHostMsg_RemoveFilteredListener( | 378 new ExtensionHostMsg_RemoveFilteredListener( |
| 366 extension_id, event_name, *event_matcher->value(), remove_lazy)); | 379 extension_id, event_name, *event_matcher->value(), remove_lazy)); |
| 367 } | 380 } |
| 368 | 381 |
| 369 event_filter.RemoveEventMatcher(matcher_id); | 382 event_filter.RemoveEventMatcher(matcher_id); |
| 370 attached_matcher_ids_.erase(matcher_id); | 383 attached_matcher_ids_.erase(matcher_id); |
| 371 } | 384 } |
| 372 | 385 |
| 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 | |
| 396 void EventBindings::AttachUnmanagedEvent( | 386 void EventBindings::AttachUnmanagedEvent( |
| 397 const v8::FunctionCallbackInfo<v8::Value>& args) { | 387 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 398 v8::Isolate* isolate = args.GetIsolate(); | 388 v8::Isolate* isolate = args.GetIsolate(); |
| 399 v8::HandleScope handle_scope(isolate); | 389 v8::HandleScope handle_scope(isolate); |
| 400 CHECK_EQ(1, args.Length()); | 390 CHECK_EQ(1, args.Length()); |
| 401 CHECK(args[0]->IsString()); | 391 CHECK(args[0]->IsString()); |
| 402 std::string event_name = gin::V8ToString(args[0]); | 392 std::string event_name = gin::V8ToString(args[0]); |
| 403 g_unmanaged_listeners.Get()[context()].insert(event_name); | 393 g_unmanaged_listeners.Get()[context()].insert(event_name); |
| 404 } | 394 } |
| 405 | 395 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 444 for (int matcher_id : attached_matcher_ids_safe) { | 434 for (int matcher_id : attached_matcher_ids_safe) { |
| 445 DetachFilteredEvent(matcher_id, false /* is_manual */); | 435 DetachFilteredEvent(matcher_id, false /* is_manual */); |
| 446 } | 436 } |
| 447 DCHECK(attached_matcher_ids_.empty()) | 437 DCHECK(attached_matcher_ids_.empty()) |
| 448 << "Filtered events cannot be attached during invalidation"; | 438 << "Filtered events cannot be attached during invalidation"; |
| 449 | 439 |
| 450 g_unmanaged_listeners.Get().erase(context()); | 440 g_unmanaged_listeners.Get().erase(context()); |
| 451 } | 441 } |
| 452 | 442 |
| 453 } // namespace extensions | 443 } // namespace extensions |
| OLD | NEW |