How To Simulate Script injection
Let's say you want a test but you don't want to bother a server. However, you want to be sure the test is asynchronous and it simulates the server.
var
head = document.getElementsByTagName("head")[0],
script = document.createElement("script")
;
head.insertBefore(script, head.lastChild);
script.src = "data:text/javascript;base64," + btoa(
"alert('Hello World')"
);
How To Simulate JSONP
Same trick, isn't it? ... except:
script.src = "data:text/javascript;base64," + btoa(
"callback(" + JSON.stringify(dummyData) + ")"
);
How To Drop Server Requests
well, this is the tricky one ...
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
document.createElement = function ( | |
createElement, // the native one | |
createResponse // the function "in charge" | |
) { | |
return function (nodeName) { | |
var result, src; | |
// if we are creating a script | |
if (/^script$/i.test(nodeName)) { | |
// result will be a place holder | |
result = createElement.call( | |
document, | |
"meta" | |
); | |
// we need to monitor the src property | |
Object.defineProperty(result, "src", { | |
get: function () { | |
return src; | |
}, | |
// when set ... | |
set: function ($src) { | |
// we can check periodically ... | |
function T() { | |
// if the placeholder is in DOM | |
if (result.parentNode) { | |
// in this case we can put a real script | |
result = result.parentNode.insertBefore( | |
createElement.call( | |
document, | |
"script" | |
), | |
result | |
); | |
// and set the encoded src | |
result.src = "data:text/javascript;base64," + | |
btoa(createResponse.call(result, src)) | |
; | |
} else { | |
// no DOM, no loading ... try later | |
setTimeout(T, 100); | |
} | |
} | |
// store the src | |
src = $src; | |
// and start checking | |
T(); | |
} | |
}); | |
} else { | |
// just return the element | |
result = createElement.call( | |
document, | |
nodeName | |
); | |
} | |
return result; | |
}; | |
}( | |
document.createElement, | |
// must return a string | |
function (src) { | |
// this points to the current script | |
// src is the address | |
// if we know the callback ... | |
if (/callback=([^&]+)/.test(src)) { | |
return RegExp.$1 + '(' + | |
JSON.stringify({dummy:"data"}) | |
+ ')'; | |
} | |
} | |
); | |
// example | |
function test(data) { | |
alert(data.dummy); | |
} | |
document.documentElement.insertBefore( | |
document.createElement("script"), | |
document.documentElement.lastChild | |
).src = "page.php?callback=test"; |
Surely there is some job to do in the createResponse() function but ... hey, we can stop bothering servers now ;)
3 comments:
What about not encoding into base64 the script src ?
e.g.:
script.src = "data:text/javascript;,alert('Hello World')";
it may have unexpected behavior with non ascii char due attribute restrictions.
Indeed even btoa is not enough, base64.encode(whateverItIs) is much better
P.S. btw ... that was kinda *not* the point about the whole post but thanks for pointing it out
Post a Comment