var NativeModule = require('native_module');
var util = NativeModule.require('util');
-var Script = process.binding('evals').NodeScript;
-var runInThisContext = Script.runInThisContext;
-var runInNewContext = Script.runInNewContext;
+var runInThisContext = require('vm').runInThisContext;
+var runInNewContext = require('vm').runInNewContext;
var assert = require('assert').ok;
sandbox.global = sandbox;
sandbox.root = root;
- return runInNewContext(content, sandbox, filename, 0, true);
+ return runInNewContext(content, sandbox, filename);
}
debug('load root module');
global.__dirname = dirname;
global.module = self;
- return runInThisContext(content, filename, 0, true);
+ return runInThisContext(content, filename);
}
// create wrapper function
var wrapper = Module.wrap(content);
- var compiledWrapper = runInThisContext(wrapper, filename, 0, true);
+ var compiledWrapper = runInThisContext(wrapper, filename);
if (global.v8debug) {
if (!resolvedArgv) {
// we enter the repl if we're not given a filename argument.
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
-var binding = process.binding('evals');
-
-module.exports = Script;
-Script.Script = Script;
+var binding = process.binding('contextify');
+var Script = binding.ContextifyScript;
var util = require('util');
-function Script(code, ctx, filename) {
- if (!(this instanceof Script)) {
- return new Script(code, ctx, filename);
+// The binding provides a few useful primitives:
+// - ContextifyScript(code, [filename]), with methods:
+// - runInThisContext()
+// - runInContext(sandbox, [timeout])
+// - makeContext(sandbox)
+// From this we build the entire documented API.
+
+Script.prototype.runInNewContext = function(initSandbox, timeout) {
+ var context = exports.createContext(initSandbox);
+ return this.runInContext(context, timeout);
+};
+
+exports.Script = Script;
+
+exports.createScript = function(code, filename) {
+ return new Script(code, filename);
+};
+
+exports.createContext = function(initSandbox) {
+ if (util.isUndefined(initSandbox)) {
+ initSandbox = {};
}
- var ns = new binding.NodeScript(code, ctx, filename);
-
- // bind all methods to this Script object
- Object.keys(binding.NodeScript.prototype).forEach(function(f) {
- if (util.isFunction(binding.NodeScript.prototype[f])) {
- this[f] = function() {
- if (!(this instanceof Script)) {
- throw new TypeError('invalid call to ' + f);
- }
- return ns[f].apply(ns, arguments);
- };
- }
- }, this);
-}
-
-Script.createScript = function(code, ctx, name) {
- return new Script(code, ctx, name);
+ binding.makeContext(initSandbox);
+
+ return initSandbox;
+};
+
+exports.runInContext = function(code, sandbox, filename, timeout) {
+ var script = exports.createScript(code, filename);
+ return script.runInContext(sandbox, timeout);
};
-Script.createContext = binding.NodeScript.createContext;
-Script.runInContext = binding.NodeScript.runInContext;
-Script.runInThisContext = binding.NodeScript.runInThisContext;
-Script.runInNewContext = binding.NodeScript.runInNewContext;
+exports.runInNewContext = function(code, sandbox, filename, timeout) {
+ var script = exports.createScript(code, filename);
+ return script.runInNewContext(sandbox, timeout);
+};
+
+exports.runInThisContext = function(code, filename, timeout) {
+ var script = exports.createScript(code, filename);
+ return script.runInThisContext(timeout);
+};
'src/node.cc',
'src/node_buffer.cc',
'src/node_constants.cc',
+ 'src/node_contextify.cc',
'src/node_extensions.cc',
'src/node_file.cc',
'src/node_http_parser.cc',
'src/node_javascript.cc',
'src/node_main.cc',
'src/node_os.cc',
- 'src/node_script.cc',
'src/node_stat_watcher.cc',
'src/node_watchdog.cc',
'src/node_zlib.cc',
'src/node.h',
'src/node_buffer.h',
'src/node_constants.h',
+ 'src/node_contextify.h',
'src/node_extensions.h',
'src/node_file.h',
'src/node_http_parser.h',
'src/node_javascript.h',
'src/node_os.h',
'src/node_root_certs.h',
- 'src/node_script.h',
'src/node_version.h',
'src/node_watchdog.h',
'src/node_wrap.h',
#include "node_file.h"
#include "node_http_parser.h"
#include "node_javascript.h"
-#include "node_script.h"
#include "node_version.h"
#if defined HAVE_PERFCTR
'global.require = require;\n' +
'return require("vm").runInThisContext(' +
JSON.stringify(body) + ', ' +
- JSON.stringify(name) + ', 0, true);\n';
+ JSON.stringify(name) + ');\n';
}
var result = module._compile(script, name + '-wrapper');
if (process._print_eval) console.log(result);
// core modules found in lib/*.js. All core modules are compiled into the
// node binary, so they can be loaded faster.
- var Script = process.binding('evals').NodeScript;
- var runInThisContext = Script.runInThisContext;
+ var ContextifyScript = process.binding('contextify').ContextifyScript;
+ function runInThisContext(code, filename) {
+ var script = new ContextifyScript(code, filename);
+ return script.runInThisContext();
+ }
function NativeModule(id) {
this.filename = id + '.js';
var source = NativeModule.getSource(this.id);
source = NativeModule.wrap(source);
- var fn = runInThisContext(source, this.filename, 0, true);
+ var fn = runInThisContext(source, this.filename);
fn(this.exports, NativeModule.require, this, this.filename);
this.loaded = true;
--- /dev/null
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+#include "node.h"
+#include "node_internals.h"
+#include "node_watchdog.h"
+
+namespace node {
+
+using v8::AccessType;
+using v8::Array;
+using v8::Boolean;
+using v8::Context;
+using v8::Function;
+using v8::FunctionCallbackInfo;
+using v8::FunctionTemplate;
+using v8::HandleScope;
+using v8::Integer;
+using v8::Local;
+using v8::None;
+using v8::Object;
+using v8::ObjectTemplate;
+using v8::Persistent;
+using v8::PropertyCallbackInfo;
+using v8::Script;
+using v8::String;
+using v8::TryCatch;
+using v8::Value;
+using v8::V8;
+
+
+class ContextifyContext : ObjectWrap {
+ private:
+ Persistent<Object> sandbox_;
+ Persistent<Object> proxy_global_;
+ static Persistent<FunctionTemplate> data_wrapper_tmpl;
+ static Persistent<Function> data_wrapper_ctor;
+
+ public:
+ Persistent<Context> context_;
+ static Persistent<FunctionTemplate> js_tmpl;
+
+ explicit ContextifyContext(Local<Object> sandbox) :
+ sandbox_(node_isolate, sandbox) {
+ }
+
+
+ ~ContextifyContext() {
+ context_.Dispose();
+ proxy_global_.Dispose();
+ sandbox_.Dispose();
+ }
+
+
+ // We override ObjectWrap::Wrap so that we can create our context after
+ // we have a reference to our "host" JavaScript object. If we try to use
+ // handle_ in the ContextifyContext constructor, it will be empty since it's
+ // set in ObjectWrap::Wrap.
+ inline void Wrap(Local<Object> handle) {
+ HandleScope scope(node_isolate);
+ ObjectWrap::Wrap(handle);
+ Local<Context> v8_context = CreateV8Context();
+ context_.Reset(node_isolate, v8_context);
+ proxy_global_.Reset(node_isolate, v8_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> CreateDataWrapper() {
+ HandleScope scope(node_isolate);
+ Local<Function> ctor = PersistentToLocal(node_isolate, data_wrapper_ctor);
+ Local<Object> wrapper = ctor->NewInstance();
+ NODE_WRAP(wrapper, this);
+ return scope.Close(wrapper);
+ }
+
+
+ Local<Context> CreateV8Context() {
+ HandleScope scope(node_isolate);
+ Local<FunctionTemplate> function_template = FunctionTemplate::New();
+ function_template->SetHiddenPrototype(true);
+
+ Local<Object> sandbox = PersistentToLocal(node_isolate, sandbox_);
+ function_template->SetClassName(sandbox->GetConstructorName());
+
+ Local<ObjectTemplate> object_template =
+ function_template->InstanceTemplate();
+ object_template->SetNamedPropertyHandler(GlobalPropertyGetterCallback,
+ GlobalPropertySetterCallback,
+ GlobalPropertyQueryCallback,
+ GlobalPropertyDeleterCallback,
+ GlobalPropertyEnumeratorCallback,
+ CreateDataWrapper());
+ object_template->SetAccessCheckCallbacks(GlobalPropertyNamedAccessCheck,
+ GlobalPropertyIndexedAccessCheck);
+ return scope.Close(Context::New(node_isolate, NULL, object_template));
+ }
+
+
+ static void Init(Local<Object> target) {
+ HandleScope scope(node_isolate);
+
+ Local<FunctionTemplate> function_template = FunctionTemplate::New();
+ function_template->InstanceTemplate()->SetInternalFieldCount(1);
+ data_wrapper_tmpl.Reset(node_isolate, function_template);
+
+ Local<FunctionTemplate> lwrapper_tmpl =
+ PersistentToLocal(node_isolate, data_wrapper_tmpl);
+ data_wrapper_ctor.Reset(node_isolate, lwrapper_tmpl->GetFunction());
+
+ js_tmpl.Reset(node_isolate, FunctionTemplate::New(New));
+ Local<FunctionTemplate> ljs_tmpl = PersistentToLocal(node_isolate, js_tmpl);
+ ljs_tmpl->InstanceTemplate()->SetInternalFieldCount(1);
+
+ Local<String> class_name
+ = FIXED_ONE_BYTE_STRING(node_isolate, "ContextifyContext");
+ ljs_tmpl->SetClassName(class_name);
+ target->Set(class_name, ljs_tmpl->GetFunction());
+
+ NODE_SET_METHOD(target, "makeContext", MakeContext);
+ }
+
+
+ // args[0] = the sandbox object
+ static void New(const FunctionCallbackInfo<Value>& args) {
+ HandleScope scope(node_isolate);
+ if (!args[0]->IsObject()) {
+ return ThrowTypeError("sandbox argument must be an object.");
+ }
+ ContextifyContext* ctx = new ContextifyContext(args[0].As<Object>());
+ ctx->Wrap(args.This());
+ }
+
+
+ static void MakeContext(const FunctionCallbackInfo<Value>& args) {
+ Local<Object> sandbox = args[0].As<Object>();
+
+ Local<FunctionTemplate> ljs_tmpl = PersistentToLocal(node_isolate, js_tmpl);
+ Local<Value> constructor_args[] = { sandbox };
+ Local<Object> contextify_context_object =
+ ljs_tmpl->GetFunction()->NewInstance(1, constructor_args);
+
+ Local<String> hidden_name =
+ FIXED_ONE_BYTE_STRING(node_isolate, "_contextifyHidden");
+ sandbox->SetHiddenValue(hidden_name, contextify_context_object);
+ }
+
+
+ static const Local<Context> ContextFromContextifiedSandbox(
+ const Local<Object>& sandbox) {
+ Local<String> hidden_name =
+ FIXED_ONE_BYTE_STRING(node_isolate, "_contextifyHidden");
+ Local<Object> hidden_context =
+ sandbox->GetHiddenValue(hidden_name).As<Object>();
+
+ if (hidden_context.IsEmpty()) {
+ ThrowTypeError("sandbox argument must have been converted to a context.");
+ return Local<Context>();
+ }
+
+ ContextifyContext* ctx =
+ ObjectWrap::Unwrap<ContextifyContext>(hidden_context);
+ Persistent<Context> context;
+ context.Reset(node_isolate, ctx->context_);
+ return PersistentToLocal(node_isolate, context);
+ }
+
+
+ static bool GlobalPropertyNamedAccessCheck(Local<Object> host,
+ Local<Value> key,
+ AccessType type,
+ Local<Value> data) {
+ return true;
+ }
+
+
+ static bool GlobalPropertyIndexedAccessCheck(Local<Object> host,
+ uint32_t key,
+ AccessType type,
+ Local<Value> data) {
+ return true;
+ }
+
+
+ static void GlobalPropertyGetterCallback(
+ Local<String> property,
+ const PropertyCallbackInfo<Value>& args) {
+ HandleScope scope(node_isolate);
+
+ Local<Object> data = args.Data()->ToObject();
+ ContextifyContext* ctx = ObjectWrap::Unwrap<ContextifyContext>(data);
+
+ Local<Object> sandbox = PersistentToLocal(node_isolate, ctx->sandbox_);
+ Local<Value> rv = sandbox->GetRealNamedProperty(property);
+ if (rv.IsEmpty()) {
+ Local<Object> proxy_global = PersistentToLocal(node_isolate,
+ ctx->proxy_global_);
+ rv = proxy_global->GetRealNamedProperty(property);
+ }
+ if (!rv.IsEmpty() && rv == ctx->sandbox_) {
+ rv = PersistentToLocal(node_isolate, ctx->proxy_global_);
+ }
+
+ args.GetReturnValue().Set(rv);
+ }
+
+
+ static void GlobalPropertySetterCallback(
+ Local<String> property,
+ Local<Value> value,
+ const PropertyCallbackInfo<Value>& args) {
+ HandleScope scope(node_isolate);
+
+ Local<Object> data = args.Data()->ToObject();
+ ContextifyContext* ctx = ObjectWrap::Unwrap<ContextifyContext>(data);
+
+ PersistentToLocal(node_isolate, ctx->sandbox_)->Set(property, value);
+ }
+
+
+ static void GlobalPropertyQueryCallback(
+ Local<String> property,
+ const PropertyCallbackInfo<Integer>& args) {
+ HandleScope scope(node_isolate);
+
+ Local<Object> data = args.Data()->ToObject();
+ ContextifyContext* ctx = ObjectWrap::Unwrap<ContextifyContext>(data);
+
+ Local<Object> sandbox = PersistentToLocal(node_isolate, ctx->sandbox_);
+ Local<Object> proxy_global = PersistentToLocal(node_isolate,
+ ctx->proxy_global_);
+
+ bool in_sandbox = sandbox->GetRealNamedProperty(property).IsEmpty();
+ bool in_proxy_global =
+ proxy_global->GetRealNamedProperty(property).IsEmpty();
+ if (!in_sandbox || !in_proxy_global) {
+ args.GetReturnValue().Set(None);
+ }
+ }
+
+
+ static void GlobalPropertyDeleterCallback(
+ Local<String> property,
+ const PropertyCallbackInfo<Boolean>& args) {
+ HandleScope scope(node_isolate);
+
+ Local<Object> data = args.Data()->ToObject();
+ ContextifyContext* ctx = ObjectWrap::Unwrap<ContextifyContext>(data);
+
+ bool success = PersistentToLocal(node_isolate,
+ ctx->sandbox_)->Delete(property);
+ if (!success) {
+ success = PersistentToLocal(node_isolate,
+ ctx->proxy_global_)->Delete(property);
+ }
+ args.GetReturnValue().Set(success);
+ }
+
+
+ static void GlobalPropertyEnumeratorCallback(
+ const PropertyCallbackInfo<Array>& args) {
+ HandleScope scope(node_isolate);
+
+ Local<Object> data = args.Data()->ToObject();
+ ContextifyContext* ctx = ObjectWrap::Unwrap<ContextifyContext>(data);
+
+ Local<Object> sandbox = PersistentToLocal(node_isolate, ctx->sandbox_);
+ args.GetReturnValue().Set(sandbox->GetPropertyNames());
+ }
+};
+
+class ContextifyScript : ObjectWrap {
+ private:
+ Persistent<Script> script_;
+
+ public:
+ static Persistent<FunctionTemplate> script_tmpl;
+
+ static void Init(Local<Object> target) {
+ HandleScope scope(node_isolate);
+ Local<String> class_name =
+ FIXED_ONE_BYTE_STRING(node_isolate, "ContextifyScript");
+
+ script_tmpl.Reset(node_isolate, FunctionTemplate::New(New));
+ Local<FunctionTemplate> lscript_tmpl =
+ PersistentToLocal(node_isolate, script_tmpl);
+ lscript_tmpl->InstanceTemplate()->SetInternalFieldCount(1);
+ lscript_tmpl->SetClassName(class_name);
+ NODE_SET_PROTOTYPE_METHOD(lscript_tmpl, "runInContext", RunInContext);
+ NODE_SET_PROTOTYPE_METHOD(lscript_tmpl,
+ "runInThisContext",
+ RunInThisContext);
+
+ target->Set(class_name, lscript_tmpl->GetFunction());
+ }
+
+
+ // args: code, [filename]
+ static void New(const FunctionCallbackInfo<Value>& args) {
+ HandleScope scope(node_isolate);
+
+ if (!args.IsConstructCall()) {
+ return ThrowError("Must call vm.Script as a constructor.");
+ }
+
+ ContextifyScript *contextify_script = new ContextifyScript();
+ contextify_script->Wrap(args.Holder());
+ Local<String> code = args[0]->ToString();
+ Local<String> filename = GetFilenameArg(args, 1);
+
+ Local<Context> context = Context::GetCurrent();
+ Context::Scope context_scope(context);
+
+ TryCatch try_catch;
+
+ Local<Script> v8_script = Script::New(code, filename);
+
+ if (v8_script.IsEmpty()) {
+ DisplayExceptionLine(try_catch.Message());
+ try_catch.ReThrow();
+ return;
+ }
+ contextify_script->script_.Reset(node_isolate, v8_script);
+ }
+
+
+ static bool InstanceOf(const Local<Value>& value) {
+ return !value.IsEmpty() &&
+ PersistentToLocal(node_isolate, script_tmpl)->HasInstance(value);
+ }
+
+
+ // args: [timeout]
+ static void RunInThisContext(const FunctionCallbackInfo<Value>& args) {
+ HandleScope scope(node_isolate);
+
+ // Assemble arguments
+ TryCatch try_catch;
+ uint64_t timeout = GetTimeoutArg(args, 0);
+ if (try_catch.HasCaught()) {
+ try_catch.ReThrow();
+ return;
+ }
+
+ // Do the eval within this context
+ EvalMachine(timeout, args, try_catch);
+ }
+
+ // args: sandbox, [timeout]
+ static void RunInContext(const FunctionCallbackInfo<Value>& args) {
+ HandleScope scope(node_isolate);
+
+ // Assemble arguments
+ TryCatch try_catch;
+ if (!args[0]->IsObject()) {
+ return ThrowTypeError("sandbox argument must be an object.");
+ }
+ Local<Object> sandbox = args[0].As<Object>();
+ uint64_t timeout = GetTimeoutArg(args, 1);
+ if (try_catch.HasCaught()) {
+ try_catch.ReThrow();
+ return;
+ }
+
+ // Get the context from the sandbox
+ Local<Context> context =
+ ContextifyContext::ContextFromContextifiedSandbox(sandbox);
+ if (try_catch.HasCaught()) {
+ try_catch.ReThrow();
+ return;
+ }
+
+ // Do the eval within the context
+ Context::Scope context_scope(context);
+ EvalMachine(timeout, args, try_catch);
+ }
+
+ static int64_t GetTimeoutArg(const FunctionCallbackInfo<Value>& args,
+ const int i) {
+ if (args[i]->IsUndefined()) {
+ return 0;
+ }
+
+ int64_t timeout = args[i]->IntegerValue();
+ if (timeout < 0) {
+ ThrowRangeError("timeout must be a positive number");
+ }
+ return timeout;
+ }
+
+
+ static Local<String> GetFilenameArg(const FunctionCallbackInfo<Value>& args,
+ const int i) {
+ return !args[i]->IsUndefined()
+ ? args[i]->ToString()
+ : FIXED_ONE_BYTE_STRING(node_isolate, "evalmachine.<anonymous>");
+ }
+
+
+ static void EvalMachine(const int64_t timeout,
+ const FunctionCallbackInfo<Value>& args,
+ TryCatch& try_catch) {
+ if (!ContextifyScript::InstanceOf(args.This())) {
+ return ThrowTypeError(
+ "Script methods can only be called on script instances.");
+ }
+
+ ContextifyScript* wrapped_script =
+ ObjectWrap::Unwrap<ContextifyScript>(args.This());
+ Local<Script> script = PersistentToLocal(node_isolate,
+ wrapped_script->script_);
+ if (script.IsEmpty()) {
+ DisplayExceptionLine(try_catch.Message());
+ try_catch.ReThrow();
+ return;
+ }
+
+ Local<Value> result;
+ if (timeout) {
+ Watchdog wd(timeout);
+ result = script->Run();
+ } else {
+ result = script->Run();
+ }
+
+ if (try_catch.HasCaught() && try_catch.HasTerminated()) {
+ V8::CancelTerminateExecution(args.GetIsolate());
+ return ThrowError("Script execution timed out.");
+ }
+
+ if (result.IsEmpty()) {
+ // Error occurred during execution of the script.
+ DisplayExceptionLine(try_catch.Message());
+ try_catch.ReThrow();
+ return;
+ }
+
+ args.GetReturnValue().Set(result);
+ }
+
+
+ ~ContextifyScript() {
+ script_.Dispose();
+ }
+};
+
+
+Persistent<FunctionTemplate> ContextifyContext::js_tmpl;
+Persistent<FunctionTemplate> ContextifyContext::data_wrapper_tmpl;
+Persistent<Function> ContextifyContext::data_wrapper_ctor;
+
+Persistent<FunctionTemplate> ContextifyScript::script_tmpl;
+
+void InitContextify(Local<Object> target) {
+ HandleScope scope(node_isolate);
+ ContextifyContext::Init(target);
+ ContextifyScript::Init(target);
+}
+
+} // namespace node
+
+NODE_MODULE(node_contextify, node::InitContextify);
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
-#ifndef SRC_NODE_SCRIPT_H_
-#define SRC_NODE_SCRIPT_H_
+#ifndef SRC_NODE_CONTEXTIFY_H_
+#define SRC_NODE_CONTEXTIFY_H_
#include "node.h"
#include "node_object_wrap.h"
namespace node {
-void InitEvals(v8::Handle<v8::Object> target);
+void InitContextify(v8::Handle<v8::Object> target);
} // namespace node
-#endif // SRC_NODE_SCRIPT_H_
+#endif // SRC_NODE_CONTEXTIFY_H_
START \
ITEM(node_buffer) \
NODE_EXT_LIST_SSL(ITEM) \
- ITEM(node_evals) \
+ ITEM(node_contextify) \
ITEM(node_fs) \
ITEM(node_http_parser) \
ITEM(node_os) \
+++ /dev/null
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-#include "node.h"
-#include "node_script.h"
-#include "node_watchdog.h"
-#include <assert.h>
-
-namespace node {
-
-using v8::Array;
-using v8::Context;
-using v8::Exception;
-using v8::Function;
-using v8::FunctionCallbackInfo;
-using v8::FunctionTemplate;
-using v8::Handle;
-using v8::HandleScope;
-using v8::Local;
-using v8::Object;
-using v8::Persistent;
-using v8::Script;
-using v8::String;
-using v8::TryCatch;
-using v8::V8;
-using v8::Value;
-
-
-class WrappedContext : ObjectWrap {
- public:
- static void Initialize(Handle<Object> target);
- static void New(const FunctionCallbackInfo<Value>& args);
-
- Local<Context> GetV8Context();
- static Local<Object> NewInstance();
- static bool InstanceOf(Handle<Value> value);
-
- protected:
-
- static Persistent<FunctionTemplate> constructor_template;
-
- WrappedContext();
- ~WrappedContext();
-
- Persistent<Context> context_;
-};
-
-
-Persistent<FunctionTemplate> WrappedContext::constructor_template;
-
-
-class WrappedScript : ObjectWrap {
- public:
- static void Initialize(Handle<Object> target);
-
- enum EvalInputFlags { compileCode, unwrapExternal };
- enum EvalContextFlags { thisContext, newContext, userContext };
- enum EvalOutputFlags { returnResult, wrapExternal };
- enum EvalTimeoutFlags { noTimeout, useTimeout };
-
- template <EvalInputFlags input_flag,
- EvalContextFlags context_flag,
- EvalOutputFlags output_flag,
- EvalTimeoutFlags timeout_flag>
- static void EvalMachine(const FunctionCallbackInfo<Value>& args);
-
- protected:
- WrappedScript() : ObjectWrap() {}
- ~WrappedScript();
-
- static void New(const FunctionCallbackInfo<Value>& args);
- static void CreateContext(const FunctionCallbackInfo<Value>& args);
- static void RunInContext(const FunctionCallbackInfo<Value>& args);
- static void RunInThisContext(const FunctionCallbackInfo<Value>& args);
- static void RunInNewContext(const FunctionCallbackInfo<Value>& args);
- static void CompileRunInContext(const FunctionCallbackInfo<Value>& args);
- static void CompileRunInThisContext(const FunctionCallbackInfo<Value>& args);
- static void CompileRunInNewContext(const FunctionCallbackInfo<Value>& args);
-
- Persistent<Script> script_;
-};
-
-
-void CloneObject(Handle<Object> recv,
- Handle<Value> source,
- Handle<Value> target) {
- HandleScope scope(node_isolate);
-
- const char raw_script_source[] =
- "(function(source, target) { \n"
- " Object.getOwnPropertyNames(source).forEach(function(key) { \n"
- " try { \n"
- " var desc = Object.getOwnPropertyDescriptor(source, key); \n"
- " if (desc.value === source) desc.value = target; \n"
- " Object.defineProperty(target, key, desc); \n"
- " } catch (e) { \n"
- " // Catch sealed properties errors \n"
- " } \n"
- " }); \n"
- "}); \n";
-
- Local<String> script_source =
- FIXED_ONE_BYTE_STRING(node_isolate, raw_script_source);
- Local<String> script_name =
- FIXED_ONE_BYTE_STRING(node_isolate, "binding:script");
- Local<Script> script = Script::Compile(script_source, script_name);
-
- Local<Function> fun = script->Run().As<Function>();
- assert(fun.IsEmpty() == false);
- assert(fun->IsFunction() == true);
-
- Handle<Value> argv[] = { source, target };
- Handle<Value> rc = fun->Call(recv, ARRAY_SIZE(argv), argv);
- assert(rc.IsEmpty() == false);
-}
-
-
-void WrappedContext::Initialize(Handle<Object> target) {
- HandleScope scope(node_isolate);
-
- Local<FunctionTemplate> t = FunctionTemplate::New(WrappedContext::New);
- t->InstanceTemplate()->SetInternalFieldCount(1);
- t->SetClassName(FIXED_ONE_BYTE_STRING(node_isolate, "Context"));
-
- target->Set(FIXED_ONE_BYTE_STRING(node_isolate, "Context"), t->GetFunction());
- constructor_template.Reset(node_isolate, t);
-}
-
-
-bool WrappedContext::InstanceOf(Handle<Value> value) {
- return !value.IsEmpty() && HasInstance(constructor_template, value);
-}
-
-
-void WrappedContext::New(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
- WrappedContext *t = new WrappedContext();
- t->Wrap(args.This());
-}
-
-
-WrappedContext::WrappedContext() : ObjectWrap() {
- context_.Reset(node_isolate, Context::New(node_isolate));
-}
-
-
-WrappedContext::~WrappedContext() {
- context_.Dispose();
-}
-
-
-Local<Object> WrappedContext::NewInstance() {
- Local<FunctionTemplate> constructor_template_handle =
- PersistentToLocal(node_isolate, constructor_template);
- return constructor_template_handle->GetFunction()->NewInstance();
-}
-
-
-Local<Context> WrappedContext::GetV8Context() {
- return PersistentToLocal(node_isolate, context_);
-}
-
-
-void WrappedScript::Initialize(Handle<Object> target) {
- HandleScope scope(node_isolate);
-
- Local<FunctionTemplate> t = FunctionTemplate::New(WrappedScript::New);
- t->InstanceTemplate()->SetInternalFieldCount(1);
- // Note: We use 'NodeScript' instead of 'Script' so that we do not
- // conflict with V8's Script class defined in v8/src/messages.js
- // See GH-203 https://github.com/joyent/node/issues/203
- t->SetClassName(FIXED_ONE_BYTE_STRING(node_isolate, "NodeScript"));
-
- NODE_SET_PROTOTYPE_METHOD(t,
- "createContext",
- WrappedScript::CreateContext);
-
- NODE_SET_PROTOTYPE_METHOD(t,
- "runInContext",
- WrappedScript::RunInContext);
-
- NODE_SET_PROTOTYPE_METHOD(t,
- "runInThisContext",
- WrappedScript::RunInThisContext);
-
- NODE_SET_PROTOTYPE_METHOD(t,
- "runInNewContext",
- WrappedScript::RunInNewContext);
-
- NODE_SET_METHOD(t,
- "createContext",
- WrappedScript::CreateContext);
-
- NODE_SET_METHOD(t,
- "runInContext",
- WrappedScript::CompileRunInContext);
-
- NODE_SET_METHOD(t,
- "runInThisContext",
- WrappedScript::CompileRunInThisContext);
-
- NODE_SET_METHOD(t,
- "runInNewContext",
- WrappedScript::CompileRunInNewContext);
-
- target->Set(FIXED_ONE_BYTE_STRING(node_isolate, "NodeScript"),
- t->GetFunction());
-}
-
-
-void WrappedScript::New(const FunctionCallbackInfo<Value>& args) {
- assert(args.IsConstructCall() == true);
- HandleScope scope(node_isolate);
- WrappedScript *t = new WrappedScript();
- t->Wrap(args.This());
- WrappedScript::EvalMachine<
- compileCode, thisContext, wrapExternal, noTimeout>(args);
-}
-
-
-WrappedScript::~WrappedScript() {
- script_.Dispose();
-}
-
-
-void WrappedScript::CreateContext(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
-
- Local<Object> context = WrappedContext::NewInstance();
-
- if (args.Length() > 0) {
- if (args[0]->IsObject()) {
- Local<Object> sandbox = args[0].As<Object>();
-
- CloneObject(args.This(), sandbox, context);
- } else {
- return ThrowTypeError(
- "createContext() accept only object as first argument.");
- }
- }
-
- args.GetReturnValue().Set(context);
-}
-
-
-void WrappedScript::RunInContext(const FunctionCallbackInfo<Value>& args) {
- WrappedScript::EvalMachine<
- unwrapExternal, userContext, returnResult, useTimeout>(args);
-}
-
-
-void WrappedScript::RunInThisContext(const FunctionCallbackInfo<Value>& args) {
- WrappedScript::EvalMachine<
- unwrapExternal, thisContext, returnResult, useTimeout>(args);
-}
-
-
-void WrappedScript::RunInNewContext(const FunctionCallbackInfo<Value>& args) {
- WrappedScript::EvalMachine<
- unwrapExternal, newContext, returnResult, useTimeout>(args);
-}
-
-
-void WrappedScript::CompileRunInContext(
- const FunctionCallbackInfo<Value>& args) {
- WrappedScript::EvalMachine<
- compileCode, userContext, returnResult, useTimeout>(args);
-}
-
-
-void WrappedScript::CompileRunInThisContext(
- const FunctionCallbackInfo<Value>& args) {
- WrappedScript::EvalMachine<
- compileCode, thisContext, returnResult, useTimeout>(args);
-}
-
-
-void WrappedScript::CompileRunInNewContext(
- const FunctionCallbackInfo<Value>& args) {
- WrappedScript::EvalMachine<
- compileCode, newContext, returnResult, useTimeout>(args);
-}
-
-
-template <WrappedScript::EvalInputFlags input_flag,
- WrappedScript::EvalContextFlags context_flag,
- WrappedScript::EvalOutputFlags output_flag,
- WrappedScript::EvalTimeoutFlags timeout_flag>
-void WrappedScript::EvalMachine(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
-
- if (input_flag == compileCode && args.Length() < 1) {
- return ThrowTypeError("needs at least 'code' argument.");
- }
-
- const int sandbox_index = input_flag == compileCode ? 1 : 0;
- if (context_flag == userContext &&
- !WrappedContext::InstanceOf(args[sandbox_index])) {
- return ThrowTypeError("needs a 'context' argument.");
- }
-
- Local<String> code;
- if (input_flag == compileCode) code = args[0]->ToString();
-
- Local<Object> sandbox;
- if (context_flag == newContext) {
- sandbox = args[sandbox_index]->IsObject() ? args[sandbox_index]->ToObject()
- : Object::New();
- } else if (context_flag == userContext) {
- sandbox = args[sandbox_index]->ToObject();
- }
-
- const int filename_index = sandbox_index +
- (context_flag == thisContext? 0 : 1);
- Local<String> filename;
- if (args.Length() > filename_index) {
- filename = args[filename_index]->ToString();
- } else {
- filename = FIXED_ONE_BYTE_STRING(node_isolate, "evalmachine.<anonymous>");
- }
-
- uint64_t timeout = 0;
- const int timeout_index = filename_index + 1;
- if (timeout_flag == useTimeout && args.Length() > timeout_index) {
- if (!args[timeout_index]->IsUint32()) {
- return ThrowTypeError("needs an unsigned integer 'ms' argument.");
- }
- timeout = args[timeout_index]->Uint32Value();
- }
-
- const int display_error_index = timeout_index +
- (timeout_flag == noTimeout ? 0 : 1);
- bool display_error = false;
- if (args.Length() > display_error_index &&
- args[display_error_index]->IsBoolean() &&
- args[display_error_index]->BooleanValue() == true) {
- display_error = true;
- }
-
- Local<Context> context = Context::GetCurrent();
-
- Local<Array> keys;
- if (context_flag == newContext) {
- // Create the new context
- context = Context::New(node_isolate);
-
- } else if (context_flag == userContext) {
- // Use the passed in context
- WrappedContext *nContext = ObjectWrap::Unwrap<WrappedContext>(sandbox);
- context = nContext->GetV8Context();
- }
-
- Context::Scope context_scope(context);
-
- // New and user context share code. DRY it up.
- if (context_flag == userContext || context_flag == newContext) {
- // Copy everything from the passed in sandbox (either the persistent
- // context for runInContext(), or the sandbox arg to runInNewContext()).
- CloneObject(args.This(), sandbox, context->Global()->GetPrototype());
- }
-
- // Catch errors
- TryCatch try_catch;
-
- // TryCatch must not be verbose to prevent duplicate logging
- // of uncaught exceptions (we are rethrowing them)
- try_catch.SetVerbose(false);
-
- Handle<Value> result;
- Local<Script> script;
-
- if (input_flag == compileCode) {
- // well, here WrappedScript::New would suffice in all cases, but maybe
- // Compile has a little better performance where possible
- script = output_flag == returnResult ? Script::Compile(code, filename)
- : Script::New(code, filename);
- if (script.IsEmpty()) {
- // FIXME UGLY HACK TO DISPLAY SYNTAX ERRORS.
- if (display_error) DisplayExceptionLine(try_catch.Message());
-
- // Hack because I can't get a proper stacktrace on SyntaxError
- try_catch.ReThrow();
- return;
- }
- } else {
- WrappedScript *n_script = ObjectWrap::Unwrap<WrappedScript>(args.This());
- if (!n_script) {
- return ThrowError("Must be called as a method of Script.");
- } else if (n_script->script_.IsEmpty()) {
- return ThrowError(
- "'this' must be a result of previous new Script(code) call.");
- }
-
- script = PersistentToLocal(node_isolate, n_script->script_);
- }
-
- if (output_flag == returnResult) {
- if (timeout) {
- Watchdog wd(timeout);
- result = script->Run();
- } else {
- result = script->Run();
- }
- if (try_catch.HasCaught() && try_catch.HasTerminated()) {
- V8::CancelTerminateExecution(args.GetIsolate());
- return ThrowError("Script execution timed out.");
- }
- if (result.IsEmpty()) {
- if (display_error) DisplayExceptionLine(try_catch.Message());
- try_catch.ReThrow();
- return;
- }
- } else {
- WrappedScript *n_script = ObjectWrap::Unwrap<WrappedScript>(args.This());
- if (!n_script) {
- return ThrowError("Must be called as a method of Script.");
- }
- n_script->script_.Reset(node_isolate, script);
- result = args.This();
- }
-
- if (context_flag == userContext || context_flag == newContext) {
- // success! copy changes back onto the sandbox object.
- CloneObject(args.This(), context->Global()->GetPrototype(), sandbox);
- }
-
- args.GetReturnValue().Set(result);
-}
-
-
-void InitEvals(Handle<Object> target) {
- HandleScope scope(node_isolate);
- WrappedContext::Initialize(target);
- WrappedScript::Initialize(target);
-}
-
-
-} // namespace node
-
-NODE_MODULE(node_evals, node::InitEvals)
with(this){__filename}
^^^^
SyntaxError: Strict mode code may not include a with statement
+ at Object.exports.createScript (vm.js:*)
+ at Object.exports.runInThisContext (vm.js:*)
at Object.<anonymous> ([eval]-wrapper:*:*)
at Module._compile (module.js:*:*)
at evalScript (node.js:*:*)
^
Error: hello
at [eval]:1:7
+ at Object.exports.runInThisContext (vm.js:*)
at Object.<anonymous> ([eval]-wrapper:*:*)
at Module._compile (module.js:*:*)
at evalScript (node.js:*:*)
^
Error: hello
at [eval]:1:7
+ at Object.exports.runInThisContext (vm.js:*)
at Object.<anonymous> ([eval]-wrapper:*:*)
at Module._compile (module.js:*:*)
at evalScript (node.js:*:*)
^
ReferenceError: y is not defined
at [eval]:1:16
+ at Object.exports.runInThisContext (vm.js:*)
at Object.<anonymous> ([eval]-wrapper:*:*)
at Module._compile (module.js:*:*)
at evalScript (node.js:*:*)
with(this){__filename}
^^^^
SyntaxError: Strict mode code may not include a with statement
+ at Object.exports.createScript (vm.js:*)
+ at Object.exports.runInThisContext (vm.js:*)
at Object.<anonymous> ([stdin]-wrapper:*:*)
at Module._compile (module.js:*:*)
at evalScript (node.js:*:*)
^
Error: hello
at [stdin]:1:*
+ at Object.exports.runInThisContext (vm.js:*)
at Object.<anonymous> ([stdin]-wrapper:*:*)
at Module._compile (module.js:*:*)
at evalScript (node.js:*:*)
^
Error: hello
at [stdin]:1:*
+ at Object.exports.runInThisContext (vm.js:*)
at Object.<anonymous> ([stdin]-wrapper:*:*)
at Module._compile (module.js:*:*)
at evalScript (node.js:*:*)
^
ReferenceError: y is not defined
at [stdin]:1:16
+ at Object.exports.runInThisContext (vm.js:*)
at Object.<anonymous> ([stdin]-wrapper:*:*)
at Module._compile (module.js:*:*)
at evalScript (node.js:*:*)
var common = require('../common');
var assert = require('assert');
+var vm = require('vm');
console.error('before');
-var Script = process.binding('evals').NodeScript;
-
// undefined reference
-var script = new Script('foo.bar = 5;');
-script.runInNewContext();
+vm.runInNewContext('foo.bar = 5;');
console.error('after');
before
-*test*message*undefined_reference_in_new_context.js:34
-script.runInNewContext();
- ^
+evalmachine.<anonymous>:1
+foo.bar = 5;
+^
ReferenceError: foo is not defined
- at evalmachine.<anonymous>:*
+ at evalmachine.<anonymous>:1:1
+ at ContextifyScript.Script.runInNewContext (vm.js:*)
+ at Object.exports.runInNewContext (vm.js:*)
at Object.<anonymous> (*test*message*undefined_reference_in_new_context.js:*)
at Module._compile (module.js:*)
at *..js (module.js:*)
at Function.Module._load (module.js:*:*)
at Function.Module.runMain (module.js:*:*)
at startup (node.js:*:*)
- at node.js:*:*
addScenario('timeout.js', null, 2);
addScenario('domain.js', null, 10);
-// Exception is thrown from module.js (internal file)
+// Exception is thrown from vm.js via module.js (internal file)
// var compiledWrapper = runInThisContext(wrapper, filename, 0, true);
-addScenario('parse-error.js', 'module.js', null);
+addScenario('parse-error.js', 'vm.js', null);
run();
];
// }}}
-var Script = require('vm').Script;
-var foreignObject = Script.runInContext('({"foo": ["bar", "baz"]})',
- Script.createContext());
+var vm = require('vm');
+var foreignObject = vm.runInNewContext('({"foo": ["bar", "baz"]})');
var qsNoMungeTestCases = [
['', {}],
--- /dev/null
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+var common = require('../common');
+var assert = require('assert');
+var vm = require('vm');
+
+// Test 1: vm.runInNewContext
+var sandbox = {};
+var result = vm.runInNewContext(
+ 'foo = "bar"; this.typeofProcess = typeof process; typeof Object;',
+ sandbox
+);
+assert.deepEqual(sandbox, {
+ foo: 'bar',
+ typeofProcess: 'undefined',
+});
+assert.strictEqual(result, 'function');
+
+// Test 2: vm.runInContext
+var sandbox2 = { foo: 'bar' };
+var context = vm.createContext(sandbox2);
+var result = vm.runInContext(
+ 'baz = foo; this.typeofProcess = typeof process; typeof Object;',
+ context
+);
+assert.deepEqual(sandbox2, {
+ foo: 'bar',
+ baz: 'bar',
+ typeofProcess: 'undefined'
+});
+assert.strictEqual(result, 'function');
+
+// Test 3: vm.runInThisContext
+var result = vm.runInThisContext(
+ 'vmResult = "foo"; Object.prototype.toString.call(process);'
+);
+assert.strictEqual(global.vmResult, 'foo');
+assert.strictEqual(result, '[object process]');
+delete global.vmResult;
+
+// Test 4: vm.runInNewContext
+var result = vm.runInNewContext(
+ 'vmResult = "foo"; typeof process;'
+);
+assert.strictEqual(global.vmResult, undefined);
+assert.strictEqual(result, 'undefined');
+
+// Test 5: vm.createContext
+var sandbox3 = {};
+var context2 = vm.createContext(sandbox3);
+assert.strictEqual(sandbox3, context2);
--- /dev/null
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+var common = require('../common');
+var assert = require('assert');
+var vm = require('vm');
+
+var sandbox = { setTimeout: setTimeout };
+
+var ctx = vm.createContext(sandbox);
+
+vm.runInContext('setTimeout(function() { x = 3; }, 0);', ctx);
+setTimeout(function () {
+ assert.strictEqual(sandbox.x, 3);
+ assert.strictEqual(ctx.x, 3);
+}, 1);
--- /dev/null
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+var common = require('../common');
+var assert = require('assert');
+var vm = require('vm');
+
+var sandbox = { x: 3 };
+
+var ctx = vm.createContext(sandbox);
+
+assert.strictEqual(vm.runInContext('x;', ctx), 3);
+vm.runInContext('y = 4;', ctx);
+assert.strictEqual(sandbox.y, 4);
+assert.strictEqual(ctx.y, 4);
var Script = vm.Script;
var script = new Script('"passed";');
-common.debug('run in a new empty context');
-var context = script.createContext();
+console.error('run in a new empty context');
+var context = vm.createContext();
var result = script.runInContext(context);
assert.equal('passed', result);
-common.debug('create a new pre-populated context');
-context = script.createContext({'foo': 'bar', 'thing': 'lala'});
+console.error('create a new pre-populated context');
+context = vm.createContext({'foo': 'bar', 'thing': 'lala'});
assert.equal('bar', context.foo);
assert.equal('lala', context.thing);
-common.debug('test updating context');
+console.error('test updating context');
script = new Script('foo = 3;');
result = script.runInContext(context);
assert.equal(3, context.foo);
assert.equal('lala', context.thing);
// Issue GH-227:
-Script.runInNewContext('', null, 'some.js');
+assert.throws(function () {
+ vm.runInNewContext('', null, 'some.js');
+}, TypeError);
// Issue GH-1140:
-common.debug('test runInContext signature');
+console.error('test runInContext signature');
var gh1140Exception;
try {
- Script.runInContext('throw new Error()', context, 'expected-filename.js');
+ vm.runInContext('throw new Error()', context, 'expected-filename.js');
}
catch (e) {
gh1140Exception = e;
'expected exception from runInContext signature test');
// GH-558, non-context argument segfaults / raises assertion
-function isTypeError(o) {
- return o instanceof TypeError;
-}
-
-([undefined, null, 0, 0.0, '', {}, []].forEach(function(e) {
- assert.throws(function() { script.runInContext(e); }, isTypeError);
- assert.throws(function() { vm.runInContext('', e); }, isTypeError);
-}));
+[undefined, null, 0, 0.0, '', {}, []].forEach(function(e) {
+ assert.throws(function() { script.runInContext(e); }, TypeError);
+ assert.throws(function() { vm.runInContext('', e); }, TypeError);
+});
// Issue GH-693:
-common.debug('test RegExp as argument to assert.throws');
+console.error('test RegExp as argument to assert.throws');
script = vm.createScript('var assert = require(\'assert\'); assert.throws(' +
'function() { throw "hello world"; }, /hello/);',
'some.js');
var common = require('../common');
var assert = require('assert');
-var Script = require('vm').Script;
+var vm = require('vm');
-common.debug('run in a new empty context');
-var context = Script.createContext();
-var result = Script.runInContext('"passed";', context);
+console.error('run in a new empty context');
+var context = vm.createContext();
+var result = vm.runInContext('"passed";', context);
assert.equal('passed', result);
-common.debug('create a new pre-populated context');
-context = Script.createContext({'foo': 'bar', 'thing': 'lala'});
+console.error('create a new pre-populated context');
+context = vm.createContext({'foo': 'bar', 'thing': 'lala'});
assert.equal('bar', context.foo);
assert.equal('lala', context.thing);
-common.debug('test updating context');
-result = Script.runInContext('var foo = 3;', context);
+console.error('test updating context');
+result = vm.runInContext('var foo = 3;', context);
assert.equal(3, context.foo);
assert.equal('lala', context.thing);
--- /dev/null
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+var common = require('../common');
+var assert = require('assert');
+var vm = require('vm');
+
+var ctx = vm.createContext();
+ctx.window = ctx;
+
+var thisVal = vm.runInContext('this;', ctx);
+var windowVal = vm.runInContext('window;', ctx);
+assert.strictEqual(thisVal, windowVal);
common.globalCheck = false;
-common.debug('run a string');
+console.error('run a string');
var script = new Script('\'passed\';');
-common.debug('script created');
+console.error('script created');
var result1 = script.runInNewContext();
var result2 = script.runInNewContext();
assert.equal('passed', result1);
assert.equal('passed', result2);
-common.debug('thrown error');
+console.error('thrown error');
script = new Script('throw new Error(\'test\');');
assert.throws(function() {
script.runInNewContext();
-});
+}, /test/);
-common.debug('undefined reference');
+console.error('undefined reference');
var error;
script = new Script('foo.bar = 5;');
-try {
+assert.throws(function () {
script.runInNewContext();
-} catch (e) {
- error = e;
-}
-assert.ok(error);
-assert.ok(error.message.indexOf('not defined') >= 0);
-
-common.debug('error.message: ' + error.message);
+}, /not defined/);
hello = 5;
assert.equal(5, hello);
-common.debug('pass values in and out');
+console.error('pass values in and out');
code = 'foo = 1;' +
'bar = 2;' +
'if (baz !== 3) throw new Error(\'test fail\');';
assert.equal(2, obj.bar);
assert.equal(2, foo);
-common.debug('call a function by reference');
+console.error('call a function by reference');
script = new Script('f()');
function changeFoo() { foo = 100 }
script.runInNewContext({ f: changeFoo });
assert.equal(foo, 100);
-common.debug('modify an object by reference');
+console.error('modify an object by reference');
script = new Script('f.a = 2');
var f = { a: 1 };
script.runInNewContext({ f: f });
assert.equal(f.a, 2);
-common.debug('invalid this');
+assert.throws(function() {
+ script.runInNewContext();
+}, /f is not defined/);
+
+console.error('invalid this');
assert.throws(function() {
script.runInNewContext.call('\'hello\';');
-});
+}, TypeError);
common.globalCheck = false;
-common.debug('run a string');
+console.error('run a string');
var script = new Script('\'passed\';');
var result = script.runInThisContext(script);
assert.equal('passed', result);
-common.debug('thrown error');
+console.error('thrown error');
script = new Script('throw new Error(\'test\');');
assert.throws(function() {
script.runInThisContext(script);
assert.equal(2, hello);
-common.debug('pass values');
+console.error('pass values');
code = 'foo = 1;' +
'bar = 2;' +
'if (typeof baz !== \'undefined\') throw new Error(\'test fail\');';
assert.equal(2, bar);
assert.equal(1, foo);
-common.debug('call a function');
+console.error('call a function');
f = function() { foo = 100 };
script = new Script('f()');
script.runInThisContext(script);
var common = require('../common');
var assert = require('assert');
-var Script = require('vm').Script;
+var vm = require('vm');
common.globalCheck = false;
-common.debug('run a string');
-var result = Script.runInNewContext('\'passed\';');
+console.error('run a string');
+var result = vm.runInNewContext('\'passed\';');
assert.equal('passed', result);
-common.debug('thrown error');
+console.error('thrown error');
assert.throws(function() {
- Script.runInNewContext('throw new Error(\'test\');');
+ vm.runInNewContext('throw new Error(\'test\');');
});
hello = 5;
-Script.runInNewContext('hello = 2');
+vm.runInNewContext('hello = 2');
assert.equal(5, hello);
-common.debug('pass values in and out');
+console.error('pass values in and out');
code = 'foo = 1;' +
'bar = 2;' +
'if (baz !== 3) throw new Error(\'test fail\');';
foo = 2;
obj = { foo: 0, baz: 3 };
-var baz = Script.runInNewContext(code, obj);
+var baz = vm.runInNewContext(code, obj);
assert.equal(1, obj.foo);
assert.equal(2, obj.bar);
assert.equal(2, foo);
-common.debug('call a function by reference');
+console.error('call a function by reference');
function changeFoo() { foo = 100 }
-Script.runInNewContext('f()', { f: changeFoo });
+vm.runInNewContext('f()', { f: changeFoo });
assert.equal(foo, 100);
-common.debug('modify an object by reference');
+console.error('modify an object by reference');
var f = { a: 1 };
-Script.runInNewContext('f.a = 2', { f: f });
+vm.runInNewContext('f.a = 2', { f: f });
assert.equal(f.a, 2);
var common = require('../common');
var assert = require('assert');
-var Script = require('vm').Script;
+var vm = require('vm');
common.globalCheck = false;
-common.debug('run a string');
-var result = Script.runInThisContext('\'passed\';');
+console.error('run a string');
+var result = vm.runInThisContext('\'passed\';');
assert.equal('passed', result);
-common.debug('thrown error');
+console.error('thrown error');
assert.throws(function() {
- Script.runInThisContext('throw new Error(\'test\');');
-});
+ vm.runInThisContext('throw new Error(\'test\');');
+}, /test/);
hello = 5;
-Script.runInThisContext('hello = 2');
+vm.runInThisContext('hello = 2');
assert.equal(2, hello);
-common.debug('pass values');
+console.error('pass values');
code = 'foo = 1;' +
'bar = 2;' +
'if (typeof baz !== \'undefined\') throw new Error(\'test fail\');';
foo = 2;
obj = { foo: 0, baz: 3 };
-var baz = Script.runInThisContext(code);
+var baz = vm.runInThisContext(code);
assert.equal(0, obj.foo);
assert.equal(2, bar);
assert.equal(1, foo);
-common.debug('call a function');
+console.error('call a function');
f = function() { foo = 100 };
-Script.runInThisContext('f()');
+vm.runInThisContext('f()');
assert.equal(100, foo);