Bug 1403369: Correctly handle content-side errors in tabs.executeScript(). r?zombie
MozReview-Commit-ID: CPRV9PvWe9e
--- a/toolkit/components/extensions/ExtensionContent.jsm
+++ b/toolkit/components/extensions/ExtensionContent.jsm
@@ -257,32 +257,35 @@ class Script {
}
matchesWindow(window) {
return this.matcher.matchesWindow(window);
}
async injectInto(window) {
let context = this.extension.getContext(window);
+ try {
+ if (this.runAt === "document_end") {
+ await promiseDocumentReady(window.document);
+ } else if (this.runAt === "document_idle") {
+ let readyThenIdle = promiseDocumentReady(window.document).then(() => {
+ return new Promise(resolve =>
+ window.requestIdleCallback(resolve, {timeout: idleTimeout}));
+ });
- if (this.runAt === "document_end") {
- await promiseDocumentReady(window.document);
- } else if (this.runAt === "document_idle") {
- let readyThenIdle = promiseDocumentReady(window.document).then(() => {
- return new Promise(resolve =>
- window.requestIdleCallback(resolve, {timeout: idleTimeout}));
- });
+ await Promise.race([
+ readyThenIdle,
+ promiseDocumentLoaded(window.document),
+ ]);
+ }
- await Promise.race([
- readyThenIdle,
- promiseDocumentLoaded(window.document),
- ]);
+ return this.inject(context);
+ } catch (e) {
+ return Promise.reject(context.normalizeError(e));
}
-
- return this.inject(context);
}
/**
* Tries to inject this script into the given window and sandbox, if
* there are pending operations for the window's current load state.
*
* @param {BaseContext} context
* The content script context into which to inject the scripts.
@@ -723,18 +726,24 @@ this.ExtensionContent = {
async handleExtensionExecute(global, target, options, script) {
let executeInWin = (window) => {
if (script.matchesWindow(window)) {
return script.injectInto(window);
}
return null;
};
- let promises = Array.from(this.enumerateWindows(global.docShell), executeInWin)
- .filter(promise => promise);
+ let promises;
+ try {
+ promises = Array.from(this.enumerateWindows(global.docShell), executeInWin)
+ .filter(promise => promise);
+ } catch (e) {
+ Cu.reportError(e);
+ return Promise.reject({message: "An unexpected error occurred"});
+ }
if (!promises.length) {
if (options.frame_id) {
return Promise.reject({message: `Frame not found, or missing host permission`});
}
let frames = options.all_frames ? ", and any iframes" : "";
return Promise.reject({message: `Missing host permission for the tab${frames}`});
@@ -769,12 +778,17 @@ this.ExtensionContent = {
// Helpers
* enumerateWindows(docShell) {
let enum_ = docShell.getDocShellEnumerator(docShell.typeContent,
docShell.ENUMERATE_FORWARDS);
for (let docShell of XPCOMUtils.IterSimpleEnumerator(enum_, Ci.nsIInterfaceRequestor)) {
- yield docShell.getInterface(Ci.nsIDOMWindow);
+ try {
+ yield docShell.getInterface(Ci.nsIDOMWindow);
+ } catch (e) {
+ // This can fail if the docShell is being destroyed, so just
+ // ignore the error.
+ }
}
},
};