Semi-synchronous mode to avoid HEAD element insertion issues causing some userscripts to fail.

This commit is contained in:
hackademix 2019-10-30 23:37:30 +01:00
parent cf4364e8c2
commit 17ebef5a48
1 changed files with 46 additions and 14 deletions

View File

@ -169,7 +169,7 @@
// Content Script side // Content Script side
let uuid = () => (Math.random() * Date.now()).toString(16); let uuid = () => (Math.random() * Date.now()).toString(16);
let docUrl = document.URL; let docUrl = document.URL;
browser.runtime.sendSyncMessage = msg => { browser.runtime.sendSyncMessage = (msg, callback) => {
let msgId = `${uuid()},${docUrl}`; let msgId = `${uuid()},${docUrl}`;
let url = `${ENDPOINT_PREFIX}id=${encodeURIComponent(msgId)}` + let url = `${ENDPOINT_PREFIX}id=${encodeURIComponent(msgId)}` +
`&url=${encodeURIComponent(docUrl)}`; `&url=${encodeURIComponent(docUrl)}`;
@ -178,16 +178,25 @@
// about frameAncestors // about frameAncestors
url += "&top=true"; url += "&top=true";
} }
/*
if (document.documentElement instanceof HTMLElement && !document.head) {
// let's insert a head element to let userscripts work
document.documentElement.appendChild(document.createElement("head"));
}*/
if (MOZILLA) { if (MOZILLA) {
// on Firefox we first need to send an async message telling the // on Firefox we first need to send an async message telling the
// background script about the tab ID, which does not get sent // background script about the tab ID, which does not get sent
// with "privileged" XHR // with "privileged" XHR
let result; let result, done = false;
browser.runtime.sendMessage( browser.runtime.sendMessage(
{__syncMessage__: {id: msgId, payload: msg}} {__syncMessage__: {id: msgId, payload: msg}}
).then(r => { ).then(r => {
done = true;
result = r; result = r;
if (callback) callback(r);
}).catch(e => { }).catch(e => {
done = true;
throw e; throw e;
}); });
@ -198,24 +207,45 @@
let suspendURL = url + "&suspend=true"; let suspendURL = url + "&suspend=true";
let suspended = false; let suspended = false;
let suspend = () => { let suspend = () => {
if (result || suspended) return; if (suspended) return;
suspended = true; suspended = true;
while(!done) {
try { try {
let r = new XMLHttpRequest(); let r = new XMLHttpRequest();
r.open("GET", suspendURL, false); r.open("GET", suspendURL, false);
r.send(null); r.send(null);
} finally { } catch (e) {
suspended = false; console.error(e);
} }
}
suspended = false;
}; };
let domSuspender = new MutationObserver(suspend); let domSuspender = new MutationObserver(records => {
suspend();
});
domSuspender.observe(document.documentElement, {childList: true}); domSuspender.observe(document.documentElement, {childList: true});
addEventListener("beforescriptexecute", suspend, true); addEventListener("beforescriptexecute", suspend, true);
let finalize = () => {
removeEventListener("beforescriptexecute", suspend, true);
domSuspender.disconnect();
};
if (callback) {
let realCB = callback;
callback = r => {
try {
realCB(r);
} finally {
finalize();
}
};
return;
}
try { try {
suspend(); suspend();
} finally { } finally {
removeEventListener("beforescriptexecute", suspend, true); finalize();
domSuspender.disconnect();
} }
return result; return result;
} }
@ -224,14 +254,16 @@
url += `&msg=${encodeURIComponent(JSON.stringify(msg))}`; // adding the payload url += `&msg=${encodeURIComponent(JSON.stringify(msg))}`; // adding the payload
let r = new XMLHttpRequest(); let r = new XMLHttpRequest();
let result;
try { try {
r.open("GET", url, false); r.open("GET", url, false);
r.send(null); r.send(null);
return JSON.parse(r.responseText); result = JSON.parse(r.responseText);
} catch(e) { } catch(e) {
console.error(`syncMessage error in ${document.URL}: ${e.message} (response ${r.responseText})`); console.error(`syncMessage error in ${document.URL}: ${e.message} (response ${r.responseText})`);
} }
return null; if (callback) callback(result);
return result;
}; };
} }
})(); })();