 Chromium Code Reviews
 Chromium Code Reviews Issue 2657613005:
  [Extensions Bindings] Add chrome.runtime.lastError support  (Closed)
    
  
    Issue 2657613005:
  [Extensions Bindings] Add chrome.runtime.lastError support  (Closed) 
  | 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 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 319 const SendEventListenerIPCMethod& send_event_listener_ipc) | 319 const SendEventListenerIPCMethod& send_event_listener_ipc) | 
| 320 : send_request_ipc_(send_request_ipc), | 320 : send_request_ipc_(send_request_ipc), | 
| 321 send_event_listener_ipc_(send_event_listener_ipc), | 321 send_event_listener_ipc_(send_event_listener_ipc), | 
| 322 api_system_( | 322 api_system_( | 
| 323 base::Bind(&CallJsFunction), | 323 base::Bind(&CallJsFunction), | 
| 324 base::Bind(&CallJsFunctionSync), | 324 base::Bind(&CallJsFunctionSync), | 
| 325 base::Bind(&GetAPISchema), | 325 base::Bind(&GetAPISchema), | 
| 326 base::Bind(&NativeExtensionBindingsSystem::SendRequest, | 326 base::Bind(&NativeExtensionBindingsSystem::SendRequest, | 
| 327 base::Unretained(this)), | 327 base::Unretained(this)), | 
| 328 base::Bind(&NativeExtensionBindingsSystem::OnEventListenerChanged, | 328 base::Bind(&NativeExtensionBindingsSystem::OnEventListenerChanged, | 
| 329 base::Unretained(this))), | 329 base::Unretained(this)), | 
| 330 APILastError(base::Bind(&GetRuntime))), | |
| 330 weak_factory_(this) {} | 331 weak_factory_(this) {} | 
| 331 | 332 | 
| 332 NativeExtensionBindingsSystem::~NativeExtensionBindingsSystem() {} | 333 NativeExtensionBindingsSystem::~NativeExtensionBindingsSystem() {} | 
| 333 | 334 | 
| 334 void NativeExtensionBindingsSystem::DidCreateScriptContext( | 335 void NativeExtensionBindingsSystem::DidCreateScriptContext( | 
| 335 ScriptContext* context) {} | 336 ScriptContext* context) {} | 
| 336 | 337 | 
| 337 void NativeExtensionBindingsSystem::WillReleaseScriptContext( | 338 void NativeExtensionBindingsSystem::WillReleaseScriptContext( | 
| 338 ScriptContext* context) {} | 339 ScriptContext* context) {} | 
| 339 | 340 | 
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 396 // expose this under the name of the feature (e.g., 'tabs'), but in some | 397 // expose this under the name of the feature (e.g., 'tabs'), but in some | 
| 397 // cases, this will be a prefixed API, such as 'app.runtime'. Find what the | 398 // cases, this will be a prefixed API, such as 'app.runtime'. Find what the | 
| 398 // property on the chrome object is named, and use that. So in the case of | 399 // property on the chrome object is named, and use that. So in the case of | 
| 399 // 'app.runtime', we surface a getter for simply 'app'. | 400 // 'app.runtime', we surface a getter for simply 'app'. | 
| 400 base::StringPiece accessor_name = | 401 base::StringPiece accessor_name = | 
| 401 GetFirstDifferentAPIName(map_entry.first, base::StringPiece()); | 402 GetFirstDifferentAPIName(map_entry.first, base::StringPiece()); | 
| 402 last_accessor = accessor_name; | 403 last_accessor = accessor_name; | 
| 403 v8::Local<v8::String> api_name = | 404 v8::Local<v8::String> api_name = | 
| 404 gin::StringToSymbol(v8_context->GetIsolate(), accessor_name); | 405 gin::StringToSymbol(v8_context->GetIsolate(), accessor_name); | 
| 405 v8::Maybe<bool> success = chrome->SetAccessor( | 406 v8::Maybe<bool> success = chrome->SetAccessor( | 
| 406 v8_context, api_name, &GetAPIHelper, nullptr, api_name); | 407 v8_context, api_name, &BindingAccessor, nullptr, api_name); | 
| 407 if (!success.IsJust() || !success.FromJust()) { | 408 if (!success.IsJust() || !success.FromJust()) { | 
| 408 LOG(ERROR) << "Failed to create API on Chrome object."; | 409 LOG(ERROR) << "Failed to create API on Chrome object."; | 
| 409 return; | 410 return; | 
| 410 } | 411 } | 
| 411 } | 412 } | 
| 412 } | 413 } | 
| 413 | 414 | 
| 414 void NativeExtensionBindingsSystem::DispatchEventInContext( | 415 void NativeExtensionBindingsSystem::DispatchEventInContext( | 
| 415 const std::string& event_name, | 416 const std::string& event_name, | 
| 416 const base::ListValue* event_args, | 417 const base::ListValue* event_args, | 
| 417 const base::DictionaryValue* filtering_info, | 418 const base::DictionaryValue* filtering_info, | 
| 418 ScriptContext* context) { | 419 ScriptContext* context) { | 
| 419 v8::HandleScope handle_scope(context->isolate()); | 420 v8::HandleScope handle_scope(context->isolate()); | 
| 420 v8::Context::Scope context_scope(context->v8_context()); | 421 v8::Context::Scope context_scope(context->v8_context()); | 
| 421 // TODO(devlin): Take into account |filtering_info|. | 422 // TODO(devlin): Take into account |filtering_info|. | 
| 422 api_system_.FireEventInContext(event_name, context->v8_context(), | 423 api_system_.FireEventInContext(event_name, context->v8_context(), | 
| 423 *event_args); | 424 *event_args); | 
| 424 } | 425 } | 
| 425 | 426 | 
| 426 void NativeExtensionBindingsSystem::HandleResponse( | 427 void NativeExtensionBindingsSystem::HandleResponse( | 
| 427 int request_id, | 428 int request_id, | 
| 428 bool success, | 429 bool success, | 
| 429 const base::ListValue& response, | 430 const base::ListValue& response, | 
| 430 const std::string& error) { | 431 const std::string& error) { | 
| 431 api_system_.CompleteRequest(request_id, response); | 432 api_system_.CompleteRequest(request_id, response, error); | 
| 432 } | 433 } | 
| 433 | 434 | 
| 434 RequestSender* NativeExtensionBindingsSystem::GetRequestSender() { | 435 RequestSender* NativeExtensionBindingsSystem::GetRequestSender() { | 
| 435 return nullptr; | 436 return nullptr; | 
| 436 } | 437 } | 
| 437 | 438 | 
| 438 // static | 439 void NativeExtensionBindingsSystem::BindingAccessor( | 
| 439 void NativeExtensionBindingsSystem::GetAPIHelper( | |
| 440 v8::Local<v8::Name> name, | 440 v8::Local<v8::Name> name, | 
| 441 const v8::PropertyCallbackInfo<v8::Value>& info) { | 441 const v8::PropertyCallbackInfo<v8::Value>& info) { | 
| 442 v8::Isolate* isolate = info.GetIsolate(); | 442 v8::Isolate* isolate = info.GetIsolate(); | 
| 443 v8::HandleScope handle_scope(isolate); | 443 v8::HandleScope handle_scope(isolate); | 
| 444 v8::Local<v8::Context> context = info.Holder()->CreationContext(); | 444 v8::Local<v8::Context> context = info.Holder()->CreationContext(); | 
| 445 | |
| 446 // We use info.Data() to store a real name here instead of using the provided | |
| 447 // one to handle any weirdness from the caller (non-existent strings, etc). | |
| 448 v8::Local<v8::String> api_name = info.Data().As<v8::String>(); | |
| 449 v8::Local<v8::Object> binding = GetAPIHelper(context, api_name); | |
| 450 if (!binding.IsEmpty()) | |
| 451 info.GetReturnValue().Set(binding); | |
| 452 } | |
| 453 | |
| 454 // static | |
| 455 v8::Local<v8::Object> NativeExtensionBindingsSystem::GetAPIHelper( | |
| 456 v8::Local<v8::Context> context, | |
| 457 v8::Local<v8::String> api_name) { | |
| 445 BindingsSystemPerContextData* data = GetBindingsDataFromContext(context); | 458 BindingsSystemPerContextData* data = GetBindingsDataFromContext(context); | 
| 446 if (!data) | 459 if (!data) | 
| 447 return; | 460 return v8::Local<v8::Object>(); | 
| 448 | 461 | 
| 462 v8::Isolate* isolate = context->GetIsolate(); | |
| 449 v8::Local<v8::Object> apis; | 463 v8::Local<v8::Object> apis; | 
| 450 if (data->api_object.IsEmpty()) { | 464 if (data->api_object.IsEmpty()) { | 
| 451 apis = v8::Object::New(isolate); | 465 apis = v8::Object::New(isolate); | 
| 452 data->api_object = v8::Global<v8::Object>(isolate, apis); | 466 data->api_object = v8::Global<v8::Object>(isolate, apis); | 
| 453 if (data->bindings_system->get_internal_api_.IsEmpty()) { | 467 if (data->bindings_system->get_internal_api_.IsEmpty()) { | 
| 454 data->bindings_system->get_internal_api_.Set( | 468 data->bindings_system->get_internal_api_.Set( | 
| 455 isolate, v8::FunctionTemplate::New( | 469 isolate, v8::FunctionTemplate::New( | 
| 456 isolate, &NativeExtensionBindingsSystem::GetInternalAPI, | 470 isolate, &NativeExtensionBindingsSystem::GetInternalAPI, | 
| 457 v8::Local<v8::Value>(), v8::Local<v8::Signature>(), 0, | 471 v8::Local<v8::Value>(), v8::Local<v8::Signature>(), 0, | 
| 458 v8::ConstructorBehavior::kThrow)); | 472 v8::ConstructorBehavior::kThrow)); | 
| 459 } | 473 } | 
| 460 } else { | 474 } else { | 
| 461 apis = data->api_object.Get(isolate); | 475 apis = data->api_object.Get(isolate); | 
| 462 } | 476 } | 
| 463 v8::Local<v8::Function> get_internal_api = | 477 v8::Local<v8::Function> get_internal_api = | 
| 464 data->bindings_system->get_internal_api_.Get(isolate) | 478 data->bindings_system->get_internal_api_.Get(isolate) | 
| 465 ->GetFunction(context) | 479 ->GetFunction(context) | 
| 466 .ToLocalChecked(); | 480 .ToLocalChecked(); | 
| 467 | 481 | 
| 468 // We use info.Data() to store a real name here instead of using the provided | 482 v8::Local<v8::Object> result; | 
| 
jbroman
2017/02/13 19:41:27
nit: Does this variable still need to exist? Looks
 
Devlin
2017/02/14 04:57:08
Done.
 | |
| 469 // one to handle any weirdness from the caller (non-existent strings, etc). | |
| 470 v8::Local<v8::String> api_name = info.Data().As<v8::String>(); | |
| 471 v8::Local<v8::Value> result; | |
| 472 v8::Maybe<bool> has_property = apis->HasRealNamedProperty(context, api_name); | 483 v8::Maybe<bool> has_property = apis->HasRealNamedProperty(context, api_name); | 
| 473 if (!has_property.IsJust()) | 484 if (!has_property.IsJust()) | 
| 474 return; | 485 return v8::Local<v8::Object>(); | 
| 475 | 486 | 
| 476 if (has_property.FromJust()) { | 487 if (has_property.FromJust()) { | 
| 477 result = apis->GetRealNamedProperty(context, api_name).ToLocalChecked(); | 488 v8::Local<v8::Value> value = | 
| 489 apis->GetRealNamedProperty(context, api_name).ToLocalChecked(); | |
| 490 DCHECK(value->IsObject()); | |
| 491 result = value.As<v8::Object>(); | |
| 478 } else { | 492 } else { | 
| 479 ScriptContext* script_context = | 493 ScriptContext* script_context = | 
| 480 ScriptContextSet::GetContextByV8Context(context); | 494 ScriptContextSet::GetContextByV8Context(context); | 
| 481 std::string api_name_string; | 495 std::string api_name_string; | 
| 482 CHECK(gin::Converter<std::string>::FromV8(isolate, api_name, | 496 CHECK(gin::Converter<std::string>::FromV8(isolate, api_name, | 
| 483 &api_name_string)); | 497 &api_name_string)); | 
| 484 | 498 | 
| 485 v8::Local<v8::Object> root_binding = CreateFullBinding( | 499 v8::Local<v8::Object> root_binding = CreateFullBinding( | 
| 486 context, script_context, &data->bindings_system->api_system_, | 500 context, script_context, &data->bindings_system->api_system_, | 
| 487 FeatureProvider::GetAPIFeatures(), api_name_string, get_internal_api); | 501 FeatureProvider::GetAPIFeatures(), api_name_string, get_internal_api); | 
| 488 if (root_binding.IsEmpty()) | 502 if (root_binding.IsEmpty()) | 
| 489 return; | 503 return v8::Local<v8::Object>(); | 
| 490 | 504 | 
| 491 v8::Maybe<bool> success = | 505 v8::Maybe<bool> success = | 
| 492 apis->CreateDataProperty(context, api_name, root_binding); | 506 apis->CreateDataProperty(context, api_name, root_binding); | 
| 493 if (!success.IsJust() || !success.FromJust()) | 507 if (!success.IsJust() || !success.FromJust()) | 
| 494 return; | 508 return v8::Local<v8::Object>(); | 
| 495 | 509 | 
| 496 result = root_binding; | 510 result = root_binding; | 
| 497 } | 511 } | 
| 498 | 512 | 
| 499 info.GetReturnValue().Set(result); | 513 return result; | 
| 514 } | |
| 515 | |
| 516 v8::Local<v8::Object> NativeExtensionBindingsSystem::GetRuntime( | |
| 517 v8::Local<v8::Context> context) { | |
| 518 return GetAPIHelper(context, | |
| 519 gin::StringToSymbol(context->GetIsolate(), "runtime")); | |
| 500 } | 520 } | 
| 501 | 521 | 
| 502 // static | 522 // static | 
| 503 void NativeExtensionBindingsSystem::GetInternalAPI( | 523 void NativeExtensionBindingsSystem::GetInternalAPI( | 
| 504 const v8::FunctionCallbackInfo<v8::Value>& info) { | 524 const v8::FunctionCallbackInfo<v8::Value>& info) { | 
| 505 CHECK_EQ(1, info.Length()); | 525 CHECK_EQ(1, info.Length()); | 
| 506 CHECK(info[0]->IsString()); | 526 CHECK(info[0]->IsString()); | 
| 507 | 527 | 
| 508 v8::Isolate* isolate = info.GetIsolate(); | 528 v8::Isolate* isolate = info.GetIsolate(); | 
| 509 v8::HandleScope handle_scope(isolate); | 529 v8::HandleScope handle_scope(isolate); | 
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 605 | 625 | 
| 606 void NativeExtensionBindingsSystem::OnEventListenerChanged( | 626 void NativeExtensionBindingsSystem::OnEventListenerChanged( | 
| 607 const std::string& event_name, | 627 const std::string& event_name, | 
| 608 binding::EventListenersChanged change, | 628 binding::EventListenersChanged change, | 
| 609 v8::Local<v8::Context> context) { | 629 v8::Local<v8::Context> context) { | 
| 610 send_event_listener_ipc_.Run( | 630 send_event_listener_ipc_.Run( | 
| 611 change, ScriptContextSet::GetContextByV8Context(context), event_name); | 631 change, ScriptContextSet::GetContextByV8Context(context), event_name); | 
| 612 } | 632 } | 
| 613 | 633 | 
| 614 } // namespace extensions | 634 } // namespace extensions | 
| OLD | NEW |