There is no direct way to intercept the loading process itself, but by leveraging the behavior of scripts with custom types, it is possible to manipulate the document loading sequence through a clever workaround.
By invoking window.stop
, the document loading can be halted abruptly at the outset, indicating that the full document has not been loaded successfully.
Subsequently, an XHR request can retrieve the document content for further modification. Using search and replace techniques, all script elements in the document can be rendered inactive by assigning them a specific type before injecting the modified content back into the document flow.
window.stop();
var request = new XMLHttpRequest();
request.open('GET', location.href);
request.onload = function(event) {
var html = request.responseText
.replace(/type=\"text\/javascript\"/g, '')
.replace(/<script/g, '<script type="x-instrument/javascript"');
document.open();
document.write(html);
document.close();
};
request.send(null);
At this stage, all scripts have been effectively neutralized, allowing for the implementation of a basic sequential loader as illustrated below:
setTimeout(function next(index) {
var script = document.scripts[index];
if (script == null) {
return setTimeout(callback, 0);
}
if (script.hasAttribute('src')) {
var request = new XMLHttpRequest();
request.open('GET', script.getAttribute('src'));
request.onload = function() {
var code = instrument(request.responseText);
eval(code);
setTimeout(next, 0, ++index);
};
request.send(null);
} else {
var code = instrument(script.textContent);
eval(code);
setTimeout(next, 0, ++index);
}
}, 0, 0);
This approach allows any page to undergo instrumentation simply by injecting the aforementioned script at the beginning of the document.
If preferred, the script can also be loaded as a content script within a Chrome extension, ensuring that the run_at
attribute is set to document_start
.
{
"manifest_version": 2,
"name": "instrument",
"version": "0.0.0",
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["instrument.js"],
"run_at": "document_start"
}
],
"web_accessible_resources": [
"instrument.js"
],
"permissions": [
"tabs", "<all_urls>"
]
}
Example