api_binding_bridge.cc 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  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
  3. // found in the LICENSE file.
  4. #include "extensions/renderer/bindings/api_binding_bridge.h"
  5. #include "base/values.h"
  6. #include "extensions/renderer/bindings/api_binding_hooks.h"
  7. #include "extensions/renderer/bindings/api_binding_util.h"
  8. #include "extensions/renderer/bindings/js_runner.h"
  9. #include "gin/converter.h"
  10. #include "gin/object_template_builder.h"
  11. namespace extensions {
  12. namespace {
  13. const char kApiObjectKey[] = "extensions::bridge::api_object";
  14. const char kHookInterfaceKey[] = "extensions::bridge::hook_object";
  15. v8::Local<v8::Private> GetPrivatePropertyName(v8::Isolate* isolate,
  16. const char* key) {
  17. return v8::Private::ForApi(isolate, gin::StringToSymbol(isolate, key));
  18. }
  19. } // namespace
  20. gin::WrapperInfo APIBindingBridge::kWrapperInfo = {gin::kEmbedderNativeGin};
  21. APIBindingBridge::APIBindingBridge(APIBindingHooks* hooks,
  22. v8::Local<v8::Context> context,
  23. v8::Local<v8::Value> api_object,
  24. const std::string& extension_id,
  25. const std::string& context_type)
  26. : extension_id_(extension_id), context_type_(context_type) {
  27. v8::Isolate* isolate = context->GetIsolate();
  28. v8::Local<v8::Object> wrapper = GetWrapper(isolate).ToLocalChecked();
  29. v8::Maybe<bool> result = wrapper->SetPrivate(
  30. context, GetPrivatePropertyName(isolate, kApiObjectKey), api_object);
  31. if (!result.IsJust() || !result.FromJust()) {
  32. NOTREACHED();
  33. return;
  34. }
  35. v8::Local<v8::Object> js_hook_interface = hooks->GetJSHookInterface(context);
  36. result = wrapper->SetPrivate(context,
  37. GetPrivatePropertyName(isolate,
  38. kHookInterfaceKey),
  39. js_hook_interface);
  40. DCHECK(result.IsJust() && result.FromJust());
  41. }
  42. APIBindingBridge::~APIBindingBridge() {}
  43. gin::ObjectTemplateBuilder APIBindingBridge::GetObjectTemplateBuilder(
  44. v8::Isolate* isolate) {
  45. return Wrappable<APIBindingBridge>::GetObjectTemplateBuilder(isolate)
  46. .SetMethod("registerCustomHook", &APIBindingBridge::RegisterCustomHook);
  47. }
  48. void APIBindingBridge::RegisterCustomHook(v8::Isolate* isolate,
  49. v8::Local<v8::Function> function) {
  50. // The object and arguments here are meant to match those passed to the hook
  51. // functions in binding.js.
  52. v8::Local<v8::Context> context = isolate->GetCurrentContext();
  53. if (!binding::IsContextValidOrThrowError(context))
  54. return; // Context has been invalidated.
  55. v8::Local<v8::Object> hook_object = v8::Object::New(isolate);
  56. v8::Local<v8::Object> wrapper;
  57. if (!GetWrapper(isolate).ToLocal(&wrapper))
  58. return;
  59. v8::Local<v8::Value> hook_interface =
  60. wrapper->GetPrivate(
  61. context, GetPrivatePropertyName(isolate, kHookInterfaceKey))
  62. .ToLocalChecked();
  63. v8::Maybe<bool> result = hook_object->CreateDataProperty(
  64. context, gin::StringToSymbol(isolate, "apiFunctions"), hook_interface);
  65. if (!result.IsJust() || !result.FromJust())
  66. return;
  67. v8::Local<v8::Value> api_object =
  68. wrapper
  69. ->GetPrivate(context, GetPrivatePropertyName(isolate, kApiObjectKey))
  70. .ToLocalChecked();
  71. result = hook_object->CreateDataProperty(
  72. context, gin::StringToSymbol(isolate, "compiledApi"), api_object);
  73. if (!result.IsJust() || !result.FromJust())
  74. return;
  75. result = hook_object->SetPrototype(context, v8::Null(isolate));
  76. if (!result.IsJust() || !result.FromJust())
  77. return;
  78. v8::Local<v8::String> extension_id =
  79. gin::StringToSymbol(isolate, extension_id_);
  80. v8::Local<v8::String> context_type =
  81. gin::StringToSymbol(isolate, context_type_);
  82. v8::Local<v8::Value> args[] = {hook_object, extension_id, context_type};
  83. // TODO(devlin): The context should still be valid at this point - nothing
  84. // above should be able to invalidate it. But let's make extra sure.
  85. // This CHECK is helping to track down https://crbug.com/819968, and should be
  86. // removed when that's fixed.
  87. CHECK(binding::IsContextValid(context));
  88. JSRunner::Get(context)->RunJSFunction(function, context, std::size(args),
  89. args);
  90. }
  91. } // namespace extensions