blob: 07ec45a5ad851875fc8cbf7cbc69023f97e9225a [file] [log] [blame]
[email protected]f55c90ee62014-04-12 00:50:031// Copyright 2014 The Chromium Authors. All rights reserved.
[email protected]58e10452012-02-22 03:34:452// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]f55c90ee62014-04-12 00:50:035#include "extensions/renderer/module_system.h"
[email protected]58e10452012-02-22 03:34:456
7#include "base/bind.h"
[email protected]ad6aa8f92013-06-22 15:34:168#include "base/command_line.h"
kalmanb0c1c502015-04-15 00:25:069#include "base/logging.h"
avi2d124c02015-12-23 06:36:4210#include "base/macros.h"
rdevlin.cronin95cbe922016-06-29 22:40:5211#include "base/metrics/histogram_macros.h"
[email protected]a19a16d82013-06-11 17:45:1212#include "base/strings/string_util.h"
13#include "base/strings/stringprintf.h"
rdevlin.cronin95cbe922016-06-29 22:40:5214#include "base/timer/elapsed_timer.h"
primiano7182d7b2015-01-30 18:02:0315#include "base/trace_event/trace_event.h"
sammcfb8875c2014-10-28 11:51:0416#include "content/public/renderer/render_frame.h"
[email protected]4f1633f2013-03-09 14:26:2417#include "content/public/renderer/render_view.h"
thestigb012bc3d2014-09-18 22:57:1318#include "extensions/common/extension.h"
[email protected]f55c90ee62014-04-12 00:50:0319#include "extensions/common/extensions_client.h"
20#include "extensions/renderer/console.h"
21#include "extensions/renderer/safe_builtins.h"
22#include "extensions/renderer/script_context.h"
rdevlin.croninb2cec912015-06-24 20:36:0123#include "extensions/renderer/script_context_set.h"
rdevlin.cronin1ed2e892016-12-06 21:35:4324#include "extensions/renderer/source_map.h"
bashi6a4854f2015-06-19 00:51:5125#include "extensions/renderer/v8_helpers.h"
rdevlin.cronin787c68d02017-04-18 21:03:4726#include "gin/converter.h"
[email protected]d9f51dad2014-07-09 05:39:3827#include "gin/modules/module_registry.h"
[email protected]2255a9332013-06-17 05:12:3128#include "third_party/WebKit/public/web/WebFrame.h"
[email protected]58e10452012-02-22 03:34:4529
[email protected]95ee77da2013-03-19 21:11:1130namespace extensions {
31
bashi6a4854f2015-06-19 00:51:5132using namespace v8_helpers;
33
[email protected]58e10452012-02-22 03:34:4534namespace {
35
thestig041f756e2016-10-14 18:26:1836const char kModuleSystem[] = "module_system";
37const char kModuleName[] = "module_name";
38const char kModuleField[] = "module_field";
39const char kModulesField[] = "modules";
[email protected]cc0457712012-03-21 03:56:3840
kalmanec0e3aa2015-04-28 21:50:3241// Logs an error for the calling context in preparation for potentially
42// crashing the renderer, with some added metadata about the context:
[email protected]662c48b2013-07-12 03:50:5243// - Its type (blessed, unblessed, etc).
44// - Whether it's valid.
45// - The extension ID, if one exists.
kalmanec0e3aa2015-04-28 21:50:3246// Crashing won't happen in stable/beta releases, but is encouraged to happen
47// in the less stable released to catch errors early.
[email protected]f55c90ee62014-04-12 00:50:0348void Fatal(ScriptContext* context, const std::string& message) {
[email protected]662c48b2013-07-12 03:50:5249 // Prepend some context metadata.
50 std::string full_message = "(";
51 if (!context->is_valid())
52 full_message += "Invalid ";
53 full_message += context->GetContextTypeDescription();
54 full_message += " context";
55 if (context->extension()) {
56 full_message += " for ";
57 full_message += context->extension()->id();
58 }
59 full_message += ") ";
60 full_message += message;
61
kalman309f98b2015-04-30 00:12:0062 ExtensionsClient* client = ExtensionsClient::Get();
63 if (client->ShouldSuppressFatalErrors()) {
rdevlin.croninbaa379d2017-04-19 20:49:3164 console::AddMessage(context, content::CONSOLE_MESSAGE_LEVEL_ERROR,
65 full_message);
kalman309f98b2015-04-30 00:12:0066 client->RecordDidSuppressFatalError();
67 } else {
rdevlin.croninbaa379d2017-04-19 20:49:3168 console::Fatal(context, full_message);
kalman309f98b2015-04-30 00:12:0069 }
[email protected]ad6aa8f92013-06-22 15:34:1670}
71
[email protected]95c6b3012013-12-02 14:30:3172void Warn(v8::Isolate* isolate, const std::string& message) {
rdevlin.croninb2cec912015-06-24 20:36:0173 ScriptContext* script_context =
jochen520e6222015-10-29 16:21:2474 ScriptContextSet::GetContextByV8Context(isolate->GetCurrentContext());
rdevlin.croninbaa379d2017-04-19 20:49:3175 console::AddMessage(script_context, content::CONSOLE_MESSAGE_LEVEL_WARNING,
76 message);
[email protected]ad6aa8f92013-06-22 15:34:1677}
78
[email protected]68e63ea12013-06-05 05:00:5479// Default exception handler which logs the exception.
80class DefaultExceptionHandler : public ModuleSystem::ExceptionHandler {
81 public:
[email protected]f55c90ee62014-04-12 00:50:0382 explicit DefaultExceptionHandler(ScriptContext* context)
bashi6a4854f2015-06-19 00:51:5183 : ModuleSystem::ExceptionHandler(context) {}
[email protected]ad6aa8f92013-06-22 15:34:1684
[email protected]68e63ea12013-06-05 05:00:5485 // Fatally dumps the debug info from |try_catch| to the console.
86 // Make sure this is never used for exceptions that originate in external
87 // code!
dcheng9168b2f2014-10-21 12:38:2488 void HandleUncaughtException(const v8::TryCatch& try_catch) override {
[email protected]dc3d06e2013-09-06 12:21:0389 v8::HandleScope handle_scope(context_->isolate());
[email protected]68e63ea12013-06-05 05:00:5490 std::string stack_trace = "<stack trace unavailable>";
bashi6a4854f2015-06-19 00:51:5191 v8::Local<v8::Value> v8_stack_trace;
92 if (try_catch.StackTrace(context_->v8_context()).ToLocal(&v8_stack_trace)) {
93 v8::String::Utf8Value stack_value(v8_stack_trace);
[email protected]68e63ea12013-06-05 05:00:5494 if (*stack_value)
95 stack_trace.assign(*stack_value, stack_value.length());
96 else
97 stack_trace = "<could not convert stack trace to string>";
98 }
[email protected]662c48b2013-07-12 03:50:5299 Fatal(context_, CreateExceptionString(try_catch) + "{" + stack_trace + "}");
[email protected]68e63ea12013-06-05 05:00:54100 }
101};
102
rdevlin.cronin83a4b3a2015-10-28 21:43:58103// Sets a property on the "exports" object for bindings. Called by JS with
104// exports.$set(<key>, <value>).
105void SetExportsProperty(
106 const v8::FunctionCallbackInfo<v8::Value>& args) {
107 v8::Local<v8::Object> obj = args.This();
rdevlin.cronin415b73b2015-11-13 01:14:47108 CHECK_EQ(2, args.Length());
109 CHECK(args[0]->IsString());
rdevlin.cronin83a4b3a2015-10-28 21:43:58110 v8::Maybe<bool> result =
111 obj->DefineOwnProperty(args.GetIsolate()->GetCurrentContext(),
112 args[0]->ToString(), args[1], v8::ReadOnly);
113 if (!result.FromMaybe(false))
114 LOG(ERROR) << "Failed to set private property on the export.";
115}
116
sammc9152fe902016-10-13 22:34:16117bool ContextNeedsMojoBindings(ScriptContext* context) {
118 // Mojo is only used from JS by some APIs so a context only needs the mojo
119 // bindings if at least one is available.
120 //
121 // Prefer to use Mojo from C++ if possible rather than adding to this list.
122 static const char* const kApisRequiringMojo[] = {
123 "mimeHandlerPrivate", "mojoPrivate",
124 };
125
126 for (const auto* api : kApisRequiringMojo) {
127 if (context->GetAvailability(api).is_available())
128 return true;
129 }
130 return false;
131}
132
[email protected]f55c90ee62014-04-12 00:50:03133} // namespace
[email protected]68e63ea12013-06-05 05:00:54134
135std::string ModuleSystem::ExceptionHandler::CreateExceptionString(
136 const v8::TryCatch& try_catch) {
tfarinaf85316f2015-04-29 17:03:40137 v8::Local<v8::Message> message(try_catch.Message());
[email protected]95ee77da2013-03-19 21:11:11138 if (message.IsEmpty()) {
139 return "try_catch has no message";
140 }
[email protected]58e10452012-02-22 03:34:45141
[email protected]95ee77da2013-03-19 21:11:11142 std::string resource_name = "<unknown resource>";
[email protected]bce20ba2014-06-27 18:18:45143 if (!message->GetScriptOrigin().ResourceName().IsEmpty()) {
[email protected]95ee77da2013-03-19 21:11:11144 v8::String::Utf8Value resource_name_v8(
dcarneya261b772014-11-20 17:55:07145 message->GetScriptOrigin().ResourceName());
[email protected]95ee77da2013-03-19 21:11:11146 resource_name.assign(*resource_name_v8, resource_name_v8.length());
147 }
148
149 std::string error_message = "<no error message>";
150 if (!message->Get().IsEmpty()) {
151 v8::String::Utf8Value error_message_v8(message->Get());
152 error_message.assign(*error_message_v8, error_message_v8.length());
153 }
154
rdevlin.cronin96902d82016-04-14 20:35:07155 int line_number = 0;
156 if (context_) { // |context_| can be null in unittests.
157 auto maybe = message->GetLineNumber(context_->v8_context());
158 line_number = maybe.IsJust() ? maybe.FromJust() : 0;
159 }
[email protected]95ee77da2013-03-19 21:11:11160 return base::StringPrintf("%s:%d: %s",
161 resource_name.c_str(),
bashi6a4854f2015-06-19 00:51:51162 line_number,
[email protected]95ee77da2013-03-19 21:11:11163 error_message.c_str());
164}
165
lazyboyce333962016-04-12 18:22:04166ModuleSystem::ModuleSystem(ScriptContext* context, const SourceMap* source_map)
[email protected]4f1633f2013-03-09 14:26:24167 : ObjectBackedNativeHandler(context),
[email protected]68e63ea12013-06-05 05:00:54168 context_(context),
[email protected]bad9a5f2012-04-13 19:16:54169 source_map_(source_map),
[email protected]68e63ea12013-06-05 05:00:54170 natives_enabled_(0),
[email protected]d9f51dad2014-07-09 05:39:38171 exception_handler_(new DefaultExceptionHandler(context)),
172 weak_factory_(this) {
[email protected]f55c90ee62014-04-12 00:50:03173 RouteFunction(
174 "require",
[email protected]ecde1912012-03-16 06:25:31175 base::Bind(&ModuleSystem::RequireForJs, base::Unretained(this)));
[email protected]f55c90ee62014-04-12 00:50:03176 RouteFunction(
177 "requireNative",
[email protected]4f1633f2013-03-09 14:26:24178 base::Bind(&ModuleSystem::RequireNative, base::Unretained(this)));
[email protected]d9f51dad2014-07-09 05:39:38179 RouteFunction(
180 "requireAsync",
181 base::Bind(&ModuleSystem::RequireAsync, base::Unretained(this)));
[email protected]ca557292013-12-11 08:44:27182 RouteFunction("privates",
[email protected]f55c90ee62014-04-12 00:50:03183 base::Bind(&ModuleSystem::Private, base::Unretained(this)));
[email protected]ecde1912012-03-16 06:25:31184
tfarinaf85316f2015-04-29 17:03:40185 v8::Local<v8::Object> global(context->v8_context()->Global());
[email protected]505ffde2013-12-19 15:47:13186 v8::Isolate* isolate = context->isolate();
jochen300abe232015-11-06 21:17:53187 SetPrivate(global, kModulesField, v8::Object::New(isolate));
188 SetPrivate(global, kModuleSystem, v8::External::New(isolate, this));
[email protected]d9f51dad2014-07-09 05:39:38189
190 gin::ModuleRegistry::From(context->v8_context())->AddObserver(this);
rdevlin.cronin3cf02f522016-08-15 23:12:31191 if (context_->GetRenderFrame() &&
sammc9152fe902016-10-13 22:34:16192 context_->context_type() == Feature::BLESSED_EXTENSION_CONTEXT &&
193 ContextNeedsMojoBindings(context_)) {
sammcfb8875c2014-10-28 11:51:04194 context_->GetRenderFrame()->EnsureMojoBuiltinsAreAvailable(
195 context->isolate(), context->v8_context());
196 }
[email protected]58e10452012-02-22 03:34:45197}
198
kalmanb0c1c502015-04-15 00:25:06199ModuleSystem::~ModuleSystem() {
200}
[email protected]4f1633f2013-03-09 14:26:24201
202void ModuleSystem::Invalidate() {
[email protected]079532242013-03-12 06:01:10203 // Clear the module system properties from the global context. It's polite,
204 // and we use this as a signal in lazy handlers that we no longer exist.
205 {
[email protected]dc3d06e2013-09-06 12:21:03206 v8::HandleScope scope(GetIsolate());
tfarinaf85316f2015-04-29 17:03:40207 v8::Local<v8::Object> global = context()->v8_context()->Global();
jochen300abe232015-11-06 21:17:53208 DeletePrivate(global, kModulesField);
209 DeletePrivate(global, kModuleSystem);
[email protected]079532242013-03-12 06:01:10210 }
211
kalmanb0c1c502015-04-15 00:25:06212 // Invalidate all active and clobbered NativeHandlers we own.
213 for (const auto& handler : native_handler_map_)
214 handler.second->Invalidate();
215 for (const auto& clobbered_handler : clobbered_native_handlers_)
216 clobbered_handler->Invalidate();
[email protected]079532242013-03-12 06:01:10217
[email protected]4f1633f2013-03-09 14:26:24218 ObjectBackedNativeHandler::Invalidate();
[email protected]58e10452012-02-22 03:34:45219}
220
[email protected]b6aad81c2012-03-27 08:45:15221ModuleSystem::NativesEnabledScope::NativesEnabledScope(
222 ModuleSystem* module_system)
223 : module_system_(module_system) {
224 module_system_->natives_enabled_++;
225}
226
227ModuleSystem::NativesEnabledScope::~NativesEnabledScope() {
228 module_system_->natives_enabled_--;
229 CHECK_GE(module_system_->natives_enabled_, 0);
230}
231
[email protected]144114942012-12-04 07:23:23232void ModuleSystem::HandleException(const v8::TryCatch& try_catch) {
[email protected]68e63ea12013-06-05 05:00:54233 exception_handler_->HandleUncaughtException(try_catch);
[email protected]1c6189f2012-05-18 06:45:52234}
235
bashi61ca3c72015-06-26 00:40:10236v8::MaybeLocal<v8::Object> ModuleSystem::Require(
237 const std::string& module_name) {
238 v8::Local<v8::String> v8_module_name;
239 if (!ToV8String(GetIsolate(), module_name, &v8_module_name))
240 return v8::MaybeLocal<v8::Object>();
[email protected]95c6b3012013-12-02 14:30:31241 v8::EscapableHandleScope handle_scope(GetIsolate());
rdevlin.croninfedbe842017-06-24 02:12:03242 v8::Local<v8::Value> value =
243 RequireForJsInner(v8_module_name, true /* create */);
bashi61ca3c72015-06-26 00:40:10244 if (value.IsEmpty() || !value->IsObject())
245 return v8::MaybeLocal<v8::Object>();
246 return handle_scope.Escape(value.As<v8::Object>());
[email protected]ecde1912012-03-16 06:25:31247}
248
[email protected]d8c5fbb2013-06-14 11:35:25249void ModuleSystem::RequireForJs(
[email protected]f55c90ee62014-04-12 00:50:03250 const v8::FunctionCallbackInfo<v8::Value>& args) {
bashi6a4854f2015-06-19 00:51:51251 if (!args[0]->IsString()) {
252 NOTREACHED() << "require() called with a non-string argument";
253 return;
254 }
255 v8::Local<v8::String> module_name = args[0].As<v8::String>();
rdevlin.croninfedbe842017-06-24 02:12:03256 args.GetReturnValue().Set(RequireForJsInner(module_name, true /* create */));
[email protected]ecde1912012-03-16 06:25:31257}
258
[email protected]95c6b3012013-12-02 14:30:31259v8::Local<v8::Value> ModuleSystem::RequireForJsInner(
rdevlin.croninfedbe842017-06-24 02:12:03260 v8::Local<v8::String> module_name,
261 bool create) {
[email protected]95c6b3012013-12-02 14:30:31262 v8::EscapableHandleScope handle_scope(GetIsolate());
bashi6a4854f2015-06-19 00:51:51263 v8::Local<v8::Context> v8_context = context()->v8_context();
264 v8::Context::Scope context_scope(v8_context);
[email protected]95ee77da2013-03-19 21:11:11265
tfarinaf85316f2015-04-29 17:03:40266 v8::Local<v8::Object> global(context()->v8_context()->Global());
[email protected]079532242013-03-12 06:01:10267
268 // The module system might have been deleted. This can happen if a different
269 // context keeps a reference to us, but our frame is destroyed (e.g.
270 // background page keeps reference to chrome object in a closed popup).
jochen300abe232015-11-06 21:17:53271 v8::Local<v8::Value> modules_value;
272 if (!GetPrivate(global, kModulesField, &modules_value) ||
273 modules_value->IsUndefined()) {
[email protected]95c6b3012013-12-02 14:30:31274 Warn(GetIsolate(), "Extension view no longer exists");
275 return v8::Undefined(GetIsolate());
[email protected]d2663612013-03-17 09:25:56276 }
[email protected]079532242013-03-12 06:01:10277
tfarinaf85316f2015-04-29 17:03:40278 v8::Local<v8::Object> modules(v8::Local<v8::Object>::Cast(modules_value));
bashi6a4854f2015-06-19 00:51:51279 v8::Local<v8::Value> exports;
rdevlin.cronin75b803b2016-03-02 00:13:47280 if (!GetPrivateProperty(v8_context, modules, module_name, &exports) ||
bashi6a4854f2015-06-19 00:51:51281 !exports->IsUndefined())
[email protected]95c6b3012013-12-02 14:30:31282 return handle_scope.Escape(exports);
[email protected]7c95c1a82012-04-17 02:11:33283
rdevlin.croninfedbe842017-06-24 02:12:03284 if (!create)
285 return v8::Undefined(GetIsolate());
286
[email protected]d9f51dad2014-07-09 05:39:38287 exports = LoadModule(*v8::String::Utf8Value(module_name));
rdevlin.cronin75b803b2016-03-02 00:13:47288 SetPrivateProperty(v8_context, modules, module_name, exports);
[email protected]95c6b3012013-12-02 14:30:31289 return handle_scope.Escape(exports);
[email protected]58e10452012-02-22 03:34:45290}
291
rdevlin.croninaac306632016-10-18 21:27:46292void ModuleSystem::CallModuleMethodSafe(const std::string& module_name,
293 const std::string& method_name) {
294 v8::HandleScope handle_scope(GetIsolate());
295 v8::Local<v8::Value> no_args;
rdevlin.cronin0d94256f2016-12-09 15:34:23296 CallModuleMethodSafe(module_name, method_name, 0, &no_args,
297 ScriptInjectionCallback::CompleteCallback());
rdevlin.croninaac306632016-10-18 21:27:46298}
299
300void ModuleSystem::CallModuleMethodSafe(
301 const std::string& module_name,
302 const std::string& method_name,
303 std::vector<v8::Local<v8::Value>>* args) {
rdevlin.cronin0d94256f2016-12-09 15:34:23304 CallModuleMethodSafe(module_name, method_name, args->size(), args->data(),
305 ScriptInjectionCallback::CompleteCallback());
rdevlin.croninaac306632016-10-18 21:27:46306}
307
308void ModuleSystem::CallModuleMethodSafe(const std::string& module_name,
309 const std::string& method_name,
310 int argc,
311 v8::Local<v8::Value> argv[]) {
rdevlin.cronin0d94256f2016-12-09 15:34:23312 CallModuleMethodSafe(module_name, method_name, argc, argv,
313 ScriptInjectionCallback::CompleteCallback());
314}
315
316void ModuleSystem::CallModuleMethodSafe(
317 const std::string& module_name,
318 const std::string& method_name,
319 int argc,
320 v8::Local<v8::Value> argv[],
321 const ScriptInjectionCallback::CompleteCallback& callback) {
rdevlin.croninaac306632016-10-18 21:27:46322 TRACE_EVENT2("v8", "v8.callModuleMethodSafe", "module_name", module_name,
323 "method_name", method_name);
324
325 v8::HandleScope handle_scope(GetIsolate());
326 v8::Local<v8::Context> v8_context = context()->v8_context();
327 v8::Context::Scope context_scope(v8_context);
328
329 v8::Local<v8::Function> function =
330 GetModuleFunction(module_name, method_name);
kozyatinskiydedd4892016-12-01 23:06:53331 if (function.IsEmpty()) {
rdevlin.croninfedbe842017-06-24 02:12:03332 // This can legitimately happen when the module hasn't been loaded in the
333 // context (since GetModuleFunction() does not load an unloaded module).
334 // Typically, we won't do this, but we can in the case of, e.g., dispatching
335 // events (where we'll try to dispatch to each context in a process). In
336 // these cases, though, we can know that there are no listeners registered,
337 // since the event module hasn't been loaded.
kozyatinskiydedd4892016-12-01 23:06:53338 return;
339 }
rdevlin.croninaac306632016-10-18 21:27:46340
341 {
342 v8::TryCatch try_catch(GetIsolate());
343 try_catch.SetCaptureMessage(true);
rdevlin.cronin0d94256f2016-12-09 15:34:23344 context_->SafeCallFunction(function, argc, argv, callback);
rdevlin.croninaac306632016-10-18 21:27:46345 if (try_catch.HasCaught())
346 HandleException(try_catch);
347 }
348}
349
[email protected]f55c90ee62014-04-12 00:50:03350void ModuleSystem::RegisterNativeHandler(
351 const std::string& name,
dchengf6f80662016-04-20 20:26:04352 std::unique_ptr<NativeHandler> native_handler) {
kalmanb0c1c502015-04-15 00:25:06353 ClobberExistingNativeHandler(name);
tzik8f7af2922015-11-25 03:16:48354 native_handler_map_[name] = std::move(native_handler);
[email protected]58e10452012-02-22 03:34:45355}
356
[email protected]95ee77da2013-03-19 21:11:11357void ModuleSystem::OverrideNativeHandlerForTest(const std::string& name) {
kalmanb0c1c502015-04-15 00:25:06358 ClobberExistingNativeHandler(name);
[email protected]11844fa2012-05-10 00:35:59359 overridden_native_handlers_.insert(name);
360}
361
[email protected]ecde1912012-03-16 06:25:31362void ModuleSystem::RunString(const std::string& code, const std::string& name) {
[email protected]dc3d06e2013-09-06 12:21:03363 v8::HandleScope handle_scope(GetIsolate());
bashi6a4854f2015-06-19 00:51:51364 v8::Local<v8::String> v8_code;
365 v8::Local<v8::String> v8_name;
366 if (!ToV8String(GetIsolate(), code.c_str(), &v8_code) ||
367 !ToV8String(GetIsolate(), name.c_str(), &v8_name)) {
368 Warn(GetIsolate(), "Too long code or name.");
369 return;
370 }
371 RunString(v8_code, v8_name);
[email protected]58e10452012-02-22 03:34:45372}
373
[email protected]cc0457712012-03-21 03:56:38374// static
[email protected]4e008e172013-06-13 20:15:48375void ModuleSystem::NativeLazyFieldGetter(
bashi6a4854f2015-06-19 00:51:51376 v8::Local<v8::Name> property,
[email protected]4e008e172013-06-13 20:15:48377 const v8::PropertyCallbackInfo<v8::Value>& info) {
bashi6a4854f2015-06-19 00:51:51378 LazyFieldGetterInner(property.As<v8::String>(), info,
379 &ModuleSystem::RequireNativeFromString);
[email protected]4e008e172013-06-13 20:15:48380}
381
382// static
383void ModuleSystem::LazyFieldGetter(
bashi6a4854f2015-06-19 00:51:51384 v8::Local<v8::Name> property,
[email protected]4e008e172013-06-13 20:15:48385 const v8::PropertyCallbackInfo<v8::Value>& info) {
bashi6a4854f2015-06-19 00:51:51386 LazyFieldGetterInner(property.As<v8::String>(), info, &ModuleSystem::Require);
[email protected]4e008e172013-06-13 20:15:48387}
388
389// static
390void ModuleSystem::LazyFieldGetterInner(
391 v8::Local<v8::String> property,
392 const v8::PropertyCallbackInfo<v8::Value>& info,
[email protected]4f1633f2013-03-09 14:26:24393 RequireFunction require_function) {
rdevlin.cronin95cbe922016-06-29 22:40:52394 base::ElapsedTimer timer;
[email protected]561ddce2012-03-22 01:18:55395 CHECK(!info.Data().IsEmpty());
396 CHECK(info.Data()->IsObject());
jochen300abe232015-11-06 21:17:53397 v8::Isolate* isolate = info.GetIsolate();
398 v8::HandleScope handle_scope(isolate);
tfarinaf85316f2015-04-29 17:03:40399 v8::Local<v8::Object> parameters = v8::Local<v8::Object>::Cast(info.Data());
[email protected]9a598442013-06-04 16:39:12400 // This context should be the same as context()->v8_context().
tfarinaf85316f2015-04-29 17:03:40401 v8::Local<v8::Context> context = parameters->CreationContext();
402 v8::Local<v8::Object> global(context->Global());
jochen300abe232015-11-06 21:17:53403 v8::Local<v8::Value> module_system_value;
404 if (!GetPrivate(context, global, kModuleSystem, &module_system_value) ||
405 !module_system_value->IsExternal()) {
[email protected]bad9a5f2012-04-13 19:16:54406 // ModuleSystem has been deleted.
[email protected]95ee77da2013-03-19 21:11:11407 // TODO(kalman): See comment in header file.
jochen300abe232015-11-06 21:17:53408 Warn(isolate,
[email protected]95c6b3012013-12-02 14:30:31409 "Module system has been deleted, does extension view exist?");
[email protected]4e008e172013-06-13 20:15:48410 return;
[email protected]bad9a5f2012-04-13 19:16:54411 }
[email protected]95ee77da2013-03-19 21:11:11412
[email protected]561ddce2012-03-22 01:18:55413 ModuleSystem* module_system = static_cast<ModuleSystem*>(
tfarinaf85316f2015-04-29 17:03:40414 v8::Local<v8::External>::Cast(module_system_value)->Value());
[email protected]cc0457712012-03-21 03:56:38415
bashi6a4854f2015-06-19 00:51:51416 v8::Local<v8::Value> v8_module_name;
rdevlin.cronin163beed2016-03-04 18:19:09417 if (!GetPrivateProperty(context, parameters, kModuleName, &v8_module_name)) {
jochen300abe232015-11-06 21:17:53418 Warn(isolate, "Cannot find module.");
bashi6a4854f2015-06-19 00:51:51419 return;
420 }
421 std::string name = *v8::String::Utf8Value(v8_module_name);
[email protected]4f1633f2013-03-09 14:26:24422
rdevlin.cronin741da002017-04-24 20:27:41423 // As part of instantiating a module, we delete the getter and replace it with
424 // the property directly. If we're trying to load the same module a second
425 // time, it means something went wrong. Bail out early rather than going
426 // through the initialization process again (since bindings may not expect to
427 // run multiple times).
428 if (!module_system->loaded_modules_.insert(name).second) {
429 Warn(isolate, "Previous API instantiation failed.");
430 return;
431 }
432
[email protected]4f1633f2013-03-09 14:26:24433 // Switch to our v8 context because we need functions created while running
434 // the require()d module to belong to our context, not the current one.
435 v8::Context::Scope context_scope(context);
436 NativesEnabledScope natives_enabled_scope(module_system);
437
jochen300abe232015-11-06 21:17:53438 v8::TryCatch try_catch(isolate);
bashi61ca3c72015-06-26 00:40:10439 v8::Local<v8::Value> module_value;
440 if (!(module_system->*require_function)(name).ToLocal(&module_value)) {
[email protected]4f1633f2013-03-09 14:26:24441 module_system->HandleException(try_catch);
[email protected]4e008e172013-06-13 20:15:48442 return;
[email protected]95ee77da2013-03-19 21:11:11443 }
[email protected]4f1633f2013-03-09 14:26:24444
tfarinaf85316f2015-04-29 17:03:40445 v8::Local<v8::Object> module = v8::Local<v8::Object>::Cast(module_value);
bashi6a4854f2015-06-19 00:51:51446 v8::Local<v8::Value> field_value;
rdevlin.cronin163beed2016-03-04 18:19:09447 if (!GetPrivateProperty(context, parameters, kModuleField, &field_value)) {
bashi6a4854f2015-06-19 00:51:51448 module_system->HandleException(try_catch);
449 return;
450 }
451 v8::Local<v8::String> field;
452 if (!field_value->ToString(context).ToLocal(&field)) {
453 module_system->HandleException(try_catch);
454 return;
455 }
[email protected]561ddce2012-03-22 01:18:55456
bashi6a4854f2015-06-19 00:51:51457 if (!IsTrue(module->Has(context, field))) {
[email protected]d7cd1b02013-09-10 00:22:16458 std::string field_str = *v8::String::Utf8Value(field);
[email protected]662c48b2013-07-12 03:50:52459 Fatal(module_system->context_,
460 "Lazy require of " + name + "." + field_str + " did not set the " +
461 field_str + " field");
[email protected]4e008e172013-06-13 20:15:48462 return;
[email protected]95ee77da2013-03-19 21:11:11463 }
[email protected]4f1633f2013-03-09 14:26:24464
bashi6a4854f2015-06-19 00:51:51465 v8::Local<v8::Value> new_field;
466 if (!GetProperty(context, module, field, &new_field)) {
[email protected]95ee77da2013-03-19 21:11:11467 module_system->HandleException(try_catch);
[email protected]4e008e172013-06-13 20:15:48468 return;
[email protected]95ee77da2013-03-19 21:11:11469 }
470
471 // Ok for it to be undefined, among other things it's how bindings signify
472 // that the extension doesn't have permission to use them.
473 CHECK(!new_field.IsEmpty());
474
[email protected]4f1633f2013-03-09 14:26:24475 // Delete the getter and set this field to |new_field| so the same object is
476 // returned every time a certain API is accessed.
tfarinaf85316f2015-04-29 17:03:40477 v8::Local<v8::Value> val = info.This();
[email protected]80b0c8c2014-04-22 15:00:43478 if (val->IsObject()) {
tfarinaf85316f2015-04-29 17:03:40479 v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(val);
daniel.bevenius33ac37f2017-03-20 09:00:58480 auto maybe = object->Delete(context, property);
rdevlin.cronin741da002017-04-24 20:27:41481 if (!maybe.IsJust()) {
482 // In theory, deletion should never result in throwing an error. But
483 // crazier things have happened.
484 NOTREACHED();
485 return;
486 }
487 if (!maybe.FromJust()) {
488 // Deletion can *fail* in certain cases, such as when the script does
489 // Object.freeze(chrome).
490 return;
491 }
bashi6a4854f2015-06-19 00:51:51492 SetProperty(context, object, property, new_field);
[email protected]80b0c8c2014-04-22 15:00:43493 } else {
494 NOTREACHED();
495 }
[email protected]4e008e172013-06-13 20:15:48496 info.GetReturnValue().Set(new_field);
rdevlin.cronin95cbe922016-06-29 22:40:52497
498 UMA_HISTOGRAM_TIMES("Extensions.ApiBindingGenerationTime", timer.Elapsed());
[email protected]561ddce2012-03-22 01:18:55499}
500
tfarinaf85316f2015-04-29 17:03:40501void ModuleSystem::SetLazyField(v8::Local<v8::Object> object,
[email protected]561ddce2012-03-22 01:18:55502 const std::string& field,
503 const std::string& module_name,
504 const std::string& module_field) {
[email protected]f55c90ee62014-04-12 00:50:03505 SetLazyField(
506 object, field, module_name, module_field, &ModuleSystem::LazyFieldGetter);
[email protected]4f1633f2013-03-09 14:26:24507}
508
tfarinaf85316f2015-04-29 17:03:40509void ModuleSystem::SetLazyField(v8::Local<v8::Object> object,
[email protected]4f1633f2013-03-09 14:26:24510 const std::string& field,
511 const std::string& module_name,
512 const std::string& module_field,
bashi6a4854f2015-06-19 00:51:51513 v8::AccessorNameGetterCallback getter) {
514 CHECK(field.size() < v8::String::kMaxLength);
515 CHECK(module_name.size() < v8::String::kMaxLength);
516 CHECK(module_field.size() < v8::String::kMaxLength);
[email protected]dc3d06e2013-09-06 12:21:03517 v8::HandleScope handle_scope(GetIsolate());
tfarinaf85316f2015-04-29 17:03:40518 v8::Local<v8::Object> parameters = v8::Object::New(GetIsolate());
bashi6a4854f2015-06-19 00:51:51519 v8::Local<v8::Context> context = context_->v8_context();
rdevlin.cronin741da002017-04-24 20:27:41520 // Since we reset the accessor here, we remove the record of having loaded the
521 // module.
522 loaded_modules_.erase(module_name);
rdevlin.cronin163beed2016-03-04 18:19:09523 SetPrivateProperty(context, parameters, kModuleName,
bashi6a4854f2015-06-19 00:51:51524 ToV8StringUnsafe(GetIsolate(), module_name.c_str()));
rdevlin.cronin163beed2016-03-04 18:19:09525 SetPrivateProperty(context, parameters, kModuleField,
bashi6a4854f2015-06-19 00:51:51526 ToV8StringUnsafe(GetIsolate(), module_field.c_str()));
527 auto maybe = object->SetAccessor(
528 context, ToV8StringUnsafe(GetIsolate(), field.c_str()), getter, NULL,
529 parameters);
530 CHECK(IsTrue(maybe));
[email protected]cc0457712012-03-21 03:56:38531}
[email protected]ecde1912012-03-16 06:25:31532
tfarinaf85316f2015-04-29 17:03:40533void ModuleSystem::SetNativeLazyField(v8::Local<v8::Object> object,
[email protected]4f1633f2013-03-09 14:26:24534 const std::string& field,
535 const std::string& module_name,
536 const std::string& module_field) {
[email protected]f55c90ee62014-04-12 00:50:03537 SetLazyField(object,
538 field,
539 module_name,
540 module_field,
541 &ModuleSystem::NativeLazyFieldGetter);
[email protected]4f1633f2013-03-09 14:26:24542}
543
rdevlin.cronin7bf55122016-12-22 01:55:38544void ModuleSystem::OnNativeBindingCreated(
545 const std::string& api_name,
rdevlin.cronin646703e2017-03-01 21:20:29546 v8::Local<v8::Value> api_bridge_value) {
547 DCHECK(!get_internal_api_.IsEmpty());
rdevlin.cronin7bf55122016-12-22 01:55:38548 v8::HandleScope scope(GetIsolate());
549 if (source_map_->Contains(api_name)) {
rdevlin.cronin787c68d02017-04-18 21:03:47550 // We need to load the custom bindings and store them in our modules.
551 // Storing them is important so that calls through CallModuleMethod() route
552 // to the proper objects, if they share the same name as an API.
553 v8::Local<v8::Value> modules;
554 if (!GetPrivate(context()->v8_context()->Global(), kModulesField,
555 &modules) ||
556 !modules->IsObject()) {
557 NOTREACHED();
558 return;
559 }
560
rdevlin.cronin7bf55122016-12-22 01:55:38561 NativesEnabledScope enabled(this);
rdevlin.cronin787c68d02017-04-18 21:03:47562 v8::Local<v8::Value> exports =
563 LoadModuleWithNativeAPIBridge(api_name, api_bridge_value);
564 SetPrivateProperty(context()->v8_context(), modules.As<v8::Object>(),
565 gin::StringToSymbol(GetIsolate(), api_name), exports);
rdevlin.cronin7bf55122016-12-22 01:55:38566 }
567}
568
rdevlin.cronin646703e2017-03-01 21:20:29569void ModuleSystem::SetGetInternalAPIHook(
570 v8::Local<v8::FunctionTemplate> get_internal_api) {
571 DCHECK(get_internal_api_.IsEmpty());
572 get_internal_api_.Set(GetIsolate(), get_internal_api);
573}
574
rdevlin.cronine96ca6b2017-03-09 20:05:51575void ModuleSystem::SetJSBindingUtilGetter(const JSBindingUtilGetter& getter) {
576 DCHECK(js_binding_util_getter_.is_null());
577 js_binding_util_getter_ = getter;
578}
579
tfarinaf85316f2015-04-29 17:03:40580v8::Local<v8::Value> ModuleSystem::RunString(v8::Local<v8::String> code,
581 v8::Local<v8::String> name) {
annekao533482222015-08-21 23:23:53582 return context_->RunScript(
583 name, code, base::Bind(&ExceptionHandler::HandleUncaughtException,
584 base::Unretained(exception_handler_.get())));
[email protected]9e03ce22012-03-13 08:50:05585}
586
[email protected]d8c5fbb2013-06-14 11:35:25587void ModuleSystem::RequireNative(
588 const v8::FunctionCallbackInfo<v8::Value>& args) {
[email protected]58e10452012-02-22 03:34:45589 CHECK_EQ(1, args.Length());
dcarneya261b772014-11-20 17:55:07590 std::string native_name = *v8::String::Utf8Value(args[0]);
bashi61ca3c72015-06-26 00:40:10591 v8::Local<v8::Object> object;
592 if (RequireNativeFromString(native_name).ToLocal(&object))
593 args.GetReturnValue().Set(object);
[email protected]4f1633f2013-03-09 14:26:24594}
595
bashi61ca3c72015-06-26 00:40:10596v8::MaybeLocal<v8::Object> ModuleSystem::RequireNativeFromString(
[email protected]4f1633f2013-03-09 14:26:24597 const std::string& native_name) {
[email protected]95ee77da2013-03-19 21:11:11598 if (natives_enabled_ == 0) {
599 // HACK: if in test throw exception so that we can test the natives-disabled
600 // logic; however, under normal circumstances, this is programmer error so
601 // we could crash.
[email protected]9c47471e2013-11-28 14:41:21602 if (exception_handler_) {
bashi61ca3c72015-06-26 00:40:10603 GetIsolate()->ThrowException(
bashi6a4854f2015-06-19 00:51:51604 ToV8StringUnsafe(GetIsolate(), "Natives disabled"));
bashi61ca3c72015-06-26 00:40:10605 return v8::MaybeLocal<v8::Object>();
[email protected]9c47471e2013-11-28 14:41:21606 }
[email protected]662c48b2013-07-12 03:50:52607 Fatal(context_, "Natives disabled for requireNative(" + native_name + ")");
bashi61ca3c72015-06-26 00:40:10608 return v8::MaybeLocal<v8::Object>();
[email protected]95ee77da2013-03-19 21:11:11609 }
610
[email protected]9c47471e2013-11-28 14:41:21611 if (overridden_native_handlers_.count(native_name) > 0u) {
bashi61ca3c72015-06-26 00:40:10612 v8::Local<v8::Value> value = RequireForJsInner(
rdevlin.croninfedbe842017-06-24 02:12:03613 ToV8StringUnsafe(GetIsolate(), native_name.c_str()), true /* create */);
bashi61ca3c72015-06-26 00:40:10614 if (value.IsEmpty() || !value->IsObject())
615 return v8::MaybeLocal<v8::Object>();
616 return value.As<v8::Object>();
[email protected]9c47471e2013-11-28 14:41:21617 }
[email protected]95ee77da2013-03-19 21:11:11618
[email protected]58e10452012-02-22 03:34:45619 NativeHandlerMap::iterator i = native_handler_map_.find(native_name);
[email protected]95ee77da2013-03-19 21:11:11620 if (i == native_handler_map_.end()) {
[email protected]662c48b2013-07-12 03:50:52621 Fatal(context_,
[email protected]ad6aa8f92013-06-22 15:34:16622 "Couldn't find native for requireNative(" + native_name + ")");
bashi61ca3c72015-06-26 00:40:10623 return v8::MaybeLocal<v8::Object>();
[email protected]95ee77da2013-03-19 21:11:11624 }
[email protected]58e10452012-02-22 03:34:45625 return i->second->NewInstance();
626}
[email protected]ecde1912012-03-16 06:25:31627
[email protected]d9f51dad2014-07-09 05:39:38628void ModuleSystem::RequireAsync(
629 const v8::FunctionCallbackInfo<v8::Value>& args) {
630 CHECK_EQ(1, args.Length());
dcarneya261b772014-11-20 17:55:07631 std::string module_name = *v8::String::Utf8Value(args[0]);
bashi6a4854f2015-06-19 00:51:51632 v8::Local<v8::Context> v8_context = context_->v8_context();
tfarinaf85316f2015-04-29 17:03:40633 v8::Local<v8::Promise::Resolver> resolver(
bashi6a4854f2015-06-19 00:51:51634 v8::Promise::Resolver::New(v8_context).ToLocalChecked());
[email protected]d9f51dad2014-07-09 05:39:38635 args.GetReturnValue().Set(resolver->GetPromise());
dchengf6f80662016-04-20 20:26:04636 std::unique_ptr<v8::Global<v8::Promise::Resolver>> global_resolver(
kalman83292b82015-03-12 16:40:25637 new v8::Global<v8::Promise::Resolver>(GetIsolate(), resolver));
[email protected]d9f51dad2014-07-09 05:39:38638 gin::ModuleRegistry* module_registry =
bashi6a4854f2015-06-19 00:51:51639 gin::ModuleRegistry::From(v8_context);
[email protected]d9f51dad2014-07-09 05:39:38640 if (!module_registry) {
641 Warn(GetIsolate(), "Extension view no longer exists");
daniel.bevenius33ac37f2017-03-20 09:00:58642 auto maybe = resolver->Reject(
643 v8_context,
644 v8::Exception::Error(ToV8StringUnsafe(
645 GetIsolate(),
646 "Extension view no longer exists")));
647 CHECK(IsTrue(maybe));
[email protected]d9f51dad2014-07-09 05:39:38648 return;
649 }
kalman83292b82015-03-12 16:40:25650 module_registry->LoadModule(
651 GetIsolate(), module_name,
652 base::Bind(&ModuleSystem::OnModuleLoaded, weak_factory_.GetWeakPtr(),
653 base::Passed(&global_resolver)));
[email protected]d9f51dad2014-07-09 05:39:38654 if (module_registry->available_modules().count(module_name) == 0)
655 LoadModule(module_name);
656}
657
tfarinaf85316f2015-04-29 17:03:40658v8::Local<v8::String> ModuleSystem::WrapSource(v8::Local<v8::String> source) {
[email protected]95c6b3012013-12-02 14:30:31659 v8::EscapableHandleScope handle_scope(GetIsolate());
[email protected]295890bd2013-06-15 10:52:45660 // Keep in order with the arguments in RequireForJsInner.
bashi6a4854f2015-06-19 00:51:51661 v8::Local<v8::String> left = ToV8StringUnsafe(
[email protected]2a356872014-02-21 23:18:52662 GetIsolate(),
[email protected]d9f51dad2014-07-09 05:39:38663 "(function(define, require, requireNative, requireAsync, exports, "
rdevlin.cronine96ca6b2017-03-09 20:05:51664 "console, privates, apiBridge, bindingUtil, getInternalApi,"
[email protected]0d775c72014-08-22 13:06:26665 "$Array, $Function, $JSON, $Object, $RegExp, $String, $Error) {"
[email protected]2a356872014-02-21 23:18:52666 "'use strict';");
bashi6a4854f2015-06-19 00:51:51667 v8::Local<v8::String> right = ToV8StringUnsafe(GetIsolate(), "\n})");
[email protected]95c6b3012013-12-02 14:30:31668 return handle_scope.Escape(v8::Local<v8::String>(
669 v8::String::Concat(left, v8::String::Concat(source, right))));
[email protected]ecde1912012-03-16 06:25:31670}
671
[email protected]ca557292013-12-11 08:44:27672void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) {
673 CHECK_EQ(1, args.Length());
rob5c641ed2014-12-09 00:24:57674 if (!args[0]->IsObject() || args[0]->IsNull()) {
675 GetIsolate()->ThrowException(
bashi6a4854f2015-06-19 00:51:51676 v8::Exception::TypeError(ToV8StringUnsafe(GetIsolate(),
rob5c641ed2014-12-09 00:24:57677 args[0]->IsUndefined()
678 ? "Method called without a valid receiver (this). "
679 "Did you forget to call .bind()?"
680 : "Invalid invocation: receiver is not an object!")));
681 return;
682 }
[email protected]ca557292013-12-11 08:44:27683 v8::Local<v8::Object> obj = args[0].As<v8::Object>();
jochen300abe232015-11-06 21:17:53684 v8::Local<v8::Value> privates;
685 if (!GetPrivate(obj, "privates", &privates) || !privates->IsObject()) {
[email protected]505ffde2013-12-19 15:47:13686 privates = v8::Object::New(args.GetIsolate());
kalmanad8ddd02014-10-15 00:20:06687 if (privates.IsEmpty()) {
688 GetIsolate()->ThrowException(
bashi6a4854f2015-06-19 00:51:51689 ToV8StringUnsafe(GetIsolate(), "Failed to create privates"));
kalmanad8ddd02014-10-15 00:20:06690 return;
691 }
rob77e0fbe2016-04-22 23:16:54692 v8::Maybe<bool> maybe =
693 privates.As<v8::Object>()->SetPrototype(context()->v8_context(),
694 v8::Null(args.GetIsolate()));
695 CHECK(maybe.IsJust() && maybe.FromJust());
jochen300abe232015-11-06 21:17:53696 SetPrivate(obj, "privates", privates);
[email protected]ca557292013-12-11 08:44:27697 }
698 args.GetReturnValue().Set(privates);
699}
700
tfarinaf85316f2015-04-29 17:03:40701v8::Local<v8::Value> ModuleSystem::LoadModule(const std::string& module_name) {
rdevlin.cronin646703e2017-03-01 21:20:29702 return LoadModuleWithNativeAPIBridge(module_name,
rdevlin.cronin7bf55122016-12-22 01:55:38703 v8::Undefined(GetIsolate()));
704}
705
706v8::Local<v8::Value> ModuleSystem::LoadModuleWithNativeAPIBridge(
707 const std::string& module_name,
rdevlin.cronin646703e2017-03-01 21:20:29708 v8::Local<v8::Value> api_bridge) {
[email protected]d9f51dad2014-07-09 05:39:38709 v8::EscapableHandleScope handle_scope(GetIsolate());
bashi6a4854f2015-06-19 00:51:51710 v8::Local<v8::Context> v8_context = context()->v8_context();
711 v8::Context::Scope context_scope(v8_context);
[email protected]d9f51dad2014-07-09 05:39:38712
rdevlin.cronin1ed2e892016-12-06 21:35:43713 v8::Local<v8::String> source =
714 source_map_->GetSource(GetIsolate(), module_name);
715 if (source.IsEmpty()) {
[email protected]d9f51dad2014-07-09 05:39:38716 Fatal(context_, "No source for require(" + module_name + ")");
717 return v8::Undefined(GetIsolate());
718 }
rdevlin.cronin1ed2e892016-12-06 21:35:43719 v8::Local<v8::String> wrapped_source(WrapSource(source));
bashi6a4854f2015-06-19 00:51:51720 v8::Local<v8::String> v8_module_name;
721 if (!ToV8String(GetIsolate(), module_name.c_str(), &v8_module_name)) {
722 NOTREACHED() << "module_name is too long";
723 return v8::Undefined(GetIsolate());
724 }
[email protected]d9f51dad2014-07-09 05:39:38725 // Modules are wrapped in (function(){...}) so they always return functions.
tfarinaf85316f2015-04-29 17:03:40726 v8::Local<v8::Value> func_as_value =
bashi6a4854f2015-06-19 00:51:51727 RunString(wrapped_source, v8_module_name);
[email protected]d9f51dad2014-07-09 05:39:38728 if (func_as_value.IsEmpty() || func_as_value->IsUndefined()) {
729 Fatal(context_, "Bad source for require(" + module_name + ")");
730 return v8::Undefined(GetIsolate());
731 }
732
tfarinaf85316f2015-04-29 17:03:40733 v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(func_as_value);
[email protected]d9f51dad2014-07-09 05:39:38734
tfarinaf85316f2015-04-29 17:03:40735 v8::Local<v8::Object> define_object = v8::Object::New(GetIsolate());
[email protected]d9f51dad2014-07-09 05:39:38736 gin::ModuleRegistry::InstallGlobals(GetIsolate(), define_object);
737
rdevlin.cronin83a4b3a2015-10-28 21:43:58738 v8::Local<v8::Object> exports = v8::Object::New(GetIsolate());
739
740 v8::Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(
741 GetIsolate(),
742 &SetExportsProperty);
jochen596fd5e2016-07-06 12:29:50743 tmpl->RemovePrototype();
rdevlin.cronin83a4b3a2015-10-28 21:43:58744 v8::Local<v8::String> v8_key;
745 if (!v8_helpers::ToV8String(GetIsolate(), "$set", &v8_key)) {
746 NOTREACHED();
747 return v8::Undefined(GetIsolate());
748 }
749
750 v8::Local<v8::Function> function;
751 if (!tmpl->GetFunction(v8_context).ToLocal(&function)) {
752 NOTREACHED();
753 return v8::Undefined(GetIsolate());
754 }
755
jochen37ec8f42015-12-11 10:29:49756 exports->DefineOwnProperty(v8_context, v8_key, function, v8::ReadOnly)
757 .FromJust();
rdevlin.cronin83a4b3a2015-10-28 21:43:58758
tfarinaf85316f2015-04-29 17:03:40759 v8::Local<v8::Object> natives(NewInstance());
bashi6a4854f2015-06-19 00:51:51760 CHECK(!natives.IsEmpty()); // this can fail if v8 has issues
[email protected]d9f51dad2014-07-09 05:39:38761
rdevlin.cronin646703e2017-03-01 21:20:29762 v8::Local<v8::Value> get_internal_api;
763 if (get_internal_api_.IsEmpty()) {
764 get_internal_api = v8::Undefined(GetIsolate());
765 } else {
766 get_internal_api = get_internal_api_.Get(GetIsolate())
767 ->GetFunction(v8_context)
768 .ToLocalChecked();
769 }
770
rdevlin.cronine96ca6b2017-03-09 20:05:51771 v8::Local<v8::Value> binding_util;
772 if (!js_binding_util_getter_.is_null()) {
773 js_binding_util_getter_.Run(v8_context, &binding_util);
774 if (binding_util.IsEmpty()) {
775 // The NativeExtensionBindingsSystem was destroyed. This shouldn't happen,
776 // but JS makes the impossible possible!
777 NOTREACHED();
778 return v8::Undefined(GetIsolate());
779 }
780 } else {
781 binding_util = v8::Undefined(GetIsolate());
782 }
783
[email protected]d9f51dad2014-07-09 05:39:38784 // These must match the argument order in WrapSource.
tfarinaf85316f2015-04-29 17:03:40785 v8::Local<v8::Value> args[] = {
[email protected]d9f51dad2014-07-09 05:39:38786 // AMD.
bashi6a4854f2015-06-19 00:51:51787 GetPropertyUnsafe(v8_context, define_object, "define"),
[email protected]d9f51dad2014-07-09 05:39:38788 // CommonJS.
bashi6a4854f2015-06-19 00:51:51789 GetPropertyUnsafe(v8_context, natives, "require",
790 v8::NewStringType::kInternalized),
791 GetPropertyUnsafe(v8_context, natives, "requireNative",
792 v8::NewStringType::kInternalized),
793 GetPropertyUnsafe(v8_context, natives, "requireAsync",
794 v8::NewStringType::kInternalized),
[email protected]d9f51dad2014-07-09 05:39:38795 exports,
796 // Libraries that we magically expose to every module.
kalmanfb6f10ac2014-11-06 23:55:35797 console::AsV8Object(GetIsolate()),
bashi6a4854f2015-06-19 00:51:51798 GetPropertyUnsafe(v8_context, natives, "privates",
799 v8::NewStringType::kInternalized),
rdevlin.cronin47901cb2017-02-08 23:12:50800 api_bridge, // exposed as apiBridge.
rdevlin.cronine96ca6b2017-03-09 20:05:51801 binding_util, // exposed as bindingUtil.
rdevlin.cronin47901cb2017-02-08 23:12:50802 get_internal_api, // exposed as getInternalApi.
[email protected]d9f51dad2014-07-09 05:39:38803 // Each safe builtin. Keep in order with the arguments in WrapSource.
804 context_->safe_builtins()->GetArray(),
805 context_->safe_builtins()->GetFunction(),
806 context_->safe_builtins()->GetJSON(),
807 context_->safe_builtins()->GetObjekt(),
808 context_->safe_builtins()->GetRegExp(),
809 context_->safe_builtins()->GetString(),
[email protected]0d775c72014-08-22 13:06:26810 context_->safe_builtins()->GetError(),
[email protected]d9f51dad2014-07-09 05:39:38811 };
812 {
bashi6a4854f2015-06-19 00:51:51813 v8::TryCatch try_catch(GetIsolate());
[email protected]d9f51dad2014-07-09 05:39:38814 try_catch.SetCaptureMessage(true);
rdevlin.cronina9bc8cc2016-10-06 15:51:17815 context_->SafeCallFunction(func, arraysize(args), args);
[email protected]d9f51dad2014-07-09 05:39:38816 if (try_catch.HasCaught()) {
817 HandleException(try_catch);
818 return v8::Undefined(GetIsolate());
819 }
820 }
821 return handle_scope.Escape(exports);
822}
823
824void ModuleSystem::OnDidAddPendingModule(
825 const std::string& id,
826 const std::vector<std::string>& dependencies) {
sammc2cc226562015-01-14 01:25:06827 bool module_system_managed = source_map_->Contains(id);
[email protected]d9f51dad2014-07-09 05:39:38828
829 gin::ModuleRegistry* registry =
830 gin::ModuleRegistry::From(context_->v8_context());
831 DCHECK(registry);
sammc2cc226562015-01-14 01:25:06832 for (const auto& dependency : dependencies) {
833 // If a dependency is not available, and either the module or this
834 // dependency is managed by ModuleSystem, attempt to load it. Other
835 // gin::ModuleRegistry users (WebUI and users of the mojoPrivate API) are
836 // responsible for loading their module dependencies when required.
837 if (registry->available_modules().count(dependency) == 0 &&
838 (module_system_managed || source_map_->Contains(dependency))) {
839 LoadModule(dependency);
840 }
[email protected]d9f51dad2014-07-09 05:39:38841 }
842 registry->AttemptToLoadMoreModules(GetIsolate());
843}
844
845void ModuleSystem::OnModuleLoaded(
dchengf6f80662016-04-20 20:26:04846 std::unique_ptr<v8::Global<v8::Promise::Resolver>> resolver,
tfarinaf85316f2015-04-29 17:03:40847 v8::Local<v8::Value> value) {
[email protected]d9f51dad2014-07-09 05:39:38848 if (!is_valid())
849 return;
850 v8::HandleScope handle_scope(GetIsolate());
tfarinaf85316f2015-04-29 17:03:40851 v8::Local<v8::Promise::Resolver> resolver_local(
[email protected]d9f51dad2014-07-09 05:39:38852 v8::Local<v8::Promise::Resolver>::New(GetIsolate(), *resolver));
daniel.bevenius33ac37f2017-03-20 09:00:58853 auto maybe = resolver_local->Resolve(context()->v8_context(), value);
854 CHECK(IsTrue(maybe));
[email protected]d9f51dad2014-07-09 05:39:38855}
856
kalmanb0c1c502015-04-15 00:25:06857void ModuleSystem::ClobberExistingNativeHandler(const std::string& name) {
858 NativeHandlerMap::iterator existing_handler = native_handler_map_.find(name);
859 if (existing_handler != native_handler_map_.end()) {
tzik8f7af2922015-11-25 03:16:48860 clobbered_native_handlers_.push_back(std::move(existing_handler->second));
kalmanb0c1c502015-04-15 00:25:06861 native_handler_map_.erase(existing_handler);
862 }
863}
864
rdevlin.croninaac306632016-10-18 21:27:46865v8::Local<v8::Function> ModuleSystem::GetModuleFunction(
866 const std::string& module_name,
867 const std::string& method_name) {
868 v8::Local<v8::String> v8_module_name;
869 v8::Local<v8::String> v8_method_name;
rdevlin.croninaac306632016-10-18 21:27:46870 if (!ToV8String(GetIsolate(), module_name.c_str(), &v8_module_name) ||
871 !ToV8String(GetIsolate(), method_name.c_str(), &v8_method_name)) {
rdevlin.croninfedbe842017-06-24 02:12:03872 return v8::Local<v8::Function>();
rdevlin.croninaac306632016-10-18 21:27:46873 }
874
875 v8::Local<v8::Value> module;
rdevlin.croninfedbe842017-06-24 02:12:03876 // Important: don't create the module if it doesn't exist. Doing so would
877 // force a call into JS, which is something we want to avoid in case it has
878 // been suspended. Additionally, we should only be calling module methods for
879 // modules that have been instantiated.
880 bool create = false;
881 module = RequireForJsInner(v8_module_name, create);
882
883 // RequireForJsInner() returns Undefined in the case of a module not being
884 // loaded, since we don't create it here.
885 if (!module.IsEmpty() && module->IsUndefined())
886 return v8::Local<v8::Function>();
rdevlin.croninaac306632016-10-18 21:27:46887
888 if (module.IsEmpty() || !module->IsObject()) {
889 Fatal(context_,
890 "Failed to get module " + module_name + " to call " + method_name);
rdevlin.croninfedbe842017-06-24 02:12:03891 return v8::Local<v8::Function>();
rdevlin.croninaac306632016-10-18 21:27:46892 }
893
894 v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(module);
895 v8::Local<v8::Value> value;
896 if (!GetProperty(context()->v8_context(), object, v8_method_name, &value) ||
897 !value->IsFunction()) {
898 Fatal(context_, module_name + "." + method_name + " is not a function");
rdevlin.croninfedbe842017-06-24 02:12:03899 return v8::Local<v8::Function>();
rdevlin.croninaac306632016-10-18 21:27:46900 }
901
rdevlin.croninfedbe842017-06-24 02:12:03902 return v8::Local<v8::Function>::Cast(value);
rdevlin.croninaac306632016-10-18 21:27:46903}
904
[email protected]4e008e172013-06-13 20:15:48905} // namespace extensions