| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/native_extension_bindings_system.h" | 5 #include "extensions/renderer/native_extension_bindings_system.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/memory/ptr_util.h" | 8 #include "base/memory/ptr_util.h" |
| 9 #include "content/public/common/content_switches.h" | 9 #include "content/public/common/content_switches.h" |
| 10 #include "extensions/common/constants.h" | 10 #include "extensions/common/constants.h" |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 131 const SendEventListenerIPCMethod& send_event_listener_ipc) | 131 const SendEventListenerIPCMethod& send_event_listener_ipc) |
| 132 : send_request_ipc_(send_request_ipc), | 132 : send_request_ipc_(send_request_ipc), |
| 133 send_event_listener_ipc_(send_event_listener_ipc), | 133 send_event_listener_ipc_(send_event_listener_ipc), |
| 134 api_system_( | 134 api_system_( |
| 135 base::Bind(&CallJsFunction), | 135 base::Bind(&CallJsFunction), |
| 136 base::Bind(&CallJsFunctionSync), | 136 base::Bind(&CallJsFunctionSync), |
| 137 base::Bind(&GetAPISchema), | 137 base::Bind(&GetAPISchema), |
| 138 base::Bind(&NativeExtensionBindingsSystem::SendRequest, | 138 base::Bind(&NativeExtensionBindingsSystem::SendRequest, |
| 139 base::Unretained(this)), | 139 base::Unretained(this)), |
| 140 base::Bind(&NativeExtensionBindingsSystem::OnEventListenerChanged, | 140 base::Bind(&NativeExtensionBindingsSystem::OnEventListenerChanged, |
| 141 base::Unretained(this))), | 141 base::Unretained(this)), |
| 142 APILastError(base::Bind(&GetRuntime))), |
| 142 weak_factory_(this) {} | 143 weak_factory_(this) {} |
| 143 | 144 |
| 144 NativeExtensionBindingsSystem::~NativeExtensionBindingsSystem() {} | 145 NativeExtensionBindingsSystem::~NativeExtensionBindingsSystem() {} |
| 145 | 146 |
| 146 void NativeExtensionBindingsSystem::DidCreateScriptContext( | 147 void NativeExtensionBindingsSystem::DidCreateScriptContext( |
| 147 ScriptContext* context) {} | 148 ScriptContext* context) {} |
| 148 | 149 |
| 149 void NativeExtensionBindingsSystem::WillReleaseScriptContext( | 150 void NativeExtensionBindingsSystem::WillReleaseScriptContext( |
| 150 ScriptContext* context) {} | 151 ScriptContext* context) {} |
| 151 | 152 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 // creation, but also when e.g. permissions change. We need to be checking | 195 // creation, but also when e.g. permissions change. We need to be checking |
| 195 // for whether or not the API already exists on the object as well as | 196 // for whether or not the API already exists on the object as well as |
| 196 // if we need to remove any existing APIs. | 197 // if we need to remove any existing APIs. |
| 197 if (!context->IsAnyFeatureAvailableToContext(*map_entry.second, | 198 if (!context->IsAnyFeatureAvailableToContext(*map_entry.second, |
| 198 CheckAliasStatus::NOT_ALLOWED)) | 199 CheckAliasStatus::NOT_ALLOWED)) |
| 199 continue; | 200 continue; |
| 200 | 201 |
| 201 v8::Local<v8::String> api_name = | 202 v8::Local<v8::String> api_name = |
| 202 gin::StringToSymbol(v8_context->GetIsolate(), map_entry.first); | 203 gin::StringToSymbol(v8_context->GetIsolate(), map_entry.first); |
| 203 v8::Maybe<bool> success = chrome->SetAccessor( | 204 v8::Maybe<bool> success = chrome->SetAccessor( |
| 204 v8_context, api_name, &GetAPIHelper, nullptr, api_name); | 205 v8_context, api_name, &BindingAccessor, nullptr, api_name); |
| 205 if (!success.IsJust() || !success.FromJust()) { | 206 if (!success.IsJust() || !success.FromJust()) { |
| 206 LOG(ERROR) << "Failed to create API on Chrome object."; | 207 LOG(ERROR) << "Failed to create API on Chrome object."; |
| 207 return; | 208 return; |
| 208 } | 209 } |
| 209 } | 210 } |
| 210 } | 211 } |
| 211 | 212 |
| 212 void NativeExtensionBindingsSystem::DispatchEventInContext( | 213 void NativeExtensionBindingsSystem::DispatchEventInContext( |
| 213 const std::string& event_name, | 214 const std::string& event_name, |
| 214 const base::ListValue* event_args, | 215 const base::ListValue* event_args, |
| 215 const base::DictionaryValue* filtering_info, | 216 const base::DictionaryValue* filtering_info, |
| 216 ScriptContext* context) { | 217 ScriptContext* context) { |
| 217 v8::HandleScope handle_scope(context->isolate()); | 218 v8::HandleScope handle_scope(context->isolate()); |
| 218 v8::Context::Scope context_scope(context->v8_context()); | 219 v8::Context::Scope context_scope(context->v8_context()); |
| 219 // TODO(devlin): Take into account |filtering_info|. | 220 // TODO(devlin): Take into account |filtering_info|. |
| 220 api_system_.FireEventInContext(event_name, context->v8_context(), | 221 api_system_.FireEventInContext(event_name, context->v8_context(), |
| 221 *event_args); | 222 *event_args); |
| 222 } | 223 } |
| 223 | 224 |
| 224 void NativeExtensionBindingsSystem::HandleResponse( | 225 void NativeExtensionBindingsSystem::HandleResponse( |
| 225 int request_id, | 226 int request_id, |
| 226 bool success, | 227 bool success, |
| 227 const base::ListValue& response, | 228 const base::ListValue& response, |
| 228 const std::string& error) { | 229 const std::string& error) { |
| 229 api_system_.CompleteRequest(request_id, response); | 230 api_system_.CompleteRequest(request_id, response, error); |
| 230 } | 231 } |
| 231 | 232 |
| 232 RequestSender* NativeExtensionBindingsSystem::GetRequestSender() { | 233 RequestSender* NativeExtensionBindingsSystem::GetRequestSender() { |
| 233 return nullptr; | 234 return nullptr; |
| 234 } | 235 } |
| 235 | 236 |
| 236 // static | 237 void NativeExtensionBindingsSystem::BindingAccessor( |
| 237 void NativeExtensionBindingsSystem::GetAPIHelper( | |
| 238 v8::Local<v8::Name> name, | 238 v8::Local<v8::Name> name, |
| 239 const v8::PropertyCallbackInfo<v8::Value>& info) { | 239 const v8::PropertyCallbackInfo<v8::Value>& info) { |
| 240 v8::Isolate* isolate = info.GetIsolate(); | 240 v8::Isolate* isolate = info.GetIsolate(); |
| 241 v8::HandleScope handle_scope(isolate); | 241 v8::HandleScope handle_scope(isolate); |
| 242 v8::Local<v8::Context> context = info.Holder()->CreationContext(); | 242 v8::Local<v8::Context> context = info.Holder()->CreationContext(); |
| 243 |
| 244 // We use info.Data() to store a real name here instead of using the provided |
| 245 // one to handle any weirdness from the caller (non-existent strings, etc). |
| 246 v8::Local<v8::String> api_name = info.Data().As<v8::String>(); |
| 247 v8::Local<v8::Object> binding = GetAPIHelper(context, api_name); |
| 248 if (!binding.IsEmpty()) |
| 249 info.GetReturnValue().Set(binding); |
| 250 } |
| 251 |
| 252 // static |
| 253 v8::Local<v8::Object> NativeExtensionBindingsSystem::GetAPIHelper( |
| 254 v8::Local<v8::Context> context, |
| 255 v8::Local<v8::String> api_name) { |
| 243 gin::PerContextData* per_context_data = gin::PerContextData::From(context); | 256 gin::PerContextData* per_context_data = gin::PerContextData::From(context); |
| 244 if (!per_context_data) | 257 if (!per_context_data) |
| 245 return; // Context is shutting down. | 258 return v8::Local<v8::Object>(); // Context is shutting down. |
| 246 BindingsSystemPerContextData* data = | 259 BindingsSystemPerContextData* data = |
| 247 static_cast<BindingsSystemPerContextData*>( | 260 static_cast<BindingsSystemPerContextData*>( |
| 248 per_context_data->GetUserData(kBindingsSystemPerContextKey)); | 261 per_context_data->GetUserData(kBindingsSystemPerContextKey)); |
| 249 CHECK(data); | 262 CHECK(data); |
| 250 if (!data->bindings_system) { | 263 if (!data->bindings_system) { |
| 251 NOTREACHED() << "Context outlived bindings system."; | 264 NOTREACHED() << "Context outlived bindings system."; |
| 252 return; | 265 return v8::Local<v8::Object>(); |
| 253 } | 266 } |
| 254 | 267 |
| 268 v8::Isolate* isolate = context->GetIsolate(); |
| 255 v8::Local<v8::Object> apis; | 269 v8::Local<v8::Object> apis; |
| 256 if (data->api_object.IsEmpty()) { | 270 if (data->api_object.IsEmpty()) { |
| 257 apis = v8::Object::New(isolate); | 271 apis = v8::Object::New(isolate); |
| 258 data->api_object = v8::Global<v8::Object>(isolate, apis); | 272 data->api_object = v8::Global<v8::Object>(isolate, apis); |
| 259 } else { | 273 } else { |
| 260 apis = data->api_object.Get(isolate); | 274 apis = data->api_object.Get(isolate); |
| 261 } | 275 } |
| 262 | 276 |
| 263 // We use info.Data() to store a real name here instead of using the provided | 277 v8::Local<v8::Object> result; |
| 264 // one to handle any weirdness from the caller (non-existent strings, etc). | |
| 265 v8::Local<v8::String> api_name = info.Data().As<v8::String>(); | |
| 266 v8::Local<v8::Value> result; | |
| 267 v8::Maybe<bool> has_property = apis->HasRealNamedProperty(context, api_name); | 278 v8::Maybe<bool> has_property = apis->HasRealNamedProperty(context, api_name); |
| 268 if (!has_property.IsJust()) | 279 if (!has_property.IsJust()) |
| 269 return; | 280 return v8::Local<v8::Object>(); |
| 270 | 281 |
| 271 if (has_property.FromJust()) { | 282 if (has_property.FromJust()) { |
| 272 result = apis->GetRealNamedProperty(context, api_name).ToLocalChecked(); | 283 v8::Local<v8::Value> value = |
| 284 apis->GetRealNamedProperty(context, api_name).ToLocalChecked(); |
| 285 DCHECK(value->IsObject()); |
| 286 result = value.As<v8::Object>(); |
| 273 } else { | 287 } else { |
| 274 ScriptContext* script_context = | 288 ScriptContext* script_context = |
| 275 ScriptContextSet::GetContextByV8Context(context); | 289 ScriptContextSet::GetContextByV8Context(context); |
| 276 std::string api_name_string; | 290 std::string api_name_string; |
| 277 CHECK(gin::Converter<std::string>::FromV8(isolate, api_name, | 291 CHECK(gin::Converter<std::string>::FromV8(isolate, api_name, |
| 278 &api_name_string)); | 292 &api_name_string)); |
| 279 v8::Local<v8::Object> hooks_interface; | 293 v8::Local<v8::Object> hooks_interface; |
| 280 APIBindingsSystem& api_system = data->bindings_system->api_system_; | 294 APIBindingsSystem& api_system = data->bindings_system->api_system_; |
| 281 result = api_system.CreateAPIInstance( | 295 result = api_system.CreateAPIInstance( |
| 282 api_name_string, context, isolate, | 296 api_name_string, context, isolate, |
| 283 base::Bind(&IsAPIMethodAvailable, script_context), &hooks_interface); | 297 base::Bind(&IsAPIMethodAvailable, script_context), &hooks_interface); |
| 284 | 298 |
| 285 gin::Handle<APIBindingBridge> bridge_handle = gin::CreateHandle( | 299 gin::Handle<APIBindingBridge> bridge_handle = gin::CreateHandle( |
| 286 isolate, | 300 isolate, |
| 287 new APIBindingBridge(context, result, hooks_interface, | 301 new APIBindingBridge(context, result, hooks_interface, |
| 288 script_context->GetExtensionID(), | 302 script_context->GetExtensionID(), |
| 289 script_context->GetContextTypeDescription(), | 303 script_context->GetContextTypeDescription(), |
| 290 base::Bind(&CallJsFunction))); | 304 base::Bind(&CallJsFunction))); |
| 291 v8::Local<v8::Value> native_api_bridge = bridge_handle.ToV8(); | 305 v8::Local<v8::Value> native_api_bridge = bridge_handle.ToV8(); |
| 292 | 306 |
| 293 script_context->module_system()->OnNativeBindingCreated(api_name_string, | 307 script_context->module_system()->OnNativeBindingCreated(api_name_string, |
| 294 native_api_bridge); | 308 native_api_bridge); |
| 295 | 309 |
| 296 v8::Maybe<bool> success = | 310 v8::Maybe<bool> success = |
| 297 apis->CreateDataProperty(context, api_name, result); | 311 apis->CreateDataProperty(context, api_name, result); |
| 298 if (!success.IsJust() || !success.FromJust()) | 312 if (!success.IsJust() || !success.FromJust()) |
| 299 return; | 313 return v8::Local<v8::Object>(); |
| 300 } | 314 } |
| 301 info.GetReturnValue().Set(result); | 315 return result; |
| 316 } |
| 317 |
| 318 v8::Local<v8::Object> NativeExtensionBindingsSystem::GetRuntime( |
| 319 v8::Local<v8::Context> context) { |
| 320 return GetAPIHelper(context, |
| 321 gin::StringToSymbol(context->GetIsolate(), "runtime")); |
| 302 } | 322 } |
| 303 | 323 |
| 304 void NativeExtensionBindingsSystem::SendRequest( | 324 void NativeExtensionBindingsSystem::SendRequest( |
| 305 std::unique_ptr<APIBinding::Request> request, | 325 std::unique_ptr<APIBinding::Request> request, |
| 306 v8::Local<v8::Context> context) { | 326 v8::Local<v8::Context> context) { |
| 307 ScriptContext* script_context = | 327 ScriptContext* script_context = |
| 308 ScriptContextSet::GetContextByV8Context(context); | 328 ScriptContextSet::GetContextByV8Context(context); |
| 309 | 329 |
| 310 GURL url; | 330 GURL url; |
| 311 blink::WebLocalFrame* frame = script_context->web_frame(); | 331 blink::WebLocalFrame* frame = script_context->web_frame(); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 331 | 351 |
| 332 void NativeExtensionBindingsSystem::OnEventListenerChanged( | 352 void NativeExtensionBindingsSystem::OnEventListenerChanged( |
| 333 const std::string& event_name, | 353 const std::string& event_name, |
| 334 binding::EventListenersChanged change, | 354 binding::EventListenersChanged change, |
| 335 v8::Local<v8::Context> context) { | 355 v8::Local<v8::Context> context) { |
| 336 send_event_listener_ipc_.Run( | 356 send_event_listener_ipc_.Run( |
| 337 change, ScriptContextSet::GetContextByV8Context(context), event_name); | 357 change, ScriptContextSet::GetContextByV8Context(context), event_name); |
| 338 } | 358 } |
| 339 | 359 |
| 340 } // namespace extensions | 360 } // namespace extensions |
| OLD | NEW |