| OLD | NEW |
| (Empty) |
| 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 | |
| 5 #include "extensions/renderer/api_bindings_system.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/memory/ptr_util.h" | |
| 9 #include "base/values.h" | |
| 10 #include "extensions/renderer/api_binding_hooks.h" | |
| 11 | |
| 12 namespace extensions { | |
| 13 | |
| 14 APIBindingsSystem::APIBindingsSystem( | |
| 15 const binding::RunJSFunction& call_js, | |
| 16 const binding::RunJSFunctionSync& call_js_sync, | |
| 17 const GetAPISchemaMethod& get_api_schema, | |
| 18 const BindingAccessChecker::AvailabilityCallback& is_available, | |
| 19 const APIRequestHandler::SendRequestMethod& send_request, | |
| 20 const APIEventHandler::EventListenersChangedMethod& event_listeners_changed, | |
| 21 APILastError last_error) | |
| 22 : type_reference_map_(base::Bind(&APIBindingsSystem::InitializeType, | |
| 23 base::Unretained(this))), | |
| 24 request_handler_(send_request, call_js, std::move(last_error)), | |
| 25 event_handler_(call_js, call_js_sync, event_listeners_changed), | |
| 26 access_checker_(is_available), | |
| 27 call_js_(call_js), | |
| 28 call_js_sync_(call_js_sync), | |
| 29 get_api_schema_(get_api_schema) {} | |
| 30 | |
| 31 APIBindingsSystem::~APIBindingsSystem() {} | |
| 32 | |
| 33 v8::Local<v8::Object> APIBindingsSystem::CreateAPIInstance( | |
| 34 const std::string& api_name, | |
| 35 v8::Local<v8::Context> context, | |
| 36 APIBindingHooks** hooks_out) { | |
| 37 std::unique_ptr<APIBinding>& binding = api_bindings_[api_name]; | |
| 38 if (!binding) | |
| 39 binding = CreateNewAPIBinding(api_name); | |
| 40 if (hooks_out) | |
| 41 *hooks_out = binding->hooks(); | |
| 42 return binding->CreateInstance(context); | |
| 43 } | |
| 44 | |
| 45 std::unique_ptr<APIBinding> APIBindingsSystem::CreateNewAPIBinding( | |
| 46 const std::string& api_name) { | |
| 47 const base::DictionaryValue& api_schema = get_api_schema_.Run(api_name); | |
| 48 | |
| 49 const base::ListValue* function_definitions = nullptr; | |
| 50 api_schema.GetList("functions", &function_definitions); | |
| 51 const base::ListValue* type_definitions = nullptr; | |
| 52 api_schema.GetList("types", &type_definitions); | |
| 53 const base::ListValue* event_definitions = nullptr; | |
| 54 api_schema.GetList("events", &event_definitions); | |
| 55 const base::DictionaryValue* property_definitions = nullptr; | |
| 56 api_schema.GetDictionary("properties", &property_definitions); | |
| 57 | |
| 58 // Find the hooks for the API. If none exist, an empty set will be created so | |
| 59 // we can use JS custom bindings. | |
| 60 // TODO(devlin): Once all legacy custom bindings are converted, we don't have | |
| 61 // to unconditionally pass in binding hooks. | |
| 62 std::unique_ptr<APIBindingHooks> hooks; | |
| 63 auto iter = binding_hooks_.find(api_name); | |
| 64 if (iter != binding_hooks_.end()) { | |
| 65 hooks = std::move(iter->second); | |
| 66 binding_hooks_.erase(iter); | |
| 67 } else { | |
| 68 hooks = base::MakeUnique<APIBindingHooks>(api_name, call_js_sync_); | |
| 69 } | |
| 70 | |
| 71 return base::MakeUnique<APIBinding>( | |
| 72 api_name, function_definitions, type_definitions, event_definitions, | |
| 73 property_definitions, | |
| 74 base::Bind(&APIBindingsSystem::CreateCustomType, base::Unretained(this)), | |
| 75 std::move(hooks), &type_reference_map_, &request_handler_, | |
| 76 &event_handler_, &access_checker_); | |
| 77 } | |
| 78 | |
| 79 void APIBindingsSystem::InitializeType(const std::string& type_name) { | |
| 80 // In order to initialize the type, we just initialize the full binding. This | |
| 81 // seems like a lot of work, but in practice, trying to extract out only the | |
| 82 // types from the schema, and then update the reference map based on that, is | |
| 83 // close enough to the same cost. Additionally, this happens lazily on API | |
| 84 // use, and relatively few APIs specify types from another API. Finally, this | |
| 85 // will also go away if/when we generate all these specifications. | |
| 86 std::string::size_type dot = type_name.rfind('.'); | |
| 87 // The type name should be fully qualified (include the API name). | |
| 88 DCHECK_NE(std::string::npos, dot) << type_name; | |
| 89 DCHECK_LT(dot, type_name.size() - 1); | |
| 90 std::string api_name = type_name.substr(0, dot); | |
| 91 // If we've already instantiated the binding, the type should have been in | |
| 92 // there. | |
| 93 DCHECK(api_bindings_.find(api_name) == api_bindings_.end()); | |
| 94 | |
| 95 api_bindings_[api_name] = CreateNewAPIBinding(api_name); | |
| 96 } | |
| 97 | |
| 98 void APIBindingsSystem::CompleteRequest(int request_id, | |
| 99 const base::ListValue& response, | |
| 100 const std::string& error) { | |
| 101 request_handler_.CompleteRequest(request_id, response, error); | |
| 102 } | |
| 103 | |
| 104 void APIBindingsSystem::FireEventInContext(const std::string& event_name, | |
| 105 v8::Local<v8::Context> context, | |
| 106 const base::ListValue& response, | |
| 107 const EventFilteringInfo& filter) { | |
| 108 event_handler_.FireEventInContext(event_name, context, response, filter); | |
| 109 } | |
| 110 | |
| 111 APIBindingHooks* APIBindingsSystem::GetHooksForAPI( | |
| 112 const std::string& api_name) { | |
| 113 DCHECK(api_bindings_.empty()) | |
| 114 << "Hook registration must happen before creating any binding instances."; | |
| 115 std::unique_ptr<APIBindingHooks>& hooks = binding_hooks_[api_name]; | |
| 116 if (!hooks) | |
| 117 hooks = base::MakeUnique<APIBindingHooks>(api_name, call_js_sync_); | |
| 118 return hooks.get(); | |
| 119 } | |
| 120 | |
| 121 void APIBindingsSystem::RegisterCustomType(const std::string& type_name, | |
| 122 const CustomTypeHandler& function) { | |
| 123 DCHECK(custom_types_.find(type_name) == custom_types_.end()) | |
| 124 << "Custom type already registered: " << type_name; | |
| 125 custom_types_[type_name] = function; | |
| 126 } | |
| 127 | |
| 128 void APIBindingsSystem::WillReleaseContext(v8::Local<v8::Context> context) { | |
| 129 request_handler_.InvalidateContext(context); | |
| 130 event_handler_.InvalidateContext(context); | |
| 131 } | |
| 132 | |
| 133 v8::Local<v8::Object> APIBindingsSystem::CreateCustomType( | |
| 134 v8::Isolate* isolate, | |
| 135 const std::string& type_name, | |
| 136 const std::string& property_name, | |
| 137 const base::ListValue* property_values) { | |
| 138 auto iter = custom_types_.find(type_name); | |
| 139 DCHECK(iter != custom_types_.end()) << "Custom type not found: " << type_name; | |
| 140 return iter->second.Run(isolate, property_name, property_values, | |
| 141 &request_handler_, &event_handler_, | |
| 142 &type_reference_map_, &access_checker_); | |
| 143 } | |
| 144 | |
| 145 } // namespace extensions | |
| OLD | NEW |