mirror of
https://github.com/jsbin/jsbin.git
synced 2026-01-25 15:38:56 +00:00
Merge pull request #708 from remy/fix/loop-protection-702
Fix loop protection
This commit is contained in:
commit
e52af727f1
@ -18,7 +18,7 @@
|
||||
"url": "git://github.com/remy/jsbin.git"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "./node_modules/mocha/bin/mocha"
|
||||
"test": "mocha"
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "3.0.x",
|
||||
|
||||
@ -1,202 +1,174 @@
|
||||
var consoleTest = /(^.|\b)console\./;
|
||||
var getPreparedCode = (function () {
|
||||
|
||||
var iframedelay = (function () {
|
||||
var iframedelay = { active : false },
|
||||
iframe = document.createElement('iframe'),
|
||||
doc,
|
||||
callbackName = '__callback' + (+new Date);
|
||||
var consoleTest = /(^.|\b)console\./,
|
||||
re = {
|
||||
docReady: /\$\(document\)\.ready/,
|
||||
shortDocReady: /\$\(function/,
|
||||
console: /(^.|\b)console\.(\S+)/g,
|
||||
script: /<\/script/ig,
|
||||
code: /%code%/,
|
||||
title: /<title>(.*)<\/title>/i,
|
||||
winLoad: /window\.onload\s*=/,
|
||||
scriptopen: /<script/gi
|
||||
};
|
||||
|
||||
iframe.style.height = iframe.style.width = '1px';
|
||||
iframe.style.visibility = 'hidden';
|
||||
document.body.appendChild(iframe);
|
||||
doc = iframe.contentDocument || iframe.contentWindow.document;
|
||||
|
||||
window[callbackName] = function (width) {
|
||||
iframedelay.active = width === 0;
|
||||
try {
|
||||
iframe.parentNode.removeChild(iframe);
|
||||
delete window[callbackName];
|
||||
} catch (e){}
|
||||
var two = function (i) {
|
||||
return ('0'+i).slice(-2);
|
||||
};
|
||||
|
||||
try {
|
||||
doc.open();
|
||||
doc.write('<script>window.parent.' + callbackName + '(window.innerWidth)</script>');
|
||||
doc.close();
|
||||
} catch (e) {
|
||||
iframedelay.active = true;
|
||||
}
|
||||
return function (nojs) {
|
||||
// reset all the regexp positions for reuse
|
||||
re.docReady.lastIndex = 0;
|
||||
re.shortDocReady.lastIndex = 0;
|
||||
re.console.lastIndex = 0;
|
||||
re.script.lastIndex = 0;
|
||||
re.code.lastIndex = 0;
|
||||
re.title.lastIndex = 0;
|
||||
re.winLoad.lastIndex = 0;
|
||||
re.scriptopen.lastIndex = 0;
|
||||
|
||||
return iframedelay;
|
||||
}());
|
||||
var parts = [],
|
||||
source = '',
|
||||
js = '',
|
||||
css = '',
|
||||
close = '',
|
||||
hasHTML = false,
|
||||
hasCSS = false,
|
||||
hasJS = false,
|
||||
date = new Date(),
|
||||
scriptOffset = 0;
|
||||
|
||||
var re = null;
|
||||
|
||||
function two(i) {
|
||||
return ('0'+i).slice(-2);
|
||||
}
|
||||
|
||||
function getPreparedCode(nojs) {
|
||||
// init the regular expression cache because this function
|
||||
// is called much earlier than the above code is actually encountered
|
||||
// yay for massive .js app!
|
||||
if (!re) {
|
||||
re = {
|
||||
docReady: /\$\(document\)\.ready/,
|
||||
shortDocReady: /\$\(function/,
|
||||
console: /(^.|\b)console\.(\S+)/g,
|
||||
script: /<\/script/ig,
|
||||
code: /%code%/,
|
||||
title: /<title>(.*)<\/title>/i,
|
||||
winLoad: /window\.onload\s*=/,
|
||||
scriptopen: /<script/gi
|
||||
};
|
||||
}
|
||||
|
||||
// reset all the regexp positions for reuse
|
||||
re.docReady.lastIndex = 0;
|
||||
re.shortDocReady.lastIndex = 0;
|
||||
re.console.lastIndex = 0;
|
||||
re.script.lastIndex = 0;
|
||||
re.code.lastIndex = 0;
|
||||
re.title.lastIndex = 0;
|
||||
re.winLoad.lastIndex = 0;
|
||||
re.scriptopen.lastIndex = 0;
|
||||
|
||||
var parts = [],
|
||||
source = '',
|
||||
js = '',
|
||||
css = '',
|
||||
close = '',
|
||||
hasHTML = false,
|
||||
hasCSS = false,
|
||||
hasJS = false,
|
||||
date = new Date(),
|
||||
scriptOffset = 0;
|
||||
|
||||
try {
|
||||
source = editors.html.render();
|
||||
} catch (e) {
|
||||
window.console && window.console.error(e.message);
|
||||
}
|
||||
|
||||
hasHTML = !!$.trim(source);
|
||||
|
||||
if (!nojs) {
|
||||
try {
|
||||
js = editors.javascript.render();
|
||||
|
||||
if (js.trim()) js += '\n\n// created @ ' + two(date.getHours()) + ':' + two(date.getMinutes()) + ':' + two(date.getSeconds());
|
||||
source = editors.html.render();
|
||||
} catch (e) {
|
||||
window.console && window.console.error(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
hasJS = !!js.trim();
|
||||
hasHTML = !!$.trim(source);
|
||||
|
||||
try {
|
||||
css = editors.css.render();
|
||||
} catch (e) {
|
||||
window.console && window.console.error(e.message);
|
||||
}
|
||||
if (!nojs) {
|
||||
try {
|
||||
js = editors.javascript.render();
|
||||
|
||||
hasCSS = !!$.trim(css);
|
||||
|
||||
// escape any script tags in the JS code, because that'll break the mushing together
|
||||
js = js.replace(re.script, '<\\/script');
|
||||
|
||||
// note that I'm using split and reconcat instead of replace, because if the js var
|
||||
// contains '$$' it's replaced to '$' - thus breaking Prototype code. This method
|
||||
// gets around the problem.
|
||||
if (!hasHTML && hasJS) {
|
||||
source = "<pre>\n" + js.replace(/[<>&]/g, function (m) {
|
||||
if (m == '<') return '<';
|
||||
if (m == '>') return '>';
|
||||
if (m == '"') return '"';
|
||||
}) + "</pre>";
|
||||
} else if (re.code.test(source)) {
|
||||
parts = source.split('%code%');
|
||||
source = parts[0] + js + parts[1];
|
||||
scriptOffset = parts[0].split('\n').length;
|
||||
} else if (hasJS) {
|
||||
close = '';
|
||||
if (source.indexOf('</body>') !== -1) {
|
||||
parts.push(source.substring(0, source.lastIndexOf('</body>')));
|
||||
parts.push(source.substring(source.lastIndexOf('</body>')));
|
||||
|
||||
source = parts[0];
|
||||
close = parts.length == 2 && parts[1] ? parts[1] : '';
|
||||
if (js.trim()) js += '\n\n// created @ ' + two(date.getHours()) + ':' + two(date.getMinutes()) + ':' + two(date.getSeconds());
|
||||
} catch (e) {
|
||||
window.console && window.console.error(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
// RS: not sure why I ran this in closure, but it means the expected globals are no longer so
|
||||
// js = "window.onload = function(){" + js + "\n}\n";
|
||||
var type = jsbin.panels.panels.javascript.type ? ' type="text/' + jsbin.panels.panels.javascript.type + '"' : '';
|
||||
hasJS = !!js.trim();
|
||||
|
||||
scriptOffset = source.split('\n').length - 1;
|
||||
source += "<script" + type + ">\n" + js + "\n</script>\n" + close;
|
||||
}
|
||||
|
||||
// redirect console logged to our custom log while debugging
|
||||
if (re.console.test(source)) {
|
||||
var replaceWith = 'window.runnerWindow.proxyconsole.';
|
||||
// yes, this code looks stupid, but in fact what it does is look for
|
||||
// 'console.' and then checks the position of the code. If it's inside
|
||||
// an openning script tag, it'll change it to window.top._console,
|
||||
// otherwise it'll leave it.
|
||||
source = source.replace(re.console, function (all, str, arg, pos) {
|
||||
var open = source.lastIndexOf('<script', pos),
|
||||
close = source.lastIndexOf('</script', pos);
|
||||
|
||||
if (open > close) {
|
||||
return replaceWith + arg;
|
||||
} else {
|
||||
return all;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!hasHTML && !hasJS && hasCSS) {
|
||||
source = "<pre>\n" + css + "</pre>";
|
||||
} else if (css && hasHTML) {
|
||||
parts = [];
|
||||
close = '';
|
||||
if (source.indexOf('</head>') !== -1) {
|
||||
parts.push(source.substring(0, source.lastIndexOf('</head>')));
|
||||
parts.push(source.substring(source.lastIndexOf('</head>')));
|
||||
|
||||
source = parts[0];
|
||||
close = parts.length == 2 && parts[1] ? parts[1] : '';
|
||||
try {
|
||||
css = editors.css.render();
|
||||
} catch (e) {
|
||||
window.console && window.console.error(e.message);
|
||||
}
|
||||
source += '<style>\n' + css + '\n</style>\n' + close;
|
||||
scriptOffset += (2 + css.split('\n').length);
|
||||
}
|
||||
|
||||
// specific change for rendering $(document).ready() because iframes doesn't trigger ready (TODO - really test in IE, may have been fixed...)
|
||||
// if (re.docReady.test(source)) {
|
||||
// source = source.replace(re.docReady, 'window.onload = ');
|
||||
// } else if (re.shortDocReady.test(source)) {
|
||||
// source = source.replace(re.shortDocReady, 'window.onload = (function');
|
||||
// }
|
||||
hasCSS = !!$.trim(css);
|
||||
|
||||
// Add defer to all inline script tags in IE.
|
||||
// This is because IE runs scripts as it loads them, so variables that scripts like jQuery add to the
|
||||
// global scope are undefined. See http://jsbin.com/ijapom/5
|
||||
if (jsbin.ie && re.scriptopen.test(source)) {
|
||||
source = source.replace(/<script(.*?)>/gi, function (all, match) {
|
||||
if (match.indexOf('src') !== -1) {
|
||||
return all;
|
||||
} else {
|
||||
return '<script defer' + match + '>';
|
||||
// Rewrite loops to detect infiniteness.
|
||||
// This is done by rewriting the for/while/do loops to perform a check at
|
||||
// the start of each iteration.
|
||||
js = loopProtect.rewriteLoops(js);
|
||||
|
||||
// escape any script tags in the JS code, because that'll break the mushing together
|
||||
js = js.replace(re.script, '<\\/script');
|
||||
|
||||
// note that I'm using split and reconcat instead of replace, because if the js var
|
||||
// contains '$$' it's replaced to '$' - thus breaking Prototype code. This method
|
||||
// gets around the problem.
|
||||
if (!hasHTML && hasJS) {
|
||||
source = "<pre>\n" + js.replace(/[<>&]/g, function (m) {
|
||||
if (m == '<') return '<';
|
||||
if (m == '>') return '>';
|
||||
if (m == '"') return '"';
|
||||
}) + "</pre>";
|
||||
} else if (re.code.test(source)) {
|
||||
parts = source.split('%code%');
|
||||
source = parts[0] + js + parts[1];
|
||||
scriptOffset = parts[0].split('\n').length;
|
||||
} else if (hasJS) {
|
||||
close = '';
|
||||
if (source.indexOf('</body>') !== -1) {
|
||||
parts.push(source.substring(0, source.lastIndexOf('</body>')));
|
||||
parts.push(source.substring(source.lastIndexOf('</body>')));
|
||||
|
||||
source = parts[0];
|
||||
close = parts.length == 2 && parts[1] ? parts[1] : '';
|
||||
}
|
||||
});
|
||||
|
||||
// RS: not sure why I ran this in closure, but it means the expected globals are no longer so
|
||||
// js = "window.onload = function(){" + js + "\n}\n";
|
||||
var type = jsbin.panels.panels.javascript.type ? ' type="text/' + jsbin.panels.panels.javascript.type + '"' : '';
|
||||
|
||||
scriptOffset = source.split('\n').length - 1;
|
||||
source += "<script" + type + ">\n" + js + "\n</script>\n" + close;
|
||||
}
|
||||
|
||||
// redirect console logged to our custom log while debugging
|
||||
if (re.console.test(source)) {
|
||||
var replaceWith = 'window.runnerWindow.proxyConsole.';
|
||||
// yes, this code looks stupid, but in fact what it does is look for
|
||||
// 'console.' and then checks the position of the code. If it's inside
|
||||
// an openning script tag, it'll change it to window.top._console,
|
||||
// otherwise it'll leave it.
|
||||
source = source.replace(re.console, function (all, str, arg, pos) {
|
||||
var open = source.lastIndexOf('<script', pos),
|
||||
close = source.lastIndexOf('</script', pos);
|
||||
|
||||
if (open > close) {
|
||||
return replaceWith + arg;
|
||||
} else {
|
||||
return all;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!hasHTML && !hasJS && hasCSS) {
|
||||
source = "<pre>\n" + css + "</pre>";
|
||||
} else if (css && hasHTML) {
|
||||
parts = [];
|
||||
close = '';
|
||||
if (source.indexOf('</head>') !== -1) {
|
||||
parts.push(source.substring(0, source.lastIndexOf('</head>')));
|
||||
parts.push(source.substring(source.lastIndexOf('</head>')));
|
||||
|
||||
source = parts[0];
|
||||
close = parts.length == 2 && parts[1] ? parts[1] : '';
|
||||
}
|
||||
source += '<style>\n' + css + '\n</style>\n' + close;
|
||||
scriptOffset += (2 + css.split('\n').length);
|
||||
}
|
||||
|
||||
// specific change for rendering $(document).ready() because iframes doesn't trigger ready (TODO - really test in IE, may have been fixed...)
|
||||
// if (re.docReady.test(source)) {
|
||||
// source = source.replace(re.docReady, 'window.onload = ');
|
||||
// } else if (re.shortDocReady.test(source)) {
|
||||
// source = source.replace(re.shortDocReady, 'window.onload = (function');
|
||||
// }
|
||||
|
||||
// Add defer to all inline script tags in IE.
|
||||
// This is because IE runs scripts as it loads them, so variables that
|
||||
// scripts like jQuery add to the global scope are undefined.
|
||||
// See http://jsbin.com/ijapom/5
|
||||
if (jsbin.ie && re.scriptopen.test(source)) {
|
||||
source = source.replace(/<script(.*?)>/gi, function (all, match) {
|
||||
if (match.indexOf('src') !== -1) {
|
||||
return all;
|
||||
} else {
|
||||
return '<script defer' + match + '>';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// read the element out of the source code and plug it in to our document.title
|
||||
var newDocTitle = source.match(re.title);
|
||||
if (newDocTitle !== null && newDocTitle[1] !== documentTitle) {
|
||||
documentTitle = newDocTitle[1];
|
||||
document.title = documentTitle + ' - ' + 'JS Bin';
|
||||
}
|
||||
|
||||
return { source: source, scriptOffset: scriptOffset };
|
||||
}
|
||||
|
||||
// read the element out of the source code and plug it in to our document.title
|
||||
var newDocTitle = source.match(re.title);
|
||||
if (newDocTitle !== null && newDocTitle[1] !== documentTitle) {
|
||||
documentTitle = newDocTitle[1];
|
||||
document.title = documentTitle + ' - ' + 'JS Bin';
|
||||
}
|
||||
|
||||
return { source: source, scriptOffset: scriptOffset };
|
||||
}
|
||||
}());
|
||||
|
||||
92
public/js/runner/loop-protect.js
Normal file
92
public/js/runner/loop-protect.js
Normal file
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Protect against infinite loops.
|
||||
* Look for for, while and do loops, and insert a check function at the start of
|
||||
* the loop. If the check function is called many many times then it returns
|
||||
* true, preventing the loop from running again.
|
||||
*/
|
||||
var loopProtect = (function () {
|
||||
|
||||
var loopProtect = {};
|
||||
|
||||
// used in the loop detection
|
||||
loopProtect.counters = {};
|
||||
|
||||
/**
|
||||
* Look for for, while and do loops, and inserts *just* at the start of the
|
||||
* loop, a check function.
|
||||
*/
|
||||
loopProtect.rewriteLoops = function (code, offset) {
|
||||
var recompiled = [],
|
||||
lines = code.split('\n'),
|
||||
re = /for\b|while\b|do\b/;
|
||||
|
||||
if (!offset) offset = 0;
|
||||
|
||||
var method = 'window.runnerWindow.protect';
|
||||
|
||||
lines.forEach(function (line, i) {
|
||||
var index = 0,
|
||||
lineNum = i - offset;
|
||||
|
||||
if (re.test(line) && line.indexOf('jsbin') === -1) {
|
||||
// try to insert the tracker after the openning brace (like while (true) { ^here^ )
|
||||
index = line.indexOf('{');
|
||||
if (index !== -1) {
|
||||
line = line.substring(0, index + 1) + ';\nif (' + method + '({ line: ' + lineNum + ' })) break;';
|
||||
} else {
|
||||
index = line.indexOf(')');
|
||||
if (index !== -1) {
|
||||
// look for a one liner
|
||||
var colonIndex = line.substring(index).indexOf(';');
|
||||
if (colonIndex !== -1) {
|
||||
// in which case, rewrite the loop to add braces
|
||||
colonIndex += index;
|
||||
line = line.substring(0, index + 1) + '{\nif (' + method + '({ line: ' + lineNum + ' })) break;\n' + line.substring(index + 1) + '\n}\n'; // extra new lines ensure we clear comment lines
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
line = ';' + method + '({ line: ' + lineNum + ', reset: true });\n' + line;
|
||||
loopProtect.counters[lineNum] = {};
|
||||
}
|
||||
recompiled.push(line);
|
||||
});
|
||||
|
||||
return recompiled.join('\n');
|
||||
};
|
||||
|
||||
/**
|
||||
* Injected code in to user's code to **try** to protect against infinite
|
||||
* loops cropping up in the code, and killing the browser. Returns true
|
||||
* when the loops has been running for more than 100ms.
|
||||
*/
|
||||
loopProtect.protect = function (state) {
|
||||
loopProtect.counters[state.line] = loopProtect.counters[state.line] || {};
|
||||
var line = loopProtect.counters[state.line];
|
||||
if (state.reset) {
|
||||
line.time = +new Date;
|
||||
}
|
||||
if ((+new Date - line.time) > 100) {
|
||||
// We've spent over 100ms on this loop... smells infinite.
|
||||
var msg = "Suspicious loop detected at line " + state.line;
|
||||
if (window.proxyConsole) {
|
||||
window.proxyConsole.error(msg);
|
||||
} else console.error(msg);
|
||||
// Returning true prevents the loop running again
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
loopProtect.reset = function () {
|
||||
// reset the counters
|
||||
loopProtect.counters = {};
|
||||
};
|
||||
|
||||
return loopProtect;
|
||||
|
||||
}());
|
||||
|
||||
if (typeof exports !== 'undefined') {
|
||||
module.exports = loopProtect;
|
||||
}
|
||||
@ -42,78 +42,6 @@ var processor = (function () {
|
||||
}) + '</pre>';
|
||||
};
|
||||
|
||||
// used in the loop detection
|
||||
processor.counters = {};
|
||||
|
||||
/**
|
||||
* Look for for, while and do loops, and inserts *just* at the start
|
||||
* of the loop, a check function. If the check function is called
|
||||
* many many times, then it throws an exception suspecting this might
|
||||
* be an infinite loop.
|
||||
*/
|
||||
processor.rewriteLoops = function (code, offset) {
|
||||
var recompiled = [],
|
||||
lines = code.split('\n'),
|
||||
re = /for\b|while\b|do\b/;
|
||||
|
||||
if (!offset) offset = 0;
|
||||
|
||||
// reset the counters
|
||||
processor.counters = {};
|
||||
|
||||
var counter = 'window.runnerWindow.protect';
|
||||
|
||||
lines.forEach(function (line, i) {
|
||||
var index = 0,
|
||||
lineNum = i - offset;
|
||||
|
||||
if (re.test(line) && line.indexOf('jsbin') === -1) {
|
||||
// try to insert the tracker after the openning brace (like while (true) { ^here^ )
|
||||
index = line.indexOf('{');
|
||||
if (index !== -1) {
|
||||
line = line.substring(0, index + 1) + ';\nif (' + counter + '({ line: ' + lineNum + ' })) break;';
|
||||
} else {
|
||||
index = line.indexOf(')');
|
||||
if (index !== -1) {
|
||||
// look for a one liner
|
||||
var colonIndex = line.substring(index).indexOf(';');
|
||||
if (colonIndex !== -1) {
|
||||
// in which case, rewrite the loop to add braces
|
||||
colonIndex += index;
|
||||
line = line.substring(0, index + 1) + '{\nif (' + counter + '({ line: ' + lineNum + ' })) break;\n' + line.substring(index + 1) + '\n}\n'; // extra new lines ensure we clear comment lines
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
line = ';' + counter + '({ line: ' + lineNum + ', reset: true });\n' + line;
|
||||
processor.counters[lineNum] = {};
|
||||
}
|
||||
recompiled.push(line);
|
||||
});
|
||||
|
||||
return recompiled.join('\n');
|
||||
};
|
||||
|
||||
/**
|
||||
* Injected code in to user's code to **try** to protect against infinite loops
|
||||
* cropping up in the code, and killing the browser. This will throw an exception
|
||||
* when a loop has hit over X number of times.
|
||||
*/
|
||||
processor.protect = function (state) {
|
||||
var line = processor.counters[state.line];
|
||||
if (state.reset) {
|
||||
line.count = 0;
|
||||
} else {
|
||||
line.count++;
|
||||
if (line.count > 100000) {
|
||||
// we've done a ton of loops, then let's say it smells like an infinite loop
|
||||
console.error("Suspicious loop detected at line " + state.line);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Render – build the final source code to be written to the iframe. Takes
|
||||
* the original source and an options object.
|
||||
@ -123,7 +51,6 @@ var processor = (function () {
|
||||
options = options || [];
|
||||
source = source || '';
|
||||
|
||||
|
||||
var combinedSource = [],
|
||||
realtime = (options.requested !== true),
|
||||
noRealtimeJs = (options.includeJsInRealtime === false);
|
||||
@ -138,13 +65,6 @@ var processor = (function () {
|
||||
// the editable area.
|
||||
source = source.replace(/(<.*?\s)(autofocus)/g, '$1');
|
||||
|
||||
|
||||
// since we're running in real time, let's try hook in some loop protection
|
||||
// basically if a loop runs for many, many times, it's probably an infinite loop
|
||||
// so we'll throw an exception. This is done by rewriting the for/while/do
|
||||
// loops to call our check at the start of each.
|
||||
source = processor.rewriteLoops(source, options.scriptOffset);
|
||||
|
||||
// Make sure the doctype is the first thing in the source
|
||||
var doctypeObj = processor.getDoctype(source),
|
||||
doctype = doctypeObj.doctype;
|
||||
|
||||
@ -3,17 +3,17 @@
|
||||
* Proxy console.logs out to the parent window
|
||||
* ========================================================================== */
|
||||
|
||||
var proxyconsole = (function () {
|
||||
var proxyConsole = (function () {
|
||||
|
||||
var supportsConsole = true;
|
||||
try { window.console.log('runner'); } catch (e) { supportsConsole = false; }
|
||||
|
||||
var proxyconsole = {};
|
||||
var proxyConsole = {};
|
||||
|
||||
/**
|
||||
* Stringify all of the console objects from an array for proxying
|
||||
*/
|
||||
proxyconsole.stringifyArgs = function (args) {
|
||||
proxyConsole.stringifyArgs = function (args) {
|
||||
var newArgs = [];
|
||||
// TODO this was forEach but when the array is [undefined] it wouldn't
|
||||
// iterate over them
|
||||
@ -34,10 +34,10 @@ var proxyconsole = (function () {
|
||||
var methods = ['debug', 'error', 'info', 'log', 'warn', 'dir', 'props'];
|
||||
methods.forEach(function (method) {
|
||||
// Create console method
|
||||
proxyconsole[method] = function () {
|
||||
proxyConsole[method] = function () {
|
||||
// Replace args that can't be sent through postMessage
|
||||
var originalArgs = [].slice.call(arguments),
|
||||
args = proxyconsole.stringifyArgs(originalArgs);
|
||||
args = proxyConsole.stringifyArgs(originalArgs);
|
||||
// Post up with method and the arguments
|
||||
runner.postMessage('console', {
|
||||
method: method,
|
||||
@ -51,6 +51,6 @@ var proxyconsole = (function () {
|
||||
};
|
||||
});
|
||||
|
||||
return proxyconsole;
|
||||
return proxyConsole;
|
||||
|
||||
}());
|
||||
@ -84,8 +84,8 @@ var runner = (function () {
|
||||
// that the user's code (that runs as a result of the following
|
||||
// childDoc.write) can access the objects.
|
||||
childWindow.runnerWindow = {
|
||||
proxyconsole: proxyconsole,
|
||||
protect: processor.protect
|
||||
proxyConsole: proxyConsole,
|
||||
protect: loopProtect.protect
|
||||
};
|
||||
|
||||
// Write the source out. IE crashes if you have lots of these, so that's
|
||||
|
||||
@ -130,7 +130,7 @@ var sandbox = (function () {
|
||||
output = e.message;
|
||||
type = 'error';
|
||||
}
|
||||
return proxyconsole[type](output);
|
||||
return proxyConsole[type](output);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
"/js/vendor/codemirror3/addon/search/match-highlighter.js",
|
||||
"/js/vendor/json2.js",
|
||||
"/js/vendor/prettyprint.js",
|
||||
"/js/runner/loop-protect.js",
|
||||
"/js/chrome/storage.js",
|
||||
"/js/jsbin.js",
|
||||
"/js/editors/mobileCodeMirror.js",
|
||||
@ -51,7 +52,8 @@
|
||||
"/js/vendor/polyfills.js",
|
||||
"/js/vendor/stringify.js",
|
||||
"/js/runner/utils.js",
|
||||
"/js/runner/proxyconsole.js",
|
||||
"/js/runner/loop-protect.js",
|
||||
"/js/runner/proxy-console.js",
|
||||
"/js/runner/processor.js",
|
||||
"/js/runner/sandbox.js",
|
||||
"/js/runner/runner.js",
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
var assert = require('assert');
|
||||
var sinon = require('sinon');
|
||||
var processor = require('../public/js/runner/processor');
|
||||
var loopProtect = require('../public/js/runner/loop-protect');
|
||||
|
||||
// expose a window object for processor compatibility
|
||||
// expose a window object for loopProtect compatibility
|
||||
global.window = {
|
||||
runnerWindow: processor
|
||||
runnerWindow: loopProtect
|
||||
};
|
||||
|
||||
var code = {
|
||||
@ -14,7 +14,7 @@ var code = {
|
||||
simplewhile: 'var i = 0; while (i < 100) {\ni += 10;\n}\nreturn i;',
|
||||
onelinewhile: 'var i = 0; while (i < 100) i += 10;\nreturn i;',
|
||||
whiletrue: 'var i = 0;\nwhile(true) {\ni++;\n}\nreturn i;',
|
||||
irl1: 'var nums = [0,1];\n var total = 8;\n for(i = 0; i <= total; i++){\n var newest = nums[i--]\n nums.push(newest);\n }\n return (nums);',
|
||||
irl1: 'var nums = [0,1];\n var total = 8;\n for(var i = 0; i <= total; i++){\n var newest = nums[i--]\n nums.push(newest);\n }\n return (nums);',
|
||||
irl2: 'var a = 0;\n for(var j=1;j<=2;j++){\n for(var i=1;i<=60000;i++) {\n a += 1;\n }\n }\n return a;',
|
||||
};
|
||||
|
||||
@ -32,25 +32,25 @@ describe('loop', function () {
|
||||
|
||||
|
||||
it('should leave none loop code alone', function () {
|
||||
assert(processor.rewriteLoops(code.simple) === code.simple);
|
||||
assert(loopProtect.rewriteLoops(code.simple) === code.simple);
|
||||
});
|
||||
|
||||
it('should rewrite for loops', function () {
|
||||
var compiled = processor.rewriteLoops(code.simplefor);
|
||||
var compiled = loopProtect.rewriteLoops(code.simplefor);
|
||||
assert(compiled !== code);
|
||||
var result = run(compiled);
|
||||
assert(result === 9);
|
||||
});
|
||||
|
||||
it('should rewrite one line for loops', function () {
|
||||
var compiled = processor.rewriteLoops(code.onelinefor);
|
||||
var compiled = loopProtect.rewriteLoops(code.onelinefor);
|
||||
assert(compiled !== code);
|
||||
var result = run(compiled);
|
||||
assert(result === 10);
|
||||
});
|
||||
|
||||
it('should throw on infinite while', function () {
|
||||
var compiled = processor.rewriteLoops(code.whiletrue);
|
||||
var compiled = loopProtect.rewriteLoops(code.whiletrue);
|
||||
|
||||
try { spy(compiled); } catch (e) {}
|
||||
|
||||
@ -58,13 +58,13 @@ describe('loop', function () {
|
||||
});
|
||||
|
||||
it('should throw on infinite for', function () {
|
||||
var compiled = processor.rewriteLoops(code.irl1);
|
||||
var compiled = loopProtect.rewriteLoops(code.irl1);
|
||||
try { spy(compiled); } catch (e) {}
|
||||
assert(spy.threw);
|
||||
});
|
||||
|
||||
it('should should allow nested loops to run', function () {
|
||||
var compiled = processor.rewriteLoops(code.irl2);
|
||||
var compiled = loopProtect.rewriteLoops(code.irl2);
|
||||
assert(run(compiled) === 120000);
|
||||
});
|
||||
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
--require should sinon
|
||||
--require should
|
||||
--reporter spec
|
||||
--ui bdd
|
||||
@ -1,39 +1,39 @@
|
||||
var spike = require('../lib/spike');
|
||||
// var spike = require('../lib/spike');
|
||||
|
||||
describe('splike.utils.makeEvent', function () {
|
||||
// describe('splike.utils.makeEvent', function () {
|
||||
|
||||
it('should convert some string data into a valid event', function () {
|
||||
var result = spike.utils.makeEvent('example', 'hello');
|
||||
result.should.equal([
|
||||
'data:hello',
|
||||
'event:example',
|
||||
'\n'
|
||||
].join('\n'));
|
||||
});
|
||||
// it('should convert some string data into a valid event', function () {
|
||||
// var result = spike.utils.makeEvent('example', 'hello');
|
||||
// result.should.equal([
|
||||
// 'data:hello',
|
||||
// 'event:example',
|
||||
// '\n'
|
||||
// ].join('\n'));
|
||||
// });
|
||||
|
||||
it('should convert and object into a valid event', function () {
|
||||
var result = spike.utils.makeEvent('example', {
|
||||
a: 10,
|
||||
b: 20
|
||||
});
|
||||
result.should.equal([
|
||||
'data:{"a":10,"b":20}',
|
||||
'event:example',
|
||||
'\n'
|
||||
].join('\n'));
|
||||
});
|
||||
// it('should convert and object into a valid event', function () {
|
||||
// var result = spike.utils.makeEvent('example', {
|
||||
// a: 10,
|
||||
// b: 20
|
||||
// });
|
||||
// result.should.equal([
|
||||
// 'data:{"a":10,"b":20}',
|
||||
// 'event:example',
|
||||
// '\n'
|
||||
// ].join('\n'));
|
||||
// });
|
||||
|
||||
it('should create an event even if no data is passed', function () {
|
||||
var result = spike.utils.makeEvent('example');
|
||||
result.should.equal([
|
||||
'event:example',
|
||||
'\n'
|
||||
].join('\n'));
|
||||
});
|
||||
// it('should create an event even if no data is passed', function () {
|
||||
// var result = spike.utils.makeEvent('example');
|
||||
// result.should.equal([
|
||||
// 'event:example',
|
||||
// '\n'
|
||||
// ].join('\n'));
|
||||
// });
|
||||
|
||||
it('should return nothing if nothing is passed', function () {
|
||||
var result = spike.utils.makeEvent();
|
||||
result.should.equal('');
|
||||
});
|
||||
// it('should return nothing if nothing is passed', function () {
|
||||
// var result = spike.utils.makeEvent();
|
||||
// result.should.equal('');
|
||||
// });
|
||||
|
||||
});
|
||||
// });
|
||||
Loading…
x
Reference in New Issue
Block a user