From 3bf34f27a1b231eec12ec999ca0f5d59bce9da14 Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Sat, 9 Dec 2017 10:32:34 -0600 Subject: [PATCH] src: flatten ContextifyContext MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flattens ContextifyContext allows the context interface to be used in other parts of the code base. PR-URL: https://github.com/nodejs/node/pull/17560 Reviewed-By: Michaƫl Zasso Reviewed-By: Tiancheng "Timothy" Gu --- node.gyp | 1 + src/node_contextify.cc | 852 ++++++++++++++++++++--------------------- src/node_contextify.h | 98 +++++ 3 files changed, 516 insertions(+), 435 deletions(-) create mode 100644 src/node_contextify.h diff --git a/node.gyp b/node.gyp index 36efe80f7a2107..95b32053a64ab9 100644 --- a/node.gyp +++ b/node.gyp @@ -351,6 +351,7 @@ 'src/node.h', 'src/node_buffer.h', 'src/node_constants.h', + 'src/node_contextify.h', 'src/node_debug_options.h', 'src/node_file.h', 'src/node_http2.h', diff --git a/src/node_contextify.cc b/src/node_contextify.cc index db907c63336cf7..c50cb19529c13d 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -22,8 +22,10 @@ #include "node_internals.h" #include "node_watchdog.h" #include "base_object-inl.h" +#include "node_contextify.h" namespace node { +namespace contextify { using v8::Array; using v8::ArrayBuffer; @@ -90,519 +92,499 @@ Local Uint32ToName(Local context, uint32_t index) { .ToLocalChecked(); } -class ContextifyContext { - protected: - // V8 reserves the first field in context objects for the debugger. We use the - // second field to hold a reference to the sandbox object. - enum { kSandboxObjectIndex = 1 }; - - Environment* const env_; - Persistent context_; - - public: - ContextifyContext(Environment* env, - Local sandbox_obj, - Local options_obj) - : env_(env) { - Local v8_context = CreateV8Context(env, sandbox_obj, options_obj); - context_.Reset(env->isolate(), v8_context); - - // Allocation failure or maximum call stack size reached - if (context_.IsEmpty()) - return; - context_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter); - context_.MarkIndependent(); - } - - - ~ContextifyContext() { - context_.Reset(); - } - +} // anonymous namespace - inline Environment* env() const { - return env_; - } +ContextifyContext::ContextifyContext( + Environment* env, + Local sandbox_obj, Local options_obj) : env_(env) { + Local v8_context = CreateV8Context(env, sandbox_obj, options_obj); + context_.Reset(env->isolate(), v8_context); + + // Allocation failure or maximum call stack size reached + if (context_.IsEmpty()) + return; + context_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter); + context_.MarkIndependent(); +} - inline Local context() const { - return PersistentToLocal(env()->isolate(), context_); - } +ContextifyContext::~ContextifyContext() { + context_.Reset(); +} - inline Local global_proxy() const { - return context()->Global(); - } +// This is an object that just keeps an internal pointer to this +// ContextifyContext. It's passed to the NamedPropertyHandler. If we +// pass the main JavaScript context object we're embedded in, then the +// NamedPropertyHandler will store a reference to it forever and keep it +// from getting gc'd. +Local ContextifyContext::CreateDataWrapper(Environment* env) { + EscapableHandleScope scope(env->isolate()); + Local wrapper = + env->script_data_constructor_function() + ->NewInstance(env->context()).FromMaybe(Local()); + if (wrapper.IsEmpty()) + return scope.Escape(Local::New(env->isolate(), Local())); + + Wrap(wrapper, this); + return scope.Escape(wrapper); +} - inline Local sandbox() const { - return Local::Cast(context()->GetEmbedderData(kSandboxObjectIndex)); +Local ContextifyContext::CreateV8Context( + Environment* env, + Local sandbox_obj, + Local options_obj) { + EscapableHandleScope scope(env->isolate()); + Local function_template = + FunctionTemplate::New(env->isolate()); + + function_template->SetClassName(sandbox_obj->GetConstructorName()); + + Local object_template = + function_template->InstanceTemplate(); + + NamedPropertyHandlerConfiguration config(PropertyGetterCallback, + PropertySetterCallback, + PropertyDescriptorCallback, + PropertyDeleterCallback, + PropertyEnumeratorCallback, + PropertyDefinerCallback, + CreateDataWrapper(env)); + + IndexedPropertyHandlerConfiguration indexed_config( + IndexedPropertyGetterCallback, + IndexedPropertySetterCallback, + IndexedPropertyDescriptorCallback, + IndexedPropertyDeleterCallback, + PropertyEnumeratorCallback, + IndexedPropertyDefinerCallback, + CreateDataWrapper(env)); + + object_template->SetHandler(config); + object_template->SetHandler(indexed_config); + + Local ctx = NewContext(env->isolate(), object_template); + + if (ctx.IsEmpty()) { + env->ThrowError("Could not instantiate context"); + return Local(); } - // This is an object that just keeps an internal pointer to this - // ContextifyContext. It's passed to the NamedPropertyHandler. If we - // pass the main JavaScript context object we're embedded in, then the - // NamedPropertyHandler will store a reference to it forever and keep it - // from getting gc'd. - Local CreateDataWrapper(Environment* env) { - EscapableHandleScope scope(env->isolate()); - Local wrapper = - env->script_data_constructor_function() - ->NewInstance(env->context()).FromMaybe(Local()); - if (wrapper.IsEmpty()) - return scope.Escape(Local::New(env->isolate(), Local())); - - Wrap(wrapper, this); - return scope.Escape(wrapper); + ctx->SetSecurityToken(env->context()->GetSecurityToken()); + + // We need to tie the lifetime of the sandbox object with the lifetime of + // newly created context. We do this by making them hold references to each + // other. The context can directly hold a reference to the sandbox as an + // embedder data field. However, we cannot hold a reference to a v8::Context + // directly in an Object, we instead hold onto the new context's global + // object instead (which then has a reference to the context). + ctx->SetEmbedderData(kSandboxObjectIndex, sandbox_obj); + sandbox_obj->SetPrivate(env->context(), + env->contextify_global_private_symbol(), + ctx->Global()); + + Local name = + options_obj->Get(env->context(), env->name_string()) + .ToLocalChecked(); + CHECK(name->IsString()); + Utf8Value name_val(env->isolate(), name); + + ContextInfo info(*name_val); + + Local origin = + options_obj->Get(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "origin")) + .ToLocalChecked(); + if (!origin->IsUndefined()) { + CHECK(origin->IsString()); + Utf8Value origin_val(env->isolate(), origin); + info.origin = *origin_val; } + env->AssignToContext(ctx, info); - Local CreateV8Context(Environment* env, - Local sandbox_obj, - Local options_obj) { - EscapableHandleScope scope(env->isolate()); - Local function_template = - FunctionTemplate::New(env->isolate()); - - function_template->SetClassName(sandbox_obj->GetConstructorName()); - - Local object_template = - function_template->InstanceTemplate(); - - NamedPropertyHandlerConfiguration config(PropertyGetterCallback, - PropertySetterCallback, - PropertyDescriptorCallback, - PropertyDeleterCallback, - PropertyEnumeratorCallback, - PropertyDefinerCallback, - CreateDataWrapper(env)); - - IndexedPropertyHandlerConfiguration indexed_config( - IndexedPropertyGetterCallback, - IndexedPropertySetterCallback, - IndexedPropertyDescriptorCallback, - IndexedPropertyDeleterCallback, - PropertyEnumeratorCallback, - IndexedPropertyDefinerCallback, - CreateDataWrapper(env)); - - object_template->SetHandler(config); - object_template->SetHandler(indexed_config); - - Local ctx = NewContext(env->isolate(), object_template); - - if (ctx.IsEmpty()) { - env->ThrowError("Could not instantiate context"); - return Local(); - } + return scope.Escape(ctx); +} - ctx->SetSecurityToken(env->context()->GetSecurityToken()); - - // We need to tie the lifetime of the sandbox object with the lifetime of - // newly created context. We do this by making them hold references to each - // other. The context can directly hold a reference to the sandbox as an - // embedder data field. However, we cannot hold a reference to a v8::Context - // directly in an Object, we instead hold onto the new context's global - // object instead (which then has a reference to the context). - ctx->SetEmbedderData(kSandboxObjectIndex, sandbox_obj); - sandbox_obj->SetPrivate(env->context(), - env->contextify_global_private_symbol(), - ctx->Global()); - - Local name = - options_obj->Get(env->context(), env->name_string()) - .ToLocalChecked(); - CHECK(name->IsString()); - Utf8Value name_val(env->isolate(), name); - - ContextInfo info(*name_val); - - Local origin = - options_obj->Get(env->context(), - FIXED_ONE_BYTE_STRING(env->isolate(), "origin")) - .ToLocalChecked(); - if (!origin->IsUndefined()) { - CHECK(origin->IsString()); - Utf8Value origin_val(env->isolate(), origin); - info.origin = *origin_val; - } - env->AssignToContext(ctx, info); +void ContextifyContext::Init(Environment* env, Local target) { + Local function_template = + FunctionTemplate::New(env->isolate()); + function_template->InstanceTemplate()->SetInternalFieldCount(1); + env->set_script_data_constructor_function(function_template->GetFunction()); - return scope.Escape(ctx); - } + env->SetMethod(target, "makeContext", MakeContext); + env->SetMethod(target, "isContext", IsContext); +} - static void Init(Environment* env, Local target) { - Local function_template = - FunctionTemplate::New(env->isolate()); - function_template->InstanceTemplate()->SetInternalFieldCount(1); - env->set_script_data_constructor_function(function_template->GetFunction()); +void ContextifyContext::MakeContext(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); - env->SetMethod(target, "makeContext", MakeContext); - env->SetMethod(target, "isContext", IsContext); + if (!args[0]->IsObject()) { + return env->ThrowTypeError("sandbox argument must be an object."); } + Local sandbox = args[0].As(); + // Don't allow contextifying a sandbox multiple times. + CHECK( + !sandbox->HasPrivate( + env->context(), + env->contextify_context_private_symbol()).FromJust()); - static void MakeContext(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); + Local options = args[1].As(); + CHECK(options->IsObject()); - if (!args[0]->IsObject()) { - return env->ThrowTypeError("sandbox argument must be an object."); - } - Local sandbox = args[0].As(); + TryCatch try_catch(env->isolate()); + ContextifyContext* context = new ContextifyContext(env, sandbox, options); - // Don't allow contextifying a sandbox multiple times. - CHECK( - !sandbox->HasPrivate( - env->context(), - env->contextify_context_private_symbol()).FromJust()); + if (try_catch.HasCaught()) { + try_catch.ReThrow(); + return; + } - Local options = args[1].As(); - CHECK(options->IsObject()); + if (context->context().IsEmpty()) + return; - TryCatch try_catch(env->isolate()); - ContextifyContext* context = new ContextifyContext(env, sandbox, options); + sandbox->SetPrivate( + env->context(), + env->contextify_context_private_symbol(), + External::New(env->isolate(), context)); +} - if (try_catch.HasCaught()) { - try_catch.ReThrow(); - return; - } - if (context->context().IsEmpty()) - return; +void ContextifyContext::IsContext(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); - sandbox->SetPrivate( - env->context(), - env->contextify_context_private_symbol(), - External::New(env->isolate(), context)); + if (!args[0]->IsObject()) { + env->ThrowTypeError("sandbox must be an object"); + return; } + Local sandbox = args[0].As(); + Maybe result = + sandbox->HasPrivate(env->context(), + env->contextify_context_private_symbol()); + args.GetReturnValue().Set(result.FromJust()); +} - static void IsContext(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - if (!args[0]->IsObject()) { - env->ThrowTypeError("sandbox must be an object"); - return; - } - Local sandbox = args[0].As(); +void ContextifyContext::WeakCallback( + const WeakCallbackInfo& data) { + ContextifyContext* context = data.GetParameter(); + delete context; +} - Maybe result = - sandbox->HasPrivate(env->context(), - env->contextify_context_private_symbol()); - args.GetReturnValue().Set(result.FromJust()); +// static +ContextifyContext* ContextifyContext::ContextFromContextifiedSandbox( + Environment* env, + const Local& sandbox) { + MaybeLocal maybe_value = + sandbox->GetPrivate(env->context(), + env->contextify_context_private_symbol()); + Local context_external_v; + if (maybe_value.ToLocal(&context_external_v) && + context_external_v->IsExternal()) { + Local context_external = context_external_v.As(); + return static_cast(context_external->Value()); } + return nullptr; +} - - static void WeakCallback(const WeakCallbackInfo& data) { - ContextifyContext* context = data.GetParameter(); - delete context; +// static +void ContextifyContext::PropertyGetterCallback( + Local property, + const PropertyCallbackInfo& args) { + ContextifyContext* ctx; + ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); + + // Still initializing + if (ctx->context_.IsEmpty()) + return; + + Local context = ctx->context(); + Local sandbox = ctx->sandbox(); + MaybeLocal maybe_rv = + sandbox->GetRealNamedProperty(context, property); + if (maybe_rv.IsEmpty()) { + maybe_rv = + ctx->global_proxy()->GetRealNamedProperty(context, property); } + Local rv; + if (maybe_rv.ToLocal(&rv)) { + if (rv == sandbox) + rv = ctx->global_proxy(); - static ContextifyContext* ContextFromContextifiedSandbox( - Environment* env, - const Local& sandbox) { - MaybeLocal maybe_value = - sandbox->GetPrivate(env->context(), - env->contextify_context_private_symbol()); - Local context_external_v; - if (maybe_value.ToLocal(&context_external_v) && - context_external_v->IsExternal()) { - Local context_external = context_external_v.As(); - return static_cast(context_external->Value()); - } - return nullptr; + args.GetReturnValue().Set(rv); } +} - - static void PropertyGetterCallback( - Local property, - const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); - - // Still initializing - if (ctx->context_.IsEmpty()) - return; - - Local context = ctx->context(); - Local sandbox = ctx->sandbox(); - MaybeLocal maybe_rv = - sandbox->GetRealNamedProperty(context, property); - if (maybe_rv.IsEmpty()) { - maybe_rv = - ctx->global_proxy()->GetRealNamedProperty(context, property); - } - - Local rv; - if (maybe_rv.ToLocal(&rv)) { - if (rv == sandbox) - rv = ctx->global_proxy(); - - args.GetReturnValue().Set(rv); - } - } - - - static void PropertySetterCallback( - Local property, - Local value, - const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); - - // Still initializing - if (ctx->context_.IsEmpty()) - return; - - auto attributes = PropertyAttribute::None; - bool is_declared_on_global_proxy = ctx->global_proxy() - ->GetRealNamedPropertyAttributes(ctx->context(), property) - .To(&attributes); - bool read_only = - static_cast(attributes) & - static_cast(PropertyAttribute::ReadOnly); - - bool is_declared_on_sandbox = ctx->sandbox() - ->GetRealNamedPropertyAttributes(ctx->context(), property) - .To(&attributes); - read_only = read_only || - (static_cast(attributes) & - static_cast(PropertyAttribute::ReadOnly)); - - if (read_only) - return; - - // true for x = 5 - // false for this.x = 5 - // false for Object.defineProperty(this, 'foo', ...) - // false for vmResult.x = 5 where vmResult = vm.runInContext(); - bool is_contextual_store = ctx->global_proxy() != args.This(); - - // Indicator to not return before setting (undeclared) function declarations - // on the sandbox in strict mode, i.e. args.ShouldThrowOnError() = true. - // True for 'function f() {}', 'this.f = function() {}', - // 'var f = function()'. - // In effect only for 'function f() {}' because - // var f = function(), is_declared = true - // this.f = function() {}, is_contextual_store = false. - bool is_function = value->IsFunction(); - - bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox; - if (!is_declared && args.ShouldThrowOnError() && is_contextual_store && - !is_function) - return; - - if (!is_declared_on_global_proxy && is_declared_on_sandbox && - args.ShouldThrowOnError() && is_contextual_store && !is_function) { - // The property exists on the sandbox but not on the global - // proxy. Setting it would throw because we are in strict mode. - // Don't attempt to set it by signaling that the call was - // intercepted. Only change the value on the sandbox. - args.GetReturnValue().Set(false); - } - - ctx->sandbox()->Set(property, value); +// static +void ContextifyContext::PropertySetterCallback( + Local property, + Local value, + const PropertyCallbackInfo& args) { + ContextifyContext* ctx; + ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); + + // Still initializing + if (ctx->context_.IsEmpty()) + return; + + auto attributes = PropertyAttribute::None; + bool is_declared_on_global_proxy = ctx->global_proxy() + ->GetRealNamedPropertyAttributes(ctx->context(), property) + .To(&attributes); + bool read_only = + static_cast(attributes) & + static_cast(PropertyAttribute::ReadOnly); + + bool is_declared_on_sandbox = ctx->sandbox() + ->GetRealNamedPropertyAttributes(ctx->context(), property) + .To(&attributes); + read_only = read_only || + (static_cast(attributes) & + static_cast(PropertyAttribute::ReadOnly)); + + if (read_only) + return; + + // true for x = 5 + // false for this.x = 5 + // false for Object.defineProperty(this, 'foo', ...) + // false for vmResult.x = 5 where vmResult = vm.runInContext(); + bool is_contextual_store = ctx->global_proxy() != args.This(); + + // Indicator to not return before setting (undeclared) function declarations + // on the sandbox in strict mode, i.e. args.ShouldThrowOnError() = true. + // True for 'function f() {}', 'this.f = function() {}', + // 'var f = function()'. + // In effect only for 'function f() {}' because + // var f = function(), is_declared = true + // this.f = function() {}, is_contextual_store = false. + bool is_function = value->IsFunction(); + + bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox; + if (!is_declared && args.ShouldThrowOnError() && is_contextual_store && + !is_function) + return; + + if (!is_declared_on_global_proxy && is_declared_on_sandbox && + args.ShouldThrowOnError() && is_contextual_store && !is_function) { + // The property exists on the sandbox but not on the global + // proxy. Setting it would throw because we are in strict mode. + // Don't attempt to set it by signaling that the call was + // intercepted. Only change the value on the sandbox. + args.GetReturnValue().Set(false); } + ctx->sandbox()->Set(property, value); +} - static void PropertyDescriptorCallback( - Local property, - const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); +// static +void ContextifyContext::PropertyDescriptorCallback( + Local property, + const PropertyCallbackInfo& args) { + ContextifyContext* ctx; + ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); - // Still initializing - if (ctx->context_.IsEmpty()) - return; + // Still initializing + if (ctx->context_.IsEmpty()) + return; - Local context = ctx->context(); + Local context = ctx->context(); - Local sandbox = ctx->sandbox(); + Local sandbox = ctx->sandbox(); - if (sandbox->HasOwnProperty(context, property).FromMaybe(false)) { - args.GetReturnValue().Set( - sandbox->GetOwnPropertyDescriptor(context, property) - .ToLocalChecked()); - } + if (sandbox->HasOwnProperty(context, property).FromMaybe(false)) { + args.GetReturnValue().Set( + sandbox->GetOwnPropertyDescriptor(context, property) + .ToLocalChecked()); } +} - - static void PropertyDefinerCallback( - Local property, - const PropertyDescriptor& desc, - const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); - - // Still initializing - if (ctx->context_.IsEmpty()) - return; - - Local context = ctx->context(); - v8::Isolate* isolate = context->GetIsolate(); - - auto attributes = PropertyAttribute::None; - bool is_declared = - ctx->global_proxy()->GetRealNamedPropertyAttributes(ctx->context(), - property) - .To(&attributes); - bool read_only = - static_cast(attributes) & - static_cast(PropertyAttribute::ReadOnly); - - // If the property is set on the global as read_only, don't change it on - // the global or sandbox. - if (is_declared && read_only) - return; - - Local sandbox = ctx->sandbox(); - - auto define_prop_on_sandbox = - [&] (PropertyDescriptor* desc_for_sandbox) { - if (desc.has_enumerable()) { - desc_for_sandbox->set_enumerable(desc.enumerable()); - } - if (desc.has_configurable()) { - desc_for_sandbox->set_configurable(desc.configurable()); - } - // Set the property on the sandbox. - sandbox->DefineProperty(context, property, *desc_for_sandbox) - .FromJust(); - }; - - if (desc.has_get() || desc.has_set()) { - PropertyDescriptor desc_for_sandbox( - desc.has_get() ? desc.get() : v8::Undefined(isolate).As(), - desc.has_set() ? desc.set() : v8::Undefined(isolate).As()); - +// static +void ContextifyContext::PropertyDefinerCallback( + Local property, + const PropertyDescriptor& desc, + const PropertyCallbackInfo& args) { + ContextifyContext* ctx; + ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); + + // Still initializing + if (ctx->context_.IsEmpty()) + return; + + Local context = ctx->context(); + v8::Isolate* isolate = context->GetIsolate(); + + auto attributes = PropertyAttribute::None; + bool is_declared = + ctx->global_proxy()->GetRealNamedPropertyAttributes(ctx->context(), + property) + .To(&attributes); + bool read_only = + static_cast(attributes) & + static_cast(PropertyAttribute::ReadOnly); + + // If the property is set on the global as read_only, don't change it on + // the global or sandbox. + if (is_declared && read_only) + return; + + Local sandbox = ctx->sandbox(); + + auto define_prop_on_sandbox = + [&] (PropertyDescriptor* desc_for_sandbox) { + if (desc.has_enumerable()) { + desc_for_sandbox->set_enumerable(desc.enumerable()); + } + if (desc.has_configurable()) { + desc_for_sandbox->set_configurable(desc.configurable()); + } + // Set the property on the sandbox. + sandbox->DefineProperty(context, property, *desc_for_sandbox) + .FromJust(); + }; + + if (desc.has_get() || desc.has_set()) { + PropertyDescriptor desc_for_sandbox( + desc.has_get() ? desc.get() : v8::Undefined(isolate).As(), + desc.has_set() ? desc.set() : v8::Undefined(isolate).As()); + + define_prop_on_sandbox(&desc_for_sandbox); + } else { + Local value = + desc.has_value() ? desc.value() : v8::Undefined(isolate).As(); + + if (desc.has_writable()) { + PropertyDescriptor desc_for_sandbox(value, desc.writable()); define_prop_on_sandbox(&desc_for_sandbox); } else { - Local value = - desc.has_value() ? desc.value() : v8::Undefined(isolate).As(); - - if (desc.has_writable()) { - PropertyDescriptor desc_for_sandbox(value, desc.writable()); - define_prop_on_sandbox(&desc_for_sandbox); - } else { - PropertyDescriptor desc_for_sandbox(value); - define_prop_on_sandbox(&desc_for_sandbox); - } + PropertyDescriptor desc_for_sandbox(value); + define_prop_on_sandbox(&desc_for_sandbox); } } +} - static void PropertyDeleterCallback( - Local property, - const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); - - // Still initializing - if (ctx->context_.IsEmpty()) - return; +// static +void ContextifyContext::PropertyDeleterCallback( + Local property, + const PropertyCallbackInfo& args) { + ContextifyContext* ctx; + ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); - Maybe success = ctx->sandbox()->Delete(ctx->context(), property); + // Still initializing + if (ctx->context_.IsEmpty()) + return; - if (success.FromMaybe(false)) - return; + Maybe success = ctx->sandbox()->Delete(ctx->context(), property); - // Delete failed on the sandbox, intercept and do not delete on - // the global object. - args.GetReturnValue().Set(false); - } + if (success.FromMaybe(false)) + return; + // Delete failed on the sandbox, intercept and do not delete on + // the global object. + args.GetReturnValue().Set(false); +} - static void PropertyEnumeratorCallback( - const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); +// static +void ContextifyContext::PropertyEnumeratorCallback( + const PropertyCallbackInfo& args) { + ContextifyContext* ctx; + ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); - // Still initializing - if (ctx->context_.IsEmpty()) - return; + // Still initializing + if (ctx->context_.IsEmpty()) + return; - args.GetReturnValue().Set(ctx->sandbox()->GetPropertyNames()); - } - - static void IndexedPropertyGetterCallback( - uint32_t index, - const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); + args.GetReturnValue().Set(ctx->sandbox()->GetPropertyNames()); +} - // Still initializing - if (ctx->context_.IsEmpty()) - return; +// static +void ContextifyContext::IndexedPropertyGetterCallback( + uint32_t index, + const PropertyCallbackInfo& args) { + ContextifyContext* ctx; + ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); - PropertyGetterCallback(Uint32ToName(ctx->context(), index), args); - } + // Still initializing + if (ctx->context_.IsEmpty()) + return; + ContextifyContext::PropertyGetterCallback( + Uint32ToName(ctx->context(), index), args); +} - static void IndexedPropertySetterCallback( - uint32_t index, - Local value, - const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); - // Still initializing - if (ctx->context_.IsEmpty()) - return; +void ContextifyContext::IndexedPropertySetterCallback( + uint32_t index, + Local value, + const PropertyCallbackInfo& args) { + ContextifyContext* ctx; + ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); - PropertySetterCallback(Uint32ToName(ctx->context(), index), value, args); - } + // Still initializing + if (ctx->context_.IsEmpty()) + return; + ContextifyContext::PropertySetterCallback( + Uint32ToName(ctx->context(), index), value, args); +} - static void IndexedPropertyDescriptorCallback( - uint32_t index, - const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); +// static +void ContextifyContext::IndexedPropertyDescriptorCallback( + uint32_t index, + const PropertyCallbackInfo& args) { + ContextifyContext* ctx; + ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); - // Still initializing - if (ctx->context_.IsEmpty()) - return; + // Still initializing + if (ctx->context_.IsEmpty()) + return; - PropertyDescriptorCallback(Uint32ToName(ctx->context(), index), args); - } + ContextifyContext::PropertyDescriptorCallback( + Uint32ToName(ctx->context(), index), args); +} - static void IndexedPropertyDefinerCallback( - uint32_t index, - const PropertyDescriptor& desc, - const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); +void ContextifyContext::IndexedPropertyDefinerCallback( + uint32_t index, + const PropertyDescriptor& desc, + const PropertyCallbackInfo& args) { + ContextifyContext* ctx; + ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); - // Still initializing - if (ctx->context_.IsEmpty()) - return; + // Still initializing + if (ctx->context_.IsEmpty()) + return; - PropertyDefinerCallback(Uint32ToName(ctx->context(), index), desc, args); - } + ContextifyContext::PropertyDefinerCallback( + Uint32ToName(ctx->context(), index), desc, args); +} - static void IndexedPropertyDeleterCallback( - uint32_t index, - const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); +// static +void ContextifyContext::IndexedPropertyDeleterCallback( + uint32_t index, + const PropertyCallbackInfo& args) { + ContextifyContext* ctx; + ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); - // Still initializing - if (ctx->context_.IsEmpty()) - return; + // Still initializing + if (ctx->context_.IsEmpty()) + return; - Maybe success = ctx->sandbox()->Delete(ctx->context(), index); + Maybe success = ctx->sandbox()->Delete(ctx->context(), index); - if (success.FromMaybe(false)) - return; + if (success.FromMaybe(false)) + return; - // Delete failed on the sandbox, intercept and do not delete on - // the global object. - args.GetReturnValue().Set(false); - } -}; + // Delete failed on the sandbox, intercept and do not delete on + // the global object. + args.GetReturnValue().Set(false); +} class ContextifyScript : public BaseObject { private: @@ -1161,7 +1143,7 @@ void InitContextify(Local target, ContextifyScript::Init(env, target); } -} // anonymous namespace +} // namespace contextify } // namespace node -NODE_BUILTIN_MODULE_CONTEXT_AWARE(contextify, node::InitContextify) +NODE_BUILTIN_MODULE_CONTEXT_AWARE(contextify, node::contextify::InitContextify) diff --git a/src/node_contextify.h b/src/node_contextify.h new file mode 100644 index 00000000000000..e8a54e1667cc31 --- /dev/null +++ b/src/node_contextify.h @@ -0,0 +1,98 @@ +#ifndef SRC_NODE_CONTEXTIFY_H_ +#define SRC_NODE_CONTEXTIFY_H_ + +#include "node_internals.h" +#include "node_watchdog.h" +#include "base_object-inl.h" + +namespace node { +namespace contextify { + +class ContextifyContext { + protected: + // V8 reserves the first field in context objects for the debugger. We use the + // second field to hold a reference to the sandbox object. + enum { kSandboxObjectIndex = 1 }; + + Environment* const env_; + v8::Persistent context_; + + public: + ContextifyContext(Environment* env, + v8::Local sandbox_obj, + v8::Local options_obj); + ~ContextifyContext(); + + v8::Local CreateDataWrapper(Environment* env); + v8::Local CreateV8Context(Environment* env, + v8::Local sandbox_obj, v8::Local options_obj); + static void Init(Environment* env, v8::Local target); + + static ContextifyContext* ContextFromContextifiedSandbox( + Environment* env, + const v8::Local& sandbox); + + inline Environment* env() const { + return env_; + } + + inline v8::Local context() const { + return PersistentToLocal(env()->isolate(), context_); + } + + inline v8::Local global_proxy() const { + return context()->Global(); + } + + inline v8::Local sandbox() const { + return v8::Local::Cast( + context()->GetEmbedderData(kSandboxObjectIndex)); + } + + private: + static void MakeContext(const v8::FunctionCallbackInfo& args); + static void IsContext(const v8::FunctionCallbackInfo& args); + static void WeakCallback( + const v8::WeakCallbackInfo& data); + static void PropertyGetterCallback( + v8::Local property, + const v8::PropertyCallbackInfo& args); + static void PropertySetterCallback( + v8::Local property, + v8::Local value, + const v8::PropertyCallbackInfo& args); + static void PropertyDescriptorCallback( + v8::Local property, + const v8::PropertyCallbackInfo& args); + static void PropertyDefinerCallback( + v8::Local property, + const v8::PropertyDescriptor& desc, + const v8::PropertyCallbackInfo& args); + static void PropertyDeleterCallback( + v8::Local property, + const v8::PropertyCallbackInfo& args); + static void PropertyEnumeratorCallback( + const v8::PropertyCallbackInfo& args); + static void IndexedPropertyGetterCallback( + uint32_t index, + const v8::PropertyCallbackInfo& args); + static void IndexedPropertySetterCallback( + uint32_t index, + v8::Local value, + const v8::PropertyCallbackInfo& args); + static void IndexedPropertyDescriptorCallback( + uint32_t index, + const v8::PropertyCallbackInfo& args); + static void IndexedPropertyDefinerCallback( + uint32_t index, + const v8::PropertyDescriptor& desc, + const v8::PropertyCallbackInfo& args); + static void IndexedPropertyDeleterCallback( + uint32_t index, + const v8::PropertyCallbackInfo& args); +}; + +} // namespace contextify +} // namespace node + +#endif // SRC_NODE_CONTEXTIFY_H_