console and execute-script work. with test

This commit is contained in:
Omar Rizwan 2020-12-30 22:44:25 -08:00
parent b09951ebc2
commit 957ea5a3d4
2 changed files with 45 additions and 15 deletions

View file

@ -229,51 +229,72 @@ router["/tabs/by-id"] = {
router["/tabs/by-id/*/text.txt"] = fromScript(`document.body.innerText`); router["/tabs/by-id/*/text.txt"] = fromScript(`document.body.innerText`);
})(); })();
let nextConsoleFh = 0; let consoleForFh = {}; let nextConsoleFh = 0; let consoleForFh = {};
chrome.runtime.onMessage.addListener(data => {
if (!consoleForFh[data.fh]) return;
consoleForFh[data.fh].push(data.xs);
});
router["/tabs/by-id/*/console"] = { router["/tabs/by-id/*/console"] = {
// this one is a bit weird. it doesn't start tracking until it's opened.
// tail -f console
async getattr() {
return {
st_mode: unix.S_IFREG | 0444,
st_nlink: 1,
st_size: 0 // FIXME
};
},
async open({path}) { async open({path}) {
const tabId = parseInt(pathComponent(path, -2)); const tabId = parseInt(pathComponent(path, -2));
const fh = nextConsoleFh++; const fh = nextConsoleFh++;
const code = ` const code = `
// runs in 'content script' context // runs in 'content script' context
var script = document.createElement('script'); var script = document.createElement('script');
var code = document.createTextNode(\` var code = \`
// runs in real Web page context (this is where we want to hook console.log) // will run both here in content script context and in
// real Web page context (so we hook console.log for both)
(function() { (function() {
if (!console.__logOld) console.__logOld = console.log; if (!console.__logOld) console.__logOld = console.log;
if (!console.__logFhs) console.__logFhs = new Set();
console.__logFhs.add(${fh});
console.log = (...xs) => { console.log = (...xs) => {
console.__logOld(...xs); console.__logOld(...xs);
// TODO: use random event for security instead of this broadcast // TODO: use random event for security instead of this broadcast
window.postMessage({fh: ${fh}, xs: xs}, '*'); for (let fh of console.__logFhs) {
window.postMessage({fh: ${fh}, xs: xs}, '*');
}
}; };
})() })()
\`); \`;
script.appendChild(code); eval(code);
script.appendChild(document.createTextNode(code));
(document.body || document.head).appendChild(script); (document.body || document.head).appendChild(script);
window.addEventListener('message', function({data}) { window.addEventListener('message', function({data}) {
if (data.fh !== ${fh}) return; if (data.fh !== ${fh}) return;
// forward to the background script
chrome.runtime.sendMessage(null, data); chrome.runtime.sendMessage(null, data);
}); });
`; `;
consoleForFh[fh] = []; consoleForFh[fh] = [];
chrome.runtime.onMessage.addListener(data => {
if (data.fh !== fh) return;
consoleForFh[fh].push(data.xs);
});
await browser.tabs.executeScript(tabId, {code}); await browser.tabs.executeScript(tabId, {code});
return {fh}; return {fh};
}, },
async read({path, fh}) { async read({path, fh, offset, size}) {
const buf = consoleForFh[fh].join('\n'); const all = consoleForFh[fh].join('\n');
// TODO: do this more incrementally ?
// will probably break down if log is huge
const buf = String.fromCharCode(...toUtf8Array(all).slice(offset, offset + size));
return { buf }; return { buf };
}, },
async release({fh}) { async release({path, fh}) {
const tabId = parseInt(pathComponent(path, -2)); const tabId = parseInt(pathComponent(path, -2));
// TODO: clean up everything // TODO: clean up the hooks inside the contexts
delete consoleForFh[fh];
return {}; return {};
} }
}; };
router["/tabs/by-id/*/eval"] = { router["/tabs/by-id/*/execute-script"] = {
// note: runs in a content script, _not_ in the Web page context
async write({path, buf}) { async write({path, buf}) {
// FIXME: chunk this properly (like if they write a script in // FIXME: chunk this properly (like if they write a script in
// multiple chunks) and only execute when ready? // multiple chunks) and only execute when ready?

View file

@ -31,7 +31,7 @@ int matches_regex(char* str, char* pattern) {
// integration tests // integration tests
int main() { int main() {
// TODO: invoke over extension // TODO: invoke over extension
assert(system("node ../extension/background.js --unhandled-rejections=strict") == 0); // run quick local JS tests /* assert(system("node ../extension/background.js --unhandled-rejections=strict") == 0); // run quick local JS tests */
// reload the extension so we know it's the latest code. // reload the extension so we know it's the latest code.
system("echo reload > ../fs/mnt/runtime/reload 2>/dev/null"); // this may error, but it should still have effect system("echo reload > ../fs/mnt/runtime/reload 2>/dev/null"); // this may error, but it should still have effect
@ -50,6 +50,7 @@ int main() {
usleep(10000); usleep(10000);
assert(times++ < 10000); assert(times++ < 10000);
} }
assert(system("echo remove > ../fs/mnt/tabs/last-focused/control") == 0); assert(system("echo remove > ../fs/mnt/tabs/last-focused/control") == 0);
} }
@ -69,6 +70,14 @@ int main() {
} }
assert(system("cat ../fs/mnt/tabs/last-focused/debugger/scripts/*test-script.js") == 0); assert(system("cat ../fs/mnt/tabs/last-focused/debugger/scripts/*test-script.js") == 0);
{
FILE* console = fopen("../fs/mnt/tabs/last-focused/console", "r");
assert(system("echo \"console.log('hi')\" > ../fs/mnt/tabs/last-focused/execute-script") == 0);
char hi[3] = {0}; fread(hi, 1, 2, console);
assert(strcmp(hi, "hi") == 0);
fclose(console);
}
assert(system("echo remove > ../fs/mnt/tabs/last-focused/control") == 0); assert(system("echo remove > ../fs/mnt/tabs/last-focused/control") == 0);
} }