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 |