-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added a contextify_vm to handle code execution
- Loading branch information
Showing
5 changed files
with
170 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
lib/engine/piston/execution_strategies/context-bootstrap.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
"use strict"; | ||
|
||
Function.prototype.constructor = function(){ throw new SecurityError("The Function constructor may not be called"); }; | ||
Function.prototype.toString = function(){ throw new SecurityError("'toString' may not be called on functions"); }; | ||
|
||
var SecurityError = function(message){ | ||
this.message = message; | ||
this.name = "SecurityError"; | ||
}; | ||
SecurityError.prototype = Error.prototype; |
125 changes: 125 additions & 0 deletions
125
lib/engine/piston/execution_strategies/contextify_vm.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
var vm = function(){ | ||
//avoid contextify's js wrapper | ||
var contextifyPath = require('path').resolve(require.resolve('contextify'), '..', '..'); | ||
var contextify = require('bindings')({ | ||
module_root: contextifyPath, | ||
bindings: 'contextify.node' | ||
}); | ||
// basic WeakMap shim if not available | ||
var WM = typeof WeakMap !== 'undefined' ? WeakMap : function WeakMap(){ | ||
var keys = [], values = []; | ||
return { | ||
set: function(key, val){ | ||
keys.push(key); | ||
values.push(val); | ||
return val; | ||
}, | ||
get: function(key){ | ||
var index = keys.indexOf(key); | ||
if (~index) return values[index]; | ||
}, | ||
has: function(key){ | ||
return !!~keys.indexOf(key); | ||
}, | ||
delete: function(key){ | ||
var index = keys.indexOf(key); | ||
if (~index) { | ||
keys.splice(index, 1); | ||
values.splice(index, 1); | ||
return true; | ||
} | ||
return false; | ||
} | ||
}; | ||
}; | ||
|
||
|
||
// allow for proper garbage collection | ||
var contexts = new WM; | ||
var Context = contextify.ContextifyContext; | ||
|
||
|
||
function createContext(sandbox){ | ||
if (sandbox == null) { | ||
sandbox = {}; | ||
} else if (Object(sandbox) !== sandbox) { | ||
throw new TypeError('Sandbox must be an object'); | ||
} | ||
contexts.set(sandbox, new Context(sandbox)); | ||
return sandbox; | ||
} | ||
|
||
function runInContext(code, sandbox){ | ||
if (Object(sandbox) === sandbox) { | ||
if (!contexts.has(sandbox)) { | ||
createContext(sandbox); | ||
} | ||
return contexts.get(sandbox).run(code); | ||
} else { | ||
throw new TypeError('Context must be an object'); | ||
} | ||
} | ||
|
||
function runInThisContext(code){ | ||
return runInContext(code, global); | ||
} | ||
|
||
function runInNewContext(code){ | ||
var sandbox = createContext(); | ||
var result = runInContext(code, sandbox); | ||
dispose(sandbox); | ||
return result; | ||
} | ||
|
||
function dispose(sandbox){ | ||
contexts.delete(sandbox); | ||
} | ||
|
||
return { | ||
createContext: createContext, | ||
runInContext: runInContext, | ||
runInThisContext: runInThisContext, | ||
runInNewContext: runInNewContext, | ||
dispose: dispose | ||
}; | ||
}(); | ||
|
||
|
||
var ContextifyVm = function(){}; | ||
|
||
ContextifyVm.make = function(){ | ||
var vm = new ContextifyVm(); | ||
return vm; | ||
}; | ||
|
||
ContextifyVm.create = function(){ | ||
var vm = ContextifyVm.make({}); | ||
return vm; | ||
}; | ||
|
||
ContextifyVm.prototype.execute = function(code, sandbox){ | ||
"use strict"; | ||
|
||
var ctx = vm.createContext(sandbox), last_eval; | ||
|
||
var fs = require("fs"), | ||
path = require("path"); | ||
|
||
var bootstrap_file = path.dirname(require.resolve("engine.js")) + "/lib/engine/piston/execution_strategies/context-bootstrap.js"; | ||
|
||
var bootstrap_code = fs.readFileSync(bootstrap_file,"utf-8"); | ||
|
||
vm.runInContext(bootstrap_code, ctx); | ||
|
||
try { | ||
last_eval = vm.runInContext("'use strict'; " + code, ctx); | ||
} catch (e) { | ||
last_eval = e.name + ': ' + e.message; | ||
} | ||
|
||
vm.dispose(ctx); | ||
|
||
return last_eval; | ||
}; | ||
|
||
exports.contextify_vm = ContextifyVm; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
spec/engine/piston/execution_strategies/contextify_spec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
var contextify_vm = require("../../../../lib/engine/piston/execution_strategies/contextify_vm").contextify_vm; | ||
|
||
describe("Code Runners", function(){ | ||
describe("Contextify", function(){ | ||
beforeEach(function(){ | ||
this.strategy = contextify_vm.make(); | ||
this.sandbox = { | ||
add: function(a,b){ return a+b;} | ||
}; | ||
}); | ||
|
||
it("evalutes code against a sandbox", function(){ | ||
var last_eval = this.strategy.execute("add(1,1)", this.sandbox); | ||
expect(last_eval).toBe(2); | ||
}); | ||
|
||
it("throws a SyntaxError when the user-code has bad syntax", function(){ | ||
var last_eval = this.strategy.execute("add(1,1", this.sandbox); | ||
expect(last_eval).toContain("SyntaxError"); | ||
}); | ||
|
||
it("throws a ReferenceError when the user-code calls an unknown sandbox function", function(){ | ||
var last_eval = this.strategy.execute("subtract(1,1)", this.sandbox); | ||
expect(last_eval).toContain("ReferenceError"); | ||
}); | ||
}); | ||
|
||
}); |