Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80786 views
1
#include "node.h"
2
#include "node_version.h"
3
#include "nan.h"
4
#include <string>
5
using namespace v8;
6
using namespace node;
7
8
class ContextWrap;
9
10
class ContextifyContext : public ObjectWrap {
11
public:
12
Persistent<Context> context;
13
Persistent<Object> sandbox;
14
Persistent<Object> proxyGlobal;
15
16
static Persistent<FunctionTemplate> jsTmpl;
17
18
ContextifyContext(Local<Object> sbox) {
19
NanScope();
20
NanAssignPersistent(sandbox, sbox);
21
}
22
23
~ContextifyContext() {
24
NanDisposePersistent(context);
25
NanDisposePersistent(proxyGlobal);
26
NanDisposePersistent(sandbox);
27
28
// Provide a GC hint that the context has gone away. Without this call it
29
// does not seem that the collector will touch the context until under extreme
30
// stress.
31
NanContextDisposedNotification();
32
}
33
34
// We override ObjectWrap::Wrap so that we can create our context after
35
// we have a reference to our "host" JavaScript object. If we try to use
36
// handle_ in the ContextifyContext constructor, it will be empty since it's
37
// set in ObjectWrap::Wrap.
38
void Wrap(Handle<Object> handle);
39
40
static void Init(Handle<Object> target) {
41
NanScope();
42
43
Local<FunctionTemplate> ljsTmpl = NanNew<FunctionTemplate>(New);
44
ljsTmpl->InstanceTemplate()->SetInternalFieldCount(1);
45
ljsTmpl->SetClassName(NanNew("ContextifyContext"));
46
NODE_SET_PROTOTYPE_METHOD(ljsTmpl, "run", ContextifyContext::Run);
47
NODE_SET_PROTOTYPE_METHOD(ljsTmpl, "getGlobal", ContextifyContext::GetGlobal);
48
49
NanAssignPersistent(jsTmpl, ljsTmpl);
50
target->Set(NanNew("ContextifyContext"), ljsTmpl->GetFunction());
51
}
52
53
static NAN_METHOD(New) {
54
NanScope();
55
56
if (args.Length() < 1) {
57
NanThrowError("Wrong number of arguments passed to ContextifyContext constructor");
58
NanReturnUndefined();
59
}
60
61
if (!args[0]->IsObject()) {
62
NanThrowTypeError("Argument to ContextifyContext constructor must be an object.");
63
NanReturnUndefined();
64
}
65
66
ContextifyContext* ctx = new ContextifyContext(args[0]->ToObject());
67
ctx->Wrap(args.This());
68
NanReturnValue(args.This());
69
}
70
71
static NAN_METHOD(Run) {
72
NanScope();
73
if (args.Length() == 0) {
74
NanThrowError("Must supply at least 1 argument to run");
75
}
76
if (!args[0]->IsString()) {
77
NanThrowTypeError("First argument to run must be a String.");
78
NanReturnUndefined();
79
}
80
ContextifyContext* ctx = ObjectWrap::Unwrap<ContextifyContext>(args.This());
81
Local<Context> lcontext = NanNew(ctx->context);
82
lcontext->Enter();
83
Local<String> code = args[0]->ToString();
84
85
TryCatch trycatch;
86
Local<NanBoundScript> script;
87
88
if (args.Length() > 1 && args[1]->IsString()) {
89
ScriptOrigin origin(args[1]->ToString());
90
script = NanCompileScript(code, origin);
91
} else {
92
script = NanCompileScript(code);
93
}
94
95
if (script.IsEmpty()) {
96
lcontext->Exit();
97
NanReturnValue(trycatch.ReThrow());
98
}
99
100
Handle<Value> result = NanRunScript(script);
101
lcontext->Exit();
102
103
if (result.IsEmpty()) {
104
NanReturnValue(trycatch.ReThrow());
105
}
106
107
NanReturnValue(result);
108
}
109
110
static bool InstanceOf(Handle<Value> value) {
111
return NanHasInstance(jsTmpl, value);
112
}
113
114
static NAN_METHOD(GetGlobal) {
115
NanScope();
116
ContextifyContext* ctx = ObjectWrap::Unwrap<ContextifyContext>(args.This());
117
NanReturnValue(NanNew(ctx->proxyGlobal));
118
}
119
};
120
121
// This is an object that just keeps an internal pointer to this
122
// ContextifyContext. It's passed to the NamedPropertyHandler. If we
123
// pass the main JavaScript context object we're embedded in, then the
124
// NamedPropertyHandler will store a reference to it forever and keep it
125
// from getting gc'd.
126
class ContextWrap : public ObjectWrap {
127
public:
128
static void Init(void) {
129
NanScope();
130
Local<FunctionTemplate> tmpl = NanNew<FunctionTemplate>();
131
tmpl->InstanceTemplate()->SetInternalFieldCount(1);
132
NanAssignPersistent(functionTemplate, tmpl);
133
NanAssignPersistent(constructor, tmpl->GetFunction());
134
}
135
136
static Local<Context> createV8Context(Handle<Object> jsContextify) {
137
NanEscapableScope();
138
Local<Object> wrapper = NanNew(constructor)->NewInstance();
139
140
ContextWrap *contextWrapper = new ContextWrap();
141
contextWrapper->Wrap(wrapper);
142
143
Local<Object> obj = NanNew(jsContextify);
144
NanMakeWeakPersistent(obj, contextWrapper, &weakCallback);
145
contextWrapper->ctx = ObjectWrap::Unwrap<ContextifyContext>(jsContextify);
146
147
Local<FunctionTemplate> ftmpl = NanNew<FunctionTemplate>();
148
ftmpl->SetHiddenPrototype(true);
149
ftmpl->SetClassName(NanNew(contextWrapper->ctx->sandbox)->GetConstructorName());
150
Local<ObjectTemplate> otmpl = ftmpl->InstanceTemplate();
151
otmpl->SetNamedPropertyHandler(GlobalPropertyGetter,
152
GlobalPropertySetter,
153
GlobalPropertyQuery,
154
GlobalPropertyDeleter,
155
GlobalPropertyEnumerator,
156
wrapper);
157
otmpl->SetAccessCheckCallbacks(GlobalPropertyNamedAccessCheck,
158
GlobalPropertyIndexedAccessCheck);
159
return NanEscapeScope(NanNew<Context>(
160
static_cast<ExtensionConfiguration*>(NULL), otmpl));
161
}
162
163
private:
164
ContextWrap() :ctx(NULL) {}
165
166
~ContextWrap() {
167
}
168
169
static bool GlobalPropertyNamedAccessCheck(Local<Object> host,
170
Local<Value> key,
171
AccessType type,
172
Local<Value> data) {
173
return true;
174
}
175
176
static bool GlobalPropertyIndexedAccessCheck(Local<Object> host,
177
uint32_t key,
178
AccessType type,
179
Local<Value> data) {
180
return true;
181
}
182
183
static NAN_PROPERTY_GETTER(GlobalPropertyGetter) {
184
NanScope();
185
Local<Object> data = args.Data()->ToObject();
186
ContextifyContext* ctx = ObjectWrap::Unwrap<ContextWrap>(data)->ctx;
187
if (!ctx)
188
NanReturnUndefined();
189
Local<Value> rv = NanNew(ctx->sandbox)->GetRealNamedProperty(property);
190
if (rv.IsEmpty()) {
191
rv = NanNew(ctx->proxyGlobal)->GetRealNamedProperty(property);
192
}
193
NanReturnValue(rv);
194
}
195
196
static NAN_PROPERTY_SETTER(GlobalPropertySetter) {
197
NanScope();
198
Local<Object> data = args.Data()->ToObject();
199
ContextifyContext* ctx = ObjectWrap::Unwrap<ContextWrap>(data)->ctx;
200
if (!ctx)
201
NanReturnUndefined();
202
NanNew(ctx->sandbox)->Set(property, value);
203
NanReturnValue(value);
204
}
205
206
static NAN_PROPERTY_QUERY(GlobalPropertyQuery) {
207
NanScope();
208
Local<Object> data = args.Data()->ToObject();
209
ContextifyContext* ctx = ObjectWrap::Unwrap<ContextWrap>(data)->ctx;
210
if (!ctx)
211
NanReturnValue(NanNew<Integer>(None));
212
if (!NanNew(ctx->sandbox)->GetRealNamedProperty(property).IsEmpty() ||
213
!NanNew(ctx->proxyGlobal)->GetRealNamedProperty(property).IsEmpty()) {
214
NanReturnValue(NanNew<Integer>(None));
215
} else {
216
NanReturnValue(Handle<Integer>());
217
}
218
}
219
220
static NAN_PROPERTY_DELETER(GlobalPropertyDeleter) {
221
NanScope();
222
Local<Object> data = args.Data()->ToObject();
223
ContextifyContext* ctx = ObjectWrap::Unwrap<ContextWrap>(data)->ctx;
224
if (!ctx)
225
NanReturnValue(NanNew<Boolean>(false));
226
bool success = NanNew(ctx->sandbox)->Delete(property);
227
NanReturnValue(NanNew<Boolean>(success));
228
}
229
230
static NAN_PROPERTY_ENUMERATOR(GlobalPropertyEnumerator) {
231
NanScope();
232
Local<Object> data = args.Data()->ToObject();
233
ContextifyContext* ctx = ObjectWrap::Unwrap<ContextWrap>(data)->ctx;
234
if (!ctx) {
235
Local<Array> blank = Array::New(0);
236
NanReturnValue(blank);
237
}
238
NanReturnValue(NanNew(ctx->sandbox)->GetPropertyNames());
239
}
240
241
NAN_WEAK_CALLBACK(weakCallback) {
242
ContextWrap *self = data.GetParameter();
243
self->ctx = NULL;
244
}
245
246
static Persistent<FunctionTemplate> functionTemplate;
247
static Persistent<Function> constructor;
248
ContextifyContext *ctx;
249
};
250
251
Persistent<FunctionTemplate> ContextWrap::functionTemplate;
252
Persistent<Function> ContextWrap::constructor;
253
254
void ContextifyContext::Wrap(Handle<Object> handle) {
255
ObjectWrap::Wrap(handle);
256
Local<Context> lcontext = ContextWrap::createV8Context(handle);
257
NanAssignPersistent(context, lcontext);
258
NanAssignPersistent(proxyGlobal, lcontext->Global());
259
}
260
261
class ContextifyScript : public ObjectWrap {
262
public:
263
static Persistent<FunctionTemplate> scriptTmpl;
264
Persistent<NanUnboundScript> script;
265
266
static void Init(Handle<Object> target) {
267
NanScope();
268
Local<FunctionTemplate> lscriptTmpl = NanNew<FunctionTemplate>(New);
269
lscriptTmpl->InstanceTemplate()->SetInternalFieldCount(1);
270
lscriptTmpl->SetClassName(NanNew("ContextifyScript"));
271
272
NODE_SET_PROTOTYPE_METHOD(lscriptTmpl, "runInContext", RunInContext);
273
274
NanAssignPersistent(scriptTmpl, lscriptTmpl);
275
target->Set(NanNew("ContextifyScript"),
276
lscriptTmpl->GetFunction());
277
}
278
static NAN_METHOD(New) {
279
NanScope();
280
ContextifyScript *contextify_script = new ContextifyScript();
281
contextify_script->Wrap(args.Holder());
282
283
if (args.Length() < 1) {
284
NanThrowTypeError("needs at least 'code' argument.");
285
NanReturnUndefined();
286
}
287
288
Local<String> code = args[0]->ToString();
289
Local<String> filename = args.Length() > 1
290
? args[1]->ToString()
291
: NanNew<String>("ContextifyScript.<anonymous>");
292
293
Handle<Context> context = NanGetCurrentContext();
294
Context::Scope context_scope(context);
295
296
// Catch errors
297
TryCatch trycatch;
298
299
ScriptOrigin origin(filename);
300
Handle<NanUnboundScript> v8_script = NanNew<NanUnboundScript>(code, origin);
301
302
if (v8_script.IsEmpty()) {
303
NanReturnValue(trycatch.ReThrow());
304
}
305
306
NanAssignPersistent(contextify_script->script, v8_script);
307
308
NanReturnValue(args.This());
309
}
310
311
static NAN_METHOD(RunInContext) {
312
NanScope();
313
if (args.Length() == 0) {
314
NanThrowError("Must supply at least 1 argument to runInContext");
315
NanReturnUndefined();
316
}
317
if (!ContextifyContext::InstanceOf(args[0]->ToObject())) {
318
NanThrowTypeError("First argument must be a ContextifyContext.");
319
NanReturnUndefined();
320
}
321
322
ContextifyContext* ctx = ObjectWrap::Unwrap<ContextifyContext>(args[0]->ToObject());
323
Local<Context> lcontext = NanNew(ctx->context);
324
lcontext->Enter();
325
ContextifyScript* wrapped_script = ObjectWrap::Unwrap<ContextifyScript>(args.This());
326
Local<NanUnboundScript> script = NanNew(wrapped_script->script);
327
TryCatch trycatch;
328
if (script.IsEmpty()) {
329
lcontext->Exit();
330
NanReturnValue(trycatch.ReThrow());
331
}
332
Handle<Value> result = NanRunScript(script);
333
lcontext->Exit();
334
if (result.IsEmpty()) {
335
NanReturnValue(trycatch.ReThrow());
336
}
337
NanReturnValue(result);
338
}
339
340
~ContextifyScript() {
341
NanDisposePersistent(script);
342
}
343
};
344
345
Persistent<FunctionTemplate> ContextifyContext::jsTmpl;
346
Persistent<FunctionTemplate> ContextifyScript::scriptTmpl;
347
348
extern "C" {
349
static void init(Handle<Object> target) {
350
ContextifyContext::Init(target);
351
ContextifyScript::Init(target);
352
ContextWrap::Init();
353
}
354
NODE_MODULE(contextify, init)
355
};
356
357