summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGus Caplan <me@gus.host>2017-12-09 10:32:34 -0600
committerTimothy Gu <timothygu99@gmail.com>2018-01-30 17:00:57 -0800
commit3bf34f27a1b231eec12ec999ca0f5d59bce9da14 (patch)
treeef2e6484b77c9e1ad99575add0377632bc5fa114 /src
parent70277d6170b5c18322542b3980564a74c3d8d1b3 (diff)
downloadandroid-node-v8-3bf34f27a1b231eec12ec999ca0f5d59bce9da14.tar.gz
android-node-v8-3bf34f27a1b231eec12ec999ca0f5d59bce9da14.tar.bz2
android-node-v8-3bf34f27a1b231eec12ec999ca0f5d59bce9da14.zip
src: flatten ContextifyContext
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 <targos@protonmail.com> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/node_contextify.cc852
-rw-r--r--src/node_contextify.h98
2 files changed, 515 insertions, 435 deletions
diff --git a/src/node_contextify.cc b/src/node_contextify.cc
index db907c6333..c50cb19529 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<Name> Uint32ToName(Local<Context> 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> context_;
-
- public:
- ContextifyContext(Environment* env,
- Local<Object> sandbox_obj,
- Local<Object> options_obj)
- : env_(env) {
- Local<Context> 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<Object> sandbox_obj, Local<Object> options_obj) : env_(env) {
+ Local<Context> 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> context() const {
- return PersistentToLocal(env()->isolate(), context_);
- }
+ContextifyContext::~ContextifyContext() {
+ context_.Reset();
+}
- inline Local<Object> 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<Value> ContextifyContext::CreateDataWrapper(Environment* env) {
+ EscapableHandleScope scope(env->isolate());
+ Local<Object> wrapper =
+ env->script_data_constructor_function()
+ ->NewInstance(env->context()).FromMaybe(Local<Object>());
+ if (wrapper.IsEmpty())
+ return scope.Escape(Local<Value>::New(env->isolate(), Local<Value>()));
+
+ Wrap(wrapper, this);
+ return scope.Escape(wrapper);
+}
- inline Local<Object> sandbox() const {
- return Local<Object>::Cast(context()->GetEmbedderData(kSandboxObjectIndex));
+Local<Context> ContextifyContext::CreateV8Context(
+ Environment* env,
+ Local<Object> sandbox_obj,
+ Local<Object> options_obj) {
+ EscapableHandleScope scope(env->isolate());
+ Local<FunctionTemplate> function_template =
+ FunctionTemplate::New(env->isolate());
+
+ function_template->SetClassName(sandbox_obj->GetConstructorName());
+
+ Local<ObjectTemplate> 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<Context> ctx = NewContext(env->isolate(), object_template);
+
+ if (ctx.IsEmpty()) {
+ env->ThrowError("Could not instantiate context");
+ return Local<Context>();
}
- // 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<Value> CreateDataWrapper(Environment* env) {
- EscapableHandleScope scope(env->isolate());
- Local<Object> wrapper =
- env->script_data_constructor_function()
- ->NewInstance(env->context()).FromMaybe(Local<Object>());
- if (wrapper.IsEmpty())
- return scope.Escape(Local<Value>::New(env->isolate(), Local<Value>()));
-
- 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<Value> name =
+ options_obj->Get(env->context(), env->name_string())
+ .ToLocalChecked();
+ CHECK(name->IsString());
+ Utf8Value name_val(env->isolate(), name);
+
+ ContextInfo info(*name_val);
+
+ Local<Value> 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<Context> CreateV8Context(Environment* env,
- Local<Object> sandbox_obj,
- Local<Object> options_obj) {
- EscapableHandleScope scope(env->isolate());
- Local<FunctionTemplate> function_template =
- FunctionTemplate::New(env->isolate());
-
- function_template->SetClassName(sandbox_obj->GetConstructorName());
-
- Local<ObjectTemplate> 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<Context> ctx = NewContext(env->isolate(), object_template);
-
- if (ctx.IsEmpty()) {
- env->ThrowError("Could not instantiate context");
- return Local<Context>();
- }
+ 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<Value> name =
- options_obj->Get(env->context(), env->name_string())
- .ToLocalChecked();
- CHECK(name->IsString());
- Utf8Value name_val(env->isolate(), name);
-
- ContextInfo info(*name_val);
-
- Local<Value> 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<Object> target) {
+ Local<FunctionTemplate> 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<Object> target) {
- Local<FunctionTemplate> 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<Value>& 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<Object> sandbox = args[0].As<Object>();
+ // Don't allow contextifying a sandbox multiple times.
+ CHECK(
+ !sandbox->HasPrivate(
+ env->context(),
+ env->contextify_context_private_symbol()).FromJust());
- static void MakeContext(const FunctionCallbackInfo<Value>& args) {
- Environment* env = Environment::GetCurrent(args);
+ Local<Object> options = args[1].As<Object>();
+ CHECK(options->IsObject());
- if (!args[0]->IsObject()) {
- return env->ThrowTypeError("sandbox argument must be an object.");
- }
- Local<Object> sandbox = args[0].As<Object>();
+ 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<Object> options = args[1].As<Object>();
- 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<Value>& 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<Object> sandbox = args[0].As<Object>();
+ Maybe<bool> result =
+ sandbox->HasPrivate(env->context(),
+ env->contextify_context_private_symbol());
+ args.GetReturnValue().Set(result.FromJust());
+}
- static void IsContext(const FunctionCallbackInfo<Value>& args) {
- Environment* env = Environment::GetCurrent(args);
- if (!args[0]->IsObject()) {
- env->ThrowTypeError("sandbox must be an object");
- return;
- }
- Local<Object> sandbox = args[0].As<Object>();
+void ContextifyContext::WeakCallback(
+ const WeakCallbackInfo<ContextifyContext>& data) {
+ ContextifyContext* context = data.GetParameter();
+ delete context;
+}
- Maybe<bool> result =
- sandbox->HasPrivate(env->context(),
- env->contextify_context_private_symbol());
- args.GetReturnValue().Set(result.FromJust());
+// static
+ContextifyContext* ContextifyContext::ContextFromContextifiedSandbox(
+ Environment* env,
+ const Local<Object>& sandbox) {
+ MaybeLocal<Value> maybe_value =
+ sandbox->GetPrivate(env->context(),
+ env->contextify_context_private_symbol());
+ Local<Value> context_external_v;
+ if (maybe_value.ToLocal(&context_external_v) &&
+ context_external_v->IsExternal()) {
+ Local<External> context_external = context_external_v.As<External>();
+ return static_cast<ContextifyContext*>(context_external->Value());
}
+ return nullptr;
+}
-
- static void WeakCallback(const WeakCallbackInfo<ContextifyContext>& data) {
- ContextifyContext* context = data.GetParameter();
- delete context;
+// static
+void ContextifyContext::PropertyGetterCallback(
+ Local<Name> property,
+ const PropertyCallbackInfo<Value>& args) {
+ ContextifyContext* ctx;
+ ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
+
+ // Still initializing
+ if (ctx->context_.IsEmpty())
+ return;
+
+ Local<Context> context = ctx->context();
+ Local<Object> sandbox = ctx->sandbox();
+ MaybeLocal<Value> maybe_rv =
+ sandbox->GetRealNamedProperty(context, property);
+ if (maybe_rv.IsEmpty()) {
+ maybe_rv =
+ ctx->global_proxy()->GetRealNamedProperty(context, property);
}
+ Local<Value> rv;
+ if (maybe_rv.ToLocal(&rv)) {
+ if (rv == sandbox)
+ rv = ctx->global_proxy();
- static ContextifyContext* ContextFromContextifiedSandbox(
- Environment* env,
- const Local<Object>& sandbox) {
- MaybeLocal<Value> maybe_value =
- sandbox->GetPrivate(env->context(),
- env->contextify_context_private_symbol());
- Local<Value> context_external_v;
- if (maybe_value.ToLocal(&context_external_v) &&
- context_external_v->IsExternal()) {
- Local<External> context_external = context_external_v.As<External>();
- return static_cast<ContextifyContext*>(context_external->Value());
- }
- return nullptr;
+ args.GetReturnValue().Set(rv);
}
+}
-
- static void PropertyGetterCallback(
- Local<Name> property,
- const PropertyCallbackInfo<Value>& args) {
- ContextifyContext* ctx;
- ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
-
- // Still initializing
- if (ctx->context_.IsEmpty())
- return;
-
- Local<Context> context = ctx->context();
- Local<Object> sandbox = ctx->sandbox();
- MaybeLocal<Value> maybe_rv =
- sandbox->GetRealNamedProperty(context, property);
- if (maybe_rv.IsEmpty()) {
- maybe_rv =
- ctx->global_proxy()->GetRealNamedProperty(context, property);
- }
-
- Local<Value> rv;
- if (maybe_rv.ToLocal(&rv)) {
- if (rv == sandbox)
- rv = ctx->global_proxy();
-
- args.GetReturnValue().Set(rv);
- }
- }
-
-
- static void PropertySetterCallback(
- Local<Name> property,
- Local<Value> value,
- const PropertyCallbackInfo<Value>& args) {
- ContextifyContext* ctx;
- ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
-
- // 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<int>(attributes) &
- static_cast<int>(PropertyAttribute::ReadOnly);
-
- bool is_declared_on_sandbox = ctx->sandbox()
- ->GetRealNamedPropertyAttributes(ctx->context(), property)
- .To(&attributes);
- read_only = read_only ||
- (static_cast<int>(attributes) &
- static_cast<int>(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<Name> property,
+ Local<Value> value,
+ const PropertyCallbackInfo<Value>& args) {
+ ContextifyContext* ctx;
+ ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
+
+ // 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<int>(attributes) &
+ static_cast<int>(PropertyAttribute::ReadOnly);
+
+ bool is_declared_on_sandbox = ctx->sandbox()
+ ->GetRealNamedPropertyAttributes(ctx->context(), property)
+ .To(&attributes);
+ read_only = read_only ||
+ (static_cast<int>(attributes) &
+ static_cast<int>(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<Name> property,
- const PropertyCallbackInfo<Value>& args) {
- ContextifyContext* ctx;
- ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
+// static
+void ContextifyContext::PropertyDescriptorCallback(
+ Local<Name> property,
+ const PropertyCallbackInfo<Value>& args) {
+ ContextifyContext* ctx;
+ ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
- // Still initializing
- if (ctx->context_.IsEmpty())
- return;
+ // Still initializing
+ if (ctx->context_.IsEmpty())
+ return;
- Local<Context> context = ctx->context();
+ Local<Context> context = ctx->context();
- Local<Object> sandbox = ctx->sandbox();
+ Local<Object> 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<Name> property,
- const PropertyDescriptor& desc,
- const PropertyCallbackInfo<Value>& args) {
- ContextifyContext* ctx;
- ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
-
- // Still initializing
- if (ctx->context_.IsEmpty())
- return;
-
- Local<Context> 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<int>(attributes) &
- static_cast<int>(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<Object> 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<Value>(),
- desc.has_set() ? desc.set() : v8::Undefined(isolate).As<Value>());
-
+// static
+void ContextifyContext::PropertyDefinerCallback(
+ Local<Name> property,
+ const PropertyDescriptor& desc,
+ const PropertyCallbackInfo<Value>& args) {
+ ContextifyContext* ctx;
+ ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
+
+ // Still initializing
+ if (ctx->context_.IsEmpty())
+ return;
+
+ Local<Context> 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<int>(attributes) &
+ static_cast<int>(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<Object> 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<Value>(),
+ desc.has_set() ? desc.set() : v8::Undefined(isolate).As<Value>());
+
+ define_prop_on_sandbox(&desc_for_sandbox);
+ } else {
+ Local<Value> value =
+ desc.has_value() ? desc.value() : v8::Undefined(isolate).As<Value>();
+
+ if (desc.has_writable()) {
+ PropertyDescriptor desc_for_sandbox(value, desc.writable());
define_prop_on_sandbox(&desc_for_sandbox);
} else {
- Local<Value> value =
- desc.has_value() ? desc.value() : v8::Undefined(isolate).As<Value>();
-
- 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<Name> property,
- const PropertyCallbackInfo<Boolean>& args) {
- ContextifyContext* ctx;
- ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
-
- // Still initializing
- if (ctx->context_.IsEmpty())
- return;
+// static
+void ContextifyContext::PropertyDeleterCallback(
+ Local<Name> property,
+ const PropertyCallbackInfo<Boolean>& args) {
+ ContextifyContext* ctx;
+ ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
- Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), property);
+ // Still initializing
+ if (ctx->context_.IsEmpty())
+ return;
- if (success.FromMaybe(false))
- return;
+ Maybe<bool> 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<Array>& args) {
- ContextifyContext* ctx;
- ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
+// static
+void ContextifyContext::PropertyEnumeratorCallback(
+ const PropertyCallbackInfo<Array>& args) {
+ ContextifyContext* ctx;
+ ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
- // 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<Value>& args) {
- ContextifyContext* ctx;
- ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
+ args.GetReturnValue().Set(ctx->sandbox()->GetPropertyNames());
+}
- // Still initializing
- if (ctx->context_.IsEmpty())
- return;
+// static
+void ContextifyContext::IndexedPropertyGetterCallback(
+ uint32_t index,
+ const PropertyCallbackInfo<Value>& args) {
+ ContextifyContext* ctx;
+ ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
- 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> value,
- const PropertyCallbackInfo<Value>& args) {
- ContextifyContext* ctx;
- ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
- // Still initializing
- if (ctx->context_.IsEmpty())
- return;
+void ContextifyContext::IndexedPropertySetterCallback(
+ uint32_t index,
+ Local<Value> value,
+ const PropertyCallbackInfo<Value>& args) {
+ ContextifyContext* ctx;
+ ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
- 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<Value>& args) {
- ContextifyContext* ctx;
- ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
+// static
+void ContextifyContext::IndexedPropertyDescriptorCallback(
+ uint32_t index,
+ const PropertyCallbackInfo<Value>& args) {
+ ContextifyContext* ctx;
+ ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
- // 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<Value>& args) {
- ContextifyContext* ctx;
- ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
+void ContextifyContext::IndexedPropertyDefinerCallback(
+ uint32_t index,
+ const PropertyDescriptor& desc,
+ const PropertyCallbackInfo<Value>& args) {
+ ContextifyContext* ctx;
+ ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
- // 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<Boolean>& args) {
- ContextifyContext* ctx;
- ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
+// static
+void ContextifyContext::IndexedPropertyDeleterCallback(
+ uint32_t index,
+ const PropertyCallbackInfo<Boolean>& args) {
+ ContextifyContext* ctx;
+ ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As<Object>());
- // Still initializing
- if (ctx->context_.IsEmpty())
- return;
+ // Still initializing
+ if (ctx->context_.IsEmpty())
+ return;
- Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), index);
+ Maybe<bool> 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<Object> 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 0000000000..e8a54e1667
--- /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<v8::Context> context_;
+
+ public:
+ ContextifyContext(Environment* env,
+ v8::Local<v8::Object> sandbox_obj,
+ v8::Local<v8::Object> options_obj);
+ ~ContextifyContext();
+
+ v8::Local<v8::Value> CreateDataWrapper(Environment* env);
+ v8::Local<v8::Context> CreateV8Context(Environment* env,
+ v8::Local<v8::Object> sandbox_obj, v8::Local<v8::Object> options_obj);
+ static void Init(Environment* env, v8::Local<v8::Object> target);
+
+ static ContextifyContext* ContextFromContextifiedSandbox(
+ Environment* env,
+ const v8::Local<v8::Object>& sandbox);
+
+ inline Environment* env() const {
+ return env_;
+ }
+
+ inline v8::Local<v8::Context> context() const {
+ return PersistentToLocal(env()->isolate(), context_);
+ }
+
+ inline v8::Local<v8::Object> global_proxy() const {
+ return context()->Global();
+ }
+
+ inline v8::Local<v8::Object> sandbox() const {
+ return v8::Local<v8::Object>::Cast(
+ context()->GetEmbedderData(kSandboxObjectIndex));
+ }
+
+ private:
+ static void MakeContext(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void IsContext(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void WeakCallback(
+ const v8::WeakCallbackInfo<ContextifyContext>& data);
+ static void PropertyGetterCallback(
+ v8::Local<v8::Name> property,
+ const v8::PropertyCallbackInfo<v8::Value>& args);
+ static void PropertySetterCallback(
+ v8::Local<v8::Name> property,
+ v8::Local<v8::Value> value,
+ const v8::PropertyCallbackInfo<v8::Value>& args);
+ static void PropertyDescriptorCallback(
+ v8::Local<v8::Name> property,
+ const v8::PropertyCallbackInfo<v8::Value>& args);
+ static void PropertyDefinerCallback(
+ v8::Local<v8::Name> property,
+ const v8::PropertyDescriptor& desc,
+ const v8::PropertyCallbackInfo<v8::Value>& args);
+ static void PropertyDeleterCallback(
+ v8::Local<v8::Name> property,
+ const v8::PropertyCallbackInfo<v8::Boolean>& args);
+ static void PropertyEnumeratorCallback(
+ const v8::PropertyCallbackInfo<v8::Array>& args);
+ static void IndexedPropertyGetterCallback(
+ uint32_t index,
+ const v8::PropertyCallbackInfo<v8::Value>& args);
+ static void IndexedPropertySetterCallback(
+ uint32_t index,
+ v8::Local<v8::Value> value,
+ const v8::PropertyCallbackInfo<v8::Value>& args);
+ static void IndexedPropertyDescriptorCallback(
+ uint32_t index,
+ const v8::PropertyCallbackInfo<v8::Value>& args);
+ static void IndexedPropertyDefinerCallback(
+ uint32_t index,
+ const v8::PropertyDescriptor& desc,
+ const v8::PropertyCallbackInfo<v8::Value>& args);
+ static void IndexedPropertyDeleterCallback(
+ uint32_t index,
+ const v8::PropertyCallbackInfo<v8::Boolean>& args);
+};
+
+} // namespace contextify
+} // namespace node
+
+#endif // SRC_NODE_CONTEXTIFY_H_